Merge "ShortcutManager: Floating shortcuts shouldn't have target activities."
diff --git a/Android.mk b/Android.mk
index 552103d..5d902c2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,7 @@
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IEphemeralResolver.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
+ core/java/android/app/IOnNotificationChannelCreatedListener.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
@@ -338,6 +339,7 @@
core/java/com/android/internal/backup/IObbBackupService.aidl \
core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
+ core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
core/java/com/android/internal/policy/IKeyguardService.aidl \
core/java/com/android/internal/policy/IKeyguardStateCallback.aidl \
@@ -515,7 +517,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(framework_res_R_stamp)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp core-junit bouncycastle ext
+LOCAL_JAVA_LIBRARIES := core-oj core-libart conscrypt okhttp legacy-test bouncycastle ext
LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
@@ -1129,7 +1131,9 @@
-proofread $(OUT_DOCS)/$(LOCAL_MODULE)-proofread.txt \
-sdkvalues $(OUT_DOCS) \
-hdf android.whichdoc offline \
- -referenceonly
+ -referenceonly \
+ -resourcesdir $(LOCAL_PATH)/docs/html/reference/images/ \
+ -resourcesoutdir reference/android/images/
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
new file mode 100644
index 0000000..791f587
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10.xml
@@ -0,0 +1,43 @@
+<!--
+ ~ 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
+ -->
+
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 10 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="20px"
+ android:autoSizeStepGranularity="1px"/>
+
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
new file mode 100644
index 0000000..cca4a52
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 100 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="110px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
new file mode 100644
index 0000000..bb9fc5e
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_1000.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 1000 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="1010px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
new file mode 100644
index 0000000..e0e5878
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_10000.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 10000 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="10010px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
new file mode 100644
index 0000000..4f66805
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_100000.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 100000 sizes!!! to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="100010px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
new file mode 100644
index 0000000..d3a4040
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_300.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 300 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="310px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
new file mode 100644
index 0000000..c7982e7
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_5.xml
@@ -0,0 +1,42 @@
+<!--
+ ~ 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
+ -->
+
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 5 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="15px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
new file mode 100644
index 0000000..b009889
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_50.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 50 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="60px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
new file mode 100644
index 0000000..f59d751
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_autosize_textview_500.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Contains 500 sizes to choose from when auto-sizing -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="400dp"
+ android:layout_height="600dp"
+ android:text="@string/long_text"
+ android:textDirection="rtl"
+ android:autoSizeText="xy"
+ android:autoSizeMinTextSize="10px"
+ android:textSize="510px"
+ android:autoSizeStepGranularity="1px"/>
diff --git a/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml b/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml
new file mode 100644
index 0000000..bc60ad4
--- /dev/null
+++ b/apct-tests/perftests/core/res/layout/test_basic_textview_layout.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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
+ -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="300dp"
+ android:layout_height="300dp"
+ android:text="@string/long_text" />
diff --git a/apct-tests/perftests/core/res/values/strings.xml b/apct-tests/perftests/core/res/values/strings.xml
new file mode 100644
index 0000000..5d1f6f0
--- /dev/null
+++ b/apct-tests/perftests/core/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="long_text">text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text typo text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text text text text text
+ text text text text text text text text text text text text </string>
+</resources>
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
new file mode 100644
index 0000000..6ee6f70
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/widget/TextViewAutoSizeLayoutPerfTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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 android.widget;
+
+import android.app.Activity;
+import android.os.Looper;
+import android.os.Bundle;
+import android.perftests.utils.PerfStatusReporter;
+import android.util.Log;
+import android.view.View;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.StubActivity;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.perftests.core.R;
+
+import java.util.Locale;
+import java.util.Collection;
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.Rule;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class TextViewAutoSizeLayoutPerfTest {
+ @Parameters(name = "{0}")
+ public static Collection layouts() {
+ return Arrays.asList(new Object[][] {
+ { "Basic TextView - no autosize", R.layout.test_basic_textview_layout},
+ { "Autosize TextView 5 sizes", R.layout.test_autosize_textview_5},
+ { "Autosize TextView 10 sizes", R.layout.test_autosize_textview_10},
+ { "Autosize TextView 50 sizes", R.layout.test_autosize_textview_50},
+ { "Autosize TextView 100 sizes", R.layout.test_autosize_textview_100},
+ { "Autosize TextView 300 sizes", R.layout.test_autosize_textview_300},
+ { "Autosize TextView 500 sizes", R.layout.test_autosize_textview_500},
+ { "Autosize TextView 1000 sizes", R.layout.test_autosize_textview_1000},
+ { "Autosize TextView 10000 sizes", R.layout.test_autosize_textview_10000},
+ { "Autosize TextView 100000 sizes", R.layout.test_autosize_textview_100000}
+ });
+ }
+
+ private int mLayoutId;
+
+ public TextViewAutoSizeLayoutPerfTest(String key, int layoutId) {
+ mLayoutId = layoutId;
+ }
+
+ @Rule
+ public ActivityTestRule<StubActivity> mActivityRule =
+ new ActivityTestRule(StubActivity.class);
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testConstruction() throws Throwable {
+ mActivityRule.runOnUiThread(() -> {
+ assertTrue("We should be running on the main thread",
+ Looper.getMainLooper().getThread() == Thread.currentThread());
+ assertTrue("We should be running on the main thread",
+ Looper.myLooper() == Looper.getMainLooper());
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ Activity activity = mActivityRule.getActivity();
+ activity.setContentView(mLayoutId);
+
+ while (state.keepRunning()) {
+ TextView textView = new TextView(activity);
+ // TextView#onMeasure() gets called, which triggers TextView#autoSizeText()
+ // which is the method we want to benchmark.
+ textView.requestLayout();
+ }
+ });
+ }
+}
diff --git a/api/current.txt b/api/current.txt
index 6bec747..304ccf8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -99,6 +99,7 @@
field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
+ field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
@@ -793,10 +794,12 @@
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
field public static final int layout_marginEnd = 16843702; // 0x10103b6
+ field public static final int layout_marginHorizontal = 16844091; // 0x101053b
field public static final int layout_marginLeft = 16842999; // 0x10100f7
field public static final int layout_marginRight = 16843001; // 0x10100f9
field public static final int layout_marginStart = 16843701; // 0x10103b5
field public static final int layout_marginTop = 16843000; // 0x10100f8
+ field public static final int layout_marginVertical = 16844092; // 0x101053c
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -864,7 +867,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
- field public static final int min = 16843367; // 0x1010267
+ field public static final int min = 16844089; // 0x1010539
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -927,11 +930,13 @@
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
field public static final int paddingEnd = 16843700; // 0x10103b4
+ field public static final int paddingHorizontal = 16844093; // 0x101053d
field public static final int paddingLeft = 16842966; // 0x10100d6
field public static final int paddingMode = 16843863; // 0x1010457
field public static final int paddingRight = 16842968; // 0x10100d8
field public static final int paddingStart = 16843699; // 0x10103b3
field public static final int paddingTop = 16842967; // 0x10100d7
+ field public static final int paddingVertical = 16844094; // 0x101053e
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1050,7 +1055,7 @@
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
- field public static final int rotationAnimation = 16843688; // 0x10103a8
+ field public static final int rotationAnimation = 16844090; // 0x101053a
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
field public static final int roundIcon = 16844076; // 0x101052c
@@ -4067,6 +4072,7 @@
field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+ field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -4824,6 +4830,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+ method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -4833,12 +4840,19 @@
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
}
+ public static abstract class KeyguardManager.KeyguardDismissCallback {
+ ctor public KeyguardManager.KeyguardDismissCallback();
+ method public void onDismissCancelled();
+ method public void onDismissError();
+ method public void onDismissSucceeded();
+ }
+
public deprecated class KeyguardManager.KeyguardLock {
method public void disableKeyguard();
method public void reenableKeyguard();
}
- public static abstract interface KeyguardManager.OnKeyguardExitResult {
+ public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
method public abstract void onKeyguardExitResult(boolean);
}
@@ -5355,17 +5369,19 @@
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public int describeContents();
+ method public void enableVibration(boolean);
method public java.lang.String getId();
method public int getImportance();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
+ method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
method public void setImportance(int);
method public void setLights(boolean);
method public void setLockscreenVisibility(int);
method public void setSound(android.net.Uri);
- method public void setVibration(boolean);
+ method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
method public void writeToParcel(android.os.Parcel, int);
@@ -5379,7 +5395,7 @@
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
- method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5413,6 +5429,10 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
}
+ public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+ method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+ }
+
public static class NotificationManager.Policy implements android.os.Parcelable {
ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
@@ -6005,6 +6025,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6080,6 +6101,7 @@
method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+ method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6169,6 +6191,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+ field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -11991,6 +12014,7 @@
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+ method public static android.graphics.ColorSpace.Renderer createRenderer();
method public float[] fromXyz(float, float, float);
method public abstract float[] fromXyz(float[]);
method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12072,6 +12096,15 @@
enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
}
+ public static class ColorSpace.Renderer {
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+ method public android.graphics.ColorSpace.Renderer clip(boolean);
+ method public android.graphics.Bitmap render();
+ method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+ method public android.graphics.ColorSpace.Renderer size(int);
+ }
+
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -21451,6 +21484,7 @@
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void release();
method public void reset();
+ method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
@@ -21503,6 +21537,10 @@
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ field public static final int SEEK_CLOSEST = 3; // 0x3
+ field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+ field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+ field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -25533,7 +25571,7 @@
method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
- method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+ method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -29998,6 +30036,7 @@
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -30047,6 +30086,7 @@
method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
method public void setOrder(int);
method public void setPersistent(boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSelectable(boolean);
method public void setShouldDisableView(boolean);
method public void setSummary(java.lang.CharSequence);
@@ -30147,6 +30187,21 @@
ctor public PreferenceCategory(android.content.Context);
}
+ public abstract interface PreferenceDataStore {
+ method public default boolean getBoolean(java.lang.String, boolean);
+ method public default float getFloat(java.lang.String, float);
+ method public default int getInt(java.lang.String, int);
+ method public default long getLong(java.lang.String, long);
+ method public default java.lang.String getString(java.lang.String, java.lang.String);
+ method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ method public default void putBoolean(java.lang.String, boolean);
+ method public default void putFloat(java.lang.String, float);
+ method public default void putInt(java.lang.String, int);
+ method public default void putLong(java.lang.String, long);
+ method public default void putString(java.lang.String, java.lang.String);
+ method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ }
+
public abstract class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
@@ -30186,6 +30241,7 @@
method public android.preference.Preference findPreference(java.lang.CharSequence);
method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.content.SharedPreferences getSharedPreferences();
method public int getSharedPreferencesMode();
method public java.lang.String getSharedPreferencesName();
@@ -30193,6 +30249,7 @@
method public boolean isStorageDeviceProtected();
method public static void setDefaultValues(android.content.Context, int, boolean);
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
method public void setStorageDefault();
@@ -37391,6 +37448,7 @@
method public int getAsuLevel();
method public int getDbm();
method public int getLevel();
+ method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -64187,7 +64245,7 @@
method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
- method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+ method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1f3fd7d..d54e6a9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -172,6 +172,7 @@
field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
field public static final java.lang.String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
field public static final java.lang.String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
+ field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES";
@@ -900,10 +901,12 @@
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
field public static final int layout_marginEnd = 16843702; // 0x10103b6
+ field public static final int layout_marginHorizontal = 16844091; // 0x101053b
field public static final int layout_marginLeft = 16842999; // 0x10100f7
field public static final int layout_marginRight = 16843001; // 0x10100f9
field public static final int layout_marginStart = 16843701; // 0x10103b5
field public static final int layout_marginTop = 16843000; // 0x10100f8
+ field public static final int layout_marginVertical = 16844092; // 0x101053c
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -971,7 +974,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
- field public static final int min = 16843367; // 0x1010267
+ field public static final int min = 16844089; // 0x1010539
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -1034,11 +1037,13 @@
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
field public static final int paddingEnd = 16843700; // 0x10103b4
+ field public static final int paddingHorizontal = 16844093; // 0x101053d
field public static final int paddingLeft = 16842966; // 0x10100d6
field public static final int paddingMode = 16843863; // 0x1010457
field public static final int paddingRight = 16842968; // 0x10100d8
field public static final int paddingStart = 16843699; // 0x10103b3
field public static final int paddingTop = 16842967; // 0x10100d7
+ field public static final int paddingVertical = 16844094; // 0x101053e
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1157,7 +1162,7 @@
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
- field public static final int rotationAnimation = 16843688; // 0x10103a8
+ field public static final int rotationAnimation = 16844090; // 0x101053a
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
field public static final int roundIcon = 16844076; // 0x101052c
@@ -4203,6 +4208,7 @@
field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+ field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -4978,6 +4984,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+ method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -4987,12 +4994,19 @@
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
}
+ public static abstract class KeyguardManager.KeyguardDismissCallback {
+ ctor public KeyguardManager.KeyguardDismissCallback();
+ method public void onDismissCancelled();
+ method public void onDismissError();
+ method public void onDismissSucceeded();
+ }
+
public deprecated class KeyguardManager.KeyguardLock {
method public void disableKeyguard();
method public void reenableKeyguard();
}
- public static abstract interface KeyguardManager.OnKeyguardExitResult {
+ public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
method public abstract void onKeyguardExitResult(boolean);
}
@@ -5511,12 +5525,14 @@
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public int describeContents();
+ method public void enableVibration(boolean);
method public java.lang.String getId();
method public int getImportance();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
method public int getUserLockedFields();
+ method public long[] getVibrationPattern();
method public void lockFields(int);
method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
method public void setBypassDnd(boolean);
@@ -5524,7 +5540,7 @@
method public void setLights(boolean);
method public void setLockscreenVisibility(int);
method public void setSound(android.net.Uri);
- method public void setVibration(boolean);
+ method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
method public org.json.JSONObject toJson() throws org.json.JSONException;
@@ -5546,7 +5562,7 @@
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
- method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5580,6 +5596,10 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
}
+ public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+ method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+ }
+
public static class NotificationManager.Policy implements android.os.Parcelable {
ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
@@ -6177,6 +6197,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6194,6 +6215,7 @@
method public java.lang.String getDeviceOwner();
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.lang.String getDeviceOwnerNameOnAnyUser();
+ method public java.lang.CharSequence getDeviceOwnerOrganizationName();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
@@ -6241,6 +6263,7 @@
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isCallerApplicationRestrictionsManagingPackage();
+ method public boolean isDeviceManaged();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isManagedProfile(android.content.ComponentName);
@@ -6263,6 +6286,7 @@
method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
+ method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6356,6 +6380,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+ field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -12474,6 +12499,7 @@
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+ method public static android.graphics.ColorSpace.Renderer createRenderer();
method public float[] fromXyz(float, float, float);
method public abstract float[] fromXyz(float[]);
method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12555,6 +12581,15 @@
enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
}
+ public static class ColorSpace.Renderer {
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+ method public android.graphics.ColorSpace.Renderer clip(boolean);
+ method public android.graphics.Bitmap render();
+ method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+ method public android.graphics.ColorSpace.Renderer size(int);
+ }
+
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -23016,6 +23051,7 @@
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void release();
method public void reset();
+ method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
@@ -23068,6 +23104,10 @@
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ field public static final int SEEK_CLOSEST = 3; // 0x3
+ field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+ field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+ field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -28058,7 +28098,7 @@
method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
- method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+ method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -32631,6 +32671,7 @@
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -32680,6 +32721,7 @@
method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
method public void setOrder(int);
method public void setPersistent(boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSelectable(boolean);
method public void setShouldDisableView(boolean);
method public void setSummary(java.lang.CharSequence);
@@ -32780,6 +32822,21 @@
ctor public PreferenceCategory(android.content.Context);
}
+ public abstract interface PreferenceDataStore {
+ method public default boolean getBoolean(java.lang.String, boolean);
+ method public default float getFloat(java.lang.String, float);
+ method public default int getInt(java.lang.String, int);
+ method public default long getLong(java.lang.String, long);
+ method public default java.lang.String getString(java.lang.String, java.lang.String);
+ method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ method public default void putBoolean(java.lang.String, boolean);
+ method public default void putFloat(java.lang.String, float);
+ method public default void putInt(java.lang.String, int);
+ method public default void putLong(java.lang.String, long);
+ method public default void putString(java.lang.String, java.lang.String);
+ method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ }
+
public abstract class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
@@ -32819,6 +32876,7 @@
method public android.preference.Preference findPreference(java.lang.CharSequence);
method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.content.SharedPreferences getSharedPreferences();
method public int getSharedPreferencesMode();
method public java.lang.String getSharedPreferencesName();
@@ -32827,6 +32885,7 @@
method public boolean isStorageDeviceProtected();
method public static void setDefaultValues(android.content.Context, int, boolean);
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
method public void setStorageCredentialProtected();
@@ -37980,19 +38039,7 @@
package android.service.persistentdata {
- public abstract interface IPersistentDataBlockService implements android.os.IInterface {
- method public abstract int getDataBlockSize() throws android.os.RemoteException;
- method public abstract int getFlashLockState() throws android.os.RemoteException;
- method public abstract long getMaximumDataBlockSize() throws android.os.RemoteException;
- method public abstract boolean getOemUnlockEnabled() throws android.os.RemoteException;
- method public abstract byte[] read() throws android.os.RemoteException;
- method public abstract void setOemUnlockEnabled(boolean) throws android.os.RemoteException;
- method public abstract void wipe() throws android.os.RemoteException;
- method public abstract int write(byte[]) throws android.os.RemoteException;
- }
-
public class PersistentDataBlockManager {
- ctor public PersistentDataBlockManager(android.service.persistentdata.IPersistentDataBlockService);
method public int getDataBlockSize();
method public int getFlashLockState();
method public long getMaximumDataBlockSize();
@@ -40471,6 +40518,7 @@
method public int getAsuLevel();
method public int getDbm();
method public int getLevel();
+ method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -67708,7 +67756,7 @@
method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
- method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+ method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4a4bf70..f269479 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -99,6 +99,7 @@
field public static final java.lang.String READ_FRAME_BUFFER = "android.permission.READ_FRAME_BUFFER";
field public static final deprecated java.lang.String READ_INPUT_STATE = "android.permission.READ_INPUT_STATE";
field public static final java.lang.String READ_LOGS = "android.permission.READ_LOGS";
+ field public static final java.lang.String READ_PHONE_NUMBER = "android.permission.READ_PHONE_NUMBER";
field public static final java.lang.String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
field public static final java.lang.String READ_SMS = "android.permission.READ_SMS";
field public static final java.lang.String READ_SYNC_SETTINGS = "android.permission.READ_SYNC_SETTINGS";
@@ -793,10 +794,12 @@
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
field public static final int layout_marginEnd = 16843702; // 0x10103b6
+ field public static final int layout_marginHorizontal = 16844091; // 0x101053b
field public static final int layout_marginLeft = 16842999; // 0x10100f7
field public static final int layout_marginRight = 16843001; // 0x10100f9
field public static final int layout_marginStart = 16843701; // 0x10103b5
field public static final int layout_marginTop = 16843000; // 0x10100f8
+ field public static final int layout_marginVertical = 16844092; // 0x101053c
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
field public static final int layout_rowWeight = 16843864; // 0x1010458
@@ -864,7 +867,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
- field public static final int min = 16843367; // 0x1010267
+ field public static final int min = 16844089; // 0x1010539
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -927,11 +930,13 @@
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
field public static final int paddingEnd = 16843700; // 0x10103b4
+ field public static final int paddingHorizontal = 16844093; // 0x101053d
field public static final int paddingLeft = 16842966; // 0x10100d6
field public static final int paddingMode = 16843863; // 0x1010457
field public static final int paddingRight = 16842968; // 0x10100d8
field public static final int paddingStart = 16843699; // 0x10103b3
field public static final int paddingTop = 16842967; // 0x10100d7
+ field public static final int paddingVertical = 16844094; // 0x101053e
field public static final int panelBackground = 16842846; // 0x101005e
field public static final int panelColorBackground = 16842849; // 0x1010061
field public static final int panelColorForeground = 16842848; // 0x1010060
@@ -1050,7 +1055,7 @@
field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
field public static final int ringtoneType = 16843257; // 0x10101f9
field public static final int rotation = 16843558; // 0x1010326
- field public static final int rotationAnimation = 16843688; // 0x10103a8
+ field public static final int rotationAnimation = 16844090; // 0x101053a
field public static final int rotationX = 16843559; // 0x1010327
field public static final int rotationY = 16843560; // 0x1010328
field public static final int roundIcon = 16844076; // 0x101052c
@@ -4077,6 +4082,7 @@
field public static final java.lang.String OPSTR_READ_CELL_BROADCASTS = "android:read_cell_broadcasts";
field public static final java.lang.String OPSTR_READ_CONTACTS = "android:read_contacts";
field public static final java.lang.String OPSTR_READ_EXTERNAL_STORAGE = "android:read_external_storage";
+ field public static final java.lang.String OPSTR_READ_PHONE_NUMBER = "android:read_phone_number";
field public static final java.lang.String OPSTR_READ_PHONE_STATE = "android:read_phone_state";
field public static final java.lang.String OPSTR_READ_SMS = "android:read_sms";
field public static final java.lang.String OPSTR_RECEIVE_MMS = "android:receive_mms";
@@ -4834,6 +4840,7 @@
public class KeyguardManager {
method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence);
+ method public void dismissKeyguard(android.app.Activity, android.app.KeyguardManager.KeyguardDismissCallback, android.os.Handler);
method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -4843,12 +4850,19 @@
method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
}
+ public static abstract class KeyguardManager.KeyguardDismissCallback {
+ ctor public KeyguardManager.KeyguardDismissCallback();
+ method public void onDismissCancelled();
+ method public void onDismissError();
+ method public void onDismissSucceeded();
+ }
+
public deprecated class KeyguardManager.KeyguardLock {
method public void disableKeyguard();
method public void reenableKeyguard();
}
- public static abstract interface KeyguardManager.OnKeyguardExitResult {
+ public static abstract deprecated interface KeyguardManager.OnKeyguardExitResult {
method public abstract void onKeyguardExitResult(boolean);
}
@@ -5365,17 +5379,19 @@
ctor protected NotificationChannel(android.os.Parcel);
method public boolean canBypassDnd();
method public int describeContents();
+ method public void enableVibration(boolean);
method public java.lang.String getId();
method public int getImportance();
method public int getLockscreenVisibility();
method public java.lang.CharSequence getName();
method public android.net.Uri getSound();
+ method public long[] getVibrationPattern();
method public void setBypassDnd(boolean);
method public void setImportance(int);
method public void setLights(boolean);
method public void setLockscreenVisibility(int);
method public void setSound(android.net.Uri);
- method public void setVibration(boolean);
+ method public void setVibrationPattern(long[]);
method public boolean shouldShowLights();
method public boolean shouldVibrate();
method public void writeToParcel(android.os.Parcel, int);
@@ -5389,7 +5405,7 @@
method public void cancel(int);
method public void cancel(java.lang.String, int);
method public void cancelAll();
- method public void createNotificationChannel(android.app.NotificationChannel);
+ method public void createNotificationChannel(android.app.NotificationChannel, android.app.NotificationManager.OnNotificationChannelCreatedListener, android.os.Handler);
method public void deleteNotificationChannel(java.lang.String);
method public android.service.notification.StatusBarNotification[] getActiveNotifications();
method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
@@ -5424,6 +5440,10 @@
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
}
+ public static abstract interface NotificationManager.OnNotificationChannelCreatedListener {
+ method public abstract void onNotificationChannelCreated(android.app.NotificationChannel);
+ }
+
public static class NotificationManager.Policy implements android.os.Parcelable {
ctor public NotificationManager.Policy(int, int, int);
ctor public NotificationManager.Policy(int, int, int, int);
@@ -6022,6 +6042,7 @@
method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
+ method public java.util.List<java.lang.String> getAffiliationIds(android.content.ComponentName);
method public java.lang.String getAlwaysOnVpnPackage(android.content.ComponentName);
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
@@ -6035,6 +6056,7 @@
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
+ method public java.lang.CharSequence getDeviceOwnerOrganizationName();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
method public long getLastBugReportRequestTime();
@@ -6080,6 +6102,7 @@
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
method public boolean isCallerApplicationRestrictionsManagingPackage();
+ method public boolean isDeviceManaged();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isManagedProfile(android.content.ComponentName);
@@ -6100,6 +6123,7 @@
method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
+ method public void setAffiliationIds(android.content.ComponentName, java.util.List<java.lang.String>);
method public void setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String, boolean) throws android.content.pm.PackageManager.NameNotFoundException, java.lang.UnsupportedOperationException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -6189,6 +6213,7 @@
field public static final java.lang.String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field public static final java.lang.String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
+ field public static final java.lang.String EXTRA_PROVISIONING_SKIP_USER_CONSENT = "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
field public static final java.lang.String EXTRA_PROVISIONING_WIFI_PAC_URL = "android.app.extra.PROVISIONING_WIFI_PAC_URL";
@@ -12020,6 +12045,7 @@
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace);
method public static android.graphics.ColorSpace.Connector connect(android.graphics.ColorSpace, android.graphics.ColorSpace.RenderIntent);
+ method public static android.graphics.ColorSpace.Renderer createRenderer();
method public float[] fromXyz(float, float, float);
method public abstract float[] fromXyz(float[]);
method public static android.graphics.ColorSpace get(android.graphics.ColorSpace.Named);
@@ -12101,6 +12127,15 @@
enum_constant public static final android.graphics.ColorSpace.RenderIntent SATURATION;
}
+ public static class ColorSpace.Renderer {
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, int);
+ method public android.graphics.ColorSpace.Renderer add(android.graphics.ColorSpace, float, float, float, int);
+ method public android.graphics.ColorSpace.Renderer clip(boolean);
+ method public android.graphics.Bitmap render();
+ method public android.graphics.ColorSpace.Renderer showWhitePoint(boolean);
+ method public android.graphics.ColorSpace.Renderer size(int);
+ }
+
public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
@@ -21536,6 +21571,7 @@
method public void prepareAsync() throws java.lang.IllegalStateException;
method public void release();
method public void reset();
+ method public void seekTo(int, int) throws java.lang.IllegalStateException;
method public void seekTo(int) throws java.lang.IllegalStateException;
method public void selectTrack(int) throws java.lang.IllegalStateException;
method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
@@ -21588,6 +21624,10 @@
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
+ field public static final int SEEK_CLOSEST = 3; // 0x3
+ field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2
+ field public static final int SEEK_NEXT_SYNC = 1; // 0x1
+ field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -25618,7 +25658,7 @@
method public static android.opengl.EGLContext eglCreateContext(android.opengl.EGLDisplay, android.opengl.EGLConfig, android.opengl.EGLContext, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferFromClientBuffer(android.opengl.EGLDisplay, int, int, android.opengl.EGLConfig, int[], int);
method public static android.opengl.EGLSurface eglCreatePbufferSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int[], int);
- method public static android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
+ method public static deprecated android.opengl.EGLSurface eglCreatePixmapSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, int, int[], int);
method public static android.opengl.EGLSurface eglCreateWindowSurface(android.opengl.EGLDisplay, android.opengl.EGLConfig, java.lang.Object, int[], int);
method public static boolean eglDestroyContext(android.opengl.EGLDisplay, android.opengl.EGLContext);
method public static boolean eglDestroySurface(android.opengl.EGLDisplay, android.opengl.EGLSurface);
@@ -30085,6 +30125,7 @@
method protected long getPersistedLong(long);
method protected java.lang.String getPersistedString(java.lang.String);
method public java.util.Set<java.lang.String> getPersistedStringSet(java.util.Set<java.lang.String>);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.preference.PreferenceManager getPreferenceManager();
method public android.content.SharedPreferences getSharedPreferences();
method public boolean getShouldDisableView();
@@ -30134,6 +30175,7 @@
method public void setOnPreferenceClickListener(android.preference.Preference.OnPreferenceClickListener);
method public void setOrder(int);
method public void setPersistent(boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSelectable(boolean);
method public void setShouldDisableView(boolean);
method public void setSummary(java.lang.CharSequence);
@@ -30234,6 +30276,21 @@
ctor public PreferenceCategory(android.content.Context);
}
+ public abstract interface PreferenceDataStore {
+ method public default boolean getBoolean(java.lang.String, boolean);
+ method public default float getFloat(java.lang.String, float);
+ method public default int getInt(java.lang.String, int);
+ method public default long getLong(java.lang.String, long);
+ method public default java.lang.String getString(java.lang.String, java.lang.String);
+ method public default java.util.Set<java.lang.String> getStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ method public default void putBoolean(java.lang.String, boolean);
+ method public default void putFloat(java.lang.String, float);
+ method public default void putInt(java.lang.String, int);
+ method public default void putLong(java.lang.String, long);
+ method public default void putString(java.lang.String, java.lang.String);
+ method public default void putStringSet(java.lang.String, java.util.Set<java.lang.String>);
+ }
+
public abstract class PreferenceFragment extends android.app.Fragment {
ctor public PreferenceFragment();
method public void addPreferencesFromIntent(android.content.Intent);
@@ -30273,6 +30330,7 @@
method public android.preference.Preference findPreference(java.lang.CharSequence);
method public static android.content.SharedPreferences getDefaultSharedPreferences(android.content.Context);
method public static java.lang.String getDefaultSharedPreferencesName(android.content.Context);
+ method public android.preference.PreferenceDataStore getPreferenceDataStore();
method public android.content.SharedPreferences getSharedPreferences();
method public int getSharedPreferencesMode();
method public java.lang.String getSharedPreferencesName();
@@ -30280,6 +30338,7 @@
method public boolean isStorageDeviceProtected();
method public static void setDefaultValues(android.content.Context, int, boolean);
method public static void setDefaultValues(android.content.Context, java.lang.String, int, int, boolean);
+ method public void setPreferenceDataStore(android.preference.PreferenceDataStore);
method public void setSharedPreferencesMode(int);
method public void setSharedPreferencesName(java.lang.String);
method public void setStorageDefault();
@@ -37485,6 +37544,7 @@
method public int getAsuLevel();
method public int getDbm();
method public int getLevel();
+ method public int getTimingAdvance();
method public int hashCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -64457,7 +64517,7 @@
method public abstract boolean eglCopyBuffers(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface, java.lang.Object);
method public abstract javax.microedition.khronos.egl.EGLContext eglCreateContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, javax.microedition.khronos.egl.EGLContext, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePbufferSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, int[]);
- method public abstract javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
+ method public abstract deprecated javax.microedition.khronos.egl.EGLSurface eglCreatePixmapSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract javax.microedition.khronos.egl.EGLSurface eglCreateWindowSurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLConfig, java.lang.Object, int[]);
method public abstract boolean eglDestroyContext(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLContext);
method public abstract boolean eglDestroySurface(javax.microedition.khronos.egl.EGLDisplay, javax.microedition.khronos.egl.EGLSurface);
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index e18de8e..eaad3a7 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -1,78 +1,67 @@
LOCAL_PATH:= $(call my-dir)
+app_process_common_shared_libs := \
+ libandroid_runtime \
+ libbinder \
+ libcutils \
+ libdl \
+ liblog \
+ libnativeloader \
+ libutils \
+
# This is a list of libraries that need to be included in order to avoid
# bad apps. This prevents a library from having a mismatch when resolving
# new/delete from an app shared library.
# See b/21032018 for more details.
-app_process_common_shared_libs := \
+app_process_common_shared_libs += \
libwilhelm \
+app_process_common_static_libs := \
+ libsigchain \
+
+app_process_src_files := \
+ app_main.cpp \
+
+app_process_cflags := \
+ -Wall -Werror -Wunused -Wunreachable-code
+
+app_process_ldflags_32 := \
+ -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
+app_process_ldflags_64 := \
+ -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
+
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
- app_main.cpp
+LOCAL_SRC_FILES:= $(app_process_src_files)
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
+LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
+LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
-LOCAL_SHARED_LIBRARIES := \
- libdl \
- libcutils \
- libutils \
- liblog \
- libbinder \
- libnativeloader \
- libandroid_runtime \
- $(app_process_common_shared_libs) \
+LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
+LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_CFLAGS += $(app_process_cflags)
+
+# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse
+# the same module). Using the same module also works around an issue with make: binaries
+# that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.
+#
+# Also pull in the asanwrapper helper.
+ifeq ($(SANITIZE_LITE),true)
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
+LOCAL_REQUIRED_MODULES := asanwrapper
+endif
include $(BUILD_EXECUTABLE)
# Create a symlink from app_process to app_process32 or 64
# depending on the target configuration.
+ifneq ($(SANITIZE_LITE),true)
include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-# Build a variant of app_process binary linked with ASan runtime.
-# ARM-only at the moment.
-ifeq ($(TARGET_ARCH),arm)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- app_main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- liblog \
- libbinder \
- libandroid_runtime \
- $(app_process_common_shared_libs) \
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-
-LOCAL_LDFLAGS := -ldl
-LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-
-LOCAL_MODULE := app_process__asan
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := app_process32
-LOCAL_MODULE_STEM_64 := app_process64
-
-LOCAL_SANITIZE := address
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_EXECUTABLE)
-
-endif # ifeq($(TARGET_ARCH),arm)
+endif
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 4291c77..db3772d 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -92,6 +92,8 @@
runSetEmulateFbe();
} else if ("get-fbe-mode".equals(op)) {
runGetFbeMode();
+ } else if ("fstrim".equals(op)) {
+ runFstrim();
} else {
throw new IllegalArgumentException();
}
@@ -210,7 +212,7 @@
mSm.benchmark(volId);
}
- public void runForget() throws RemoteException{
+ public void runForget() throws RemoteException {
final String fsUuid = nextArg();
if ("all".equals(fsUuid)) {
mSm.forgetAllVolumes();
@@ -219,6 +221,10 @@
}
}
+ public void runFstrim() throws RemoteException {
+ mSm.fstrim(0);
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -240,6 +246,7 @@
System.err.println(" sm unmount VOLUME");
System.err.println(" sm format VOLUME");
System.err.println(" sm benchmark VOLUME");
+ System.err.println(" sm fstrim");
System.err.println("");
System.err.println(" sm forget [UUID|all]");
System.err.println("");
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index 84fb626..8defb33 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -274,7 +274,7 @@
}
private void runDismissKeyguard() throws Exception {
- mWm.dismissKeyguard();
+ mWm.dismissKeyguard(null /* callback */);
}
private int parseDimension(String s) throws NumberFormatException {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index bfa6d34..913edfd8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -62,6 +62,13 @@
public static final int APP_TRANSITION_TIMEOUT = 3;
/**
+ * Grant Uri permissions from one app to another. This method only extends
+ * permission grants if {@code callingUid} has permission to them.
+ */
+ public abstract void grantUriPermissionFromIntent(int callingUid, String targetPkg,
+ Intent intent, int targetUserId);
+
+ /**
* Verify that calling app has access to the given provider.
*/
public abstract String checkContentProviderAccess(String authority, int userId);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ba6bc15..67fbc5a 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -241,8 +241,10 @@
public static final int OP_RUN_IN_BACKGROUND = 63;
/** @hide */
public static final int OP_AUDIO_ACCESSIBILITY_VOLUME = 64;
+ /** @hide Read the phone number. */
+ public static final int OP_READ_PHONE_NUMBER = 65;
/** @hide */
- public static final int _NUM_OP = 65;
+ public static final int _NUM_OP = 66;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -343,6 +345,8 @@
/** @hide Get device accounts. */
public static final String OPSTR_GET_ACCOUNTS
= "android:get_accounts";
+ public static final String OPSTR_READ_PHONE_NUMBER
+ = "android:read_phone_number";
private static final int[] RUNTIME_PERMISSIONS_OPS = {
// Contacts
@@ -367,6 +371,7 @@
OP_FINE_LOCATION,
// Phone
OP_READ_PHONE_STATE,
+ OP_READ_PHONE_NUMBER,
OP_CALL_PHONE,
OP_READ_CALL_LOG,
OP_WRITE_CALL_LOG,
@@ -455,6 +460,7 @@
OP_GET_ACCOUNTS,
OP_RUN_IN_BACKGROUND,
OP_AUDIO_ACCESSIBILITY_VOLUME,
+ OP_READ_PHONE_NUMBER,
};
/**
@@ -527,6 +533,7 @@
OPSTR_GET_ACCOUNTS,
null,
null, // OP_AUDIO_ACCESSIBILITY_VOLUME
+ OPSTR_READ_PHONE_NUMBER,
};
/**
@@ -599,6 +606,7 @@
"GET_ACCOUNTS",
"RUN_IN_BACKGROUND",
"AUDIO_ACCESSIBILITY_VOLUME",
+ "READ_PHONE_NUMBER",
};
/**
@@ -671,6 +679,7 @@
Manifest.permission.GET_ACCOUNTS,
null, // no permission for running in background
null, // no permission for changing accessibility volume
+ Manifest.permission.READ_PHONE_NUMBER,
};
/**
@@ -744,6 +753,7 @@
null, // GET_ACCOUNTS
null, // RUN_IN_BACKGROUND
UserManager.DISALLOW_ADJUST_VOLUME, //AUDIO_ACCESSIBILITY_VOLUME
+ null, // READ_PHONE_NUMBER
};
/**
@@ -816,6 +826,7 @@
false, // GET_ACCOUNTS
false, // RUN_IN_BACKGROUND
false, // AUDIO_ACCESSIBILITY_VOLUME
+ false, // READ_PHONE_NUMBER
};
/**
@@ -887,6 +898,7 @@
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND
AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ACCESSIBILITY_VOLUME
+ AppOpsManager.MODE_ALLOWED,
};
/**
@@ -962,6 +974,7 @@
false,
false,
false, // OP_AUDIO_ACCESSIBILITY_VOLUME
+ false,
};
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b199984..627e661 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -58,9 +58,11 @@
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -81,6 +83,7 @@
import dalvik.system.VMRuntime;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import com.android.internal.util.UserIcons;
@@ -1175,21 +1178,21 @@
}
@Override
- public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
- int badgeDensity) {
- Drawable badgeDrawable = getDrawableForDensity(
- com.android.internal.R.drawable.ic_corp_badge, badgeDensity);
- return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
- }
-
- @Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
- final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
- if (badgeResId == 0) {
+ if (!isManagedProfile(user.getIdentifier())) {
return icon;
}
- Drawable badgeIcon = getDrawable("system", badgeResId, null);
- return getBadgedDrawable(icon, badgeIcon, null, true);
+ Drawable badgeShadow = getDrawable("system",
+ com.android.internal.R.drawable.ic_corp_icon_badge_shadow, null);
+ Drawable badgeColor = getDrawable("system",
+ com.android.internal.R.drawable.ic_corp_icon_badge_color, null);
+ badgeColor.setTint(getUserBadgeColor(user));
+ Drawable badgeForeground = getDrawable("system",
+ com.android.internal.R.drawable.ic_corp_icon_badge_case, null);
+
+ Drawable badge = new LayerDrawable(
+ new Drawable[] {badgeShadow, badgeColor, badgeForeground });
+ return getBadgedDrawable(icon, badge, null, true);
}
@Override
@@ -1202,16 +1205,53 @@
return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
}
+ // Should have enough colors to cope with UserManagerService.getMaxManagedProfiles()
+ @VisibleForTesting
+ public static final int[] CORP_BADGE_COLORS = new int[] {
+ com.android.internal.R.color.profile_badge_1,
+ com.android.internal.R.color.profile_badge_2,
+ com.android.internal.R.color.profile_badge_3
+ };
+
+ @VisibleForTesting
+ public static final int[] CORP_BADGE_LABEL_RES_ID = new int[] {
+ com.android.internal.R.string.managed_profile_label_badge,
+ com.android.internal.R.string.managed_profile_label_badge_2,
+ com.android.internal.R.string.managed_profile_label_badge_3
+ };
+
+ private int getUserBadgeColor(UserHandle user) {
+ int badge = getUserManager().getManagedProfileBadge(user.getIdentifier());
+ if (badge < 0) {
+ badge = 0;
+ }
+ int resourceId = CORP_BADGE_COLORS[badge % CORP_BADGE_COLORS.length];
+ return Resources.getSystem().getColor(resourceId, null);
+ }
+
@Override
public Drawable getUserBadgeForDensity(UserHandle user, int density) {
- return getManagedProfileIconForDensity(user, com.android.internal.R.drawable.ic_corp_badge,
- density);
+ Drawable badgeColor = getManagedProfileIconForDensity(user,
+ com.android.internal.R.drawable.ic_corp_badge_color, density);
+ if (badgeColor == null) {
+ return null;
+ }
+ badgeColor.setTint(getUserBadgeColor(user));
+ Drawable badgeForeground = getDrawableForDensity(
+ com.android.internal.R.drawable.ic_corp_badge_case, density);
+ Drawable badge = new LayerDrawable(
+ new Drawable[] {badgeColor, badgeForeground });
+ return badge;
}
@Override
public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
- return getManagedProfileIconForDensity(user,
+ Drawable badge = getManagedProfileIconForDensity(user,
com.android.internal.R.drawable.ic_corp_badge_no_background, density);
+ if (badge != null) {
+ badge.setTint(getUserBadgeColor(user));
+ }
+ return badge;
}
private Drawable getDrawableForDensity(int drawableId, int density) {
@@ -1231,8 +1271,9 @@
@Override
public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) {
if (isManagedProfile(user.getIdentifier())) {
- return Resources.getSystem().getString(
- com.android.internal.R.string.managed_profile_label_badge, label);
+ int badge = getUserManager().getManagedProfileBadge(user.getIdentifier());
+ int resourceId = CORP_BADGE_LABEL_RES_ID[badge % CORP_BADGE_LABEL_RES_ID.length];
+ return Resources.getSystem().getString(resourceId, label);
}
return label;
}
@@ -2355,14 +2396,6 @@
return drawable;
}
- private int getBadgeResIdForUser(int userId) {
- // Return the framework-provided badge.
- if (isManagedProfile(userId)) {
- return com.android.internal.R.drawable.ic_corp_icon_badge;
- }
- return 0;
- }
-
private boolean isManagedProfile(int userId) {
return getUserManager().isManagedProfile(userId);
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index e222fee..abb098f 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -534,6 +534,12 @@
if (mSharedElementSourceNames == null) {
mSharedElementSourceNames = new ArrayList<String>();
mSharedElementTargetNames = new ArrayList<String>();
+ } else if (mSharedElementTargetNames.contains(name)) {
+ throw new IllegalArgumentException("A shared element with the target name '"
+ + name + "' has already been added to the transaction.");
+ } else if (mSharedElementSourceNames.contains(transitionName)) {
+ throw new IllegalArgumentException("A shared element with the source name '"
+ + transitionName + " has already been added to the transaction.");
}
mSharedElementSourceNames.add(transitionName);
mSharedElementTargetNames.add(name);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b8540f8..5f706dc 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2064,9 +2064,20 @@
? packageInfo.getCompatibilityInfo()
: CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
- context.mResources = createResources(activityToken, packageInfo, displayId,
- overrideConfiguration, compatInfo);
- context.mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(displayId,
+ final ResourcesManager resourcesManager = ResourcesManager.getInstance();
+
+ // Create the base resources for which all configuration contexts for this Activity
+ // will be rebased upon.
+ context.mResources = resourcesManager.createBaseActivityResources(activityToken,
+ packageInfo.getResDir(),
+ packageInfo.getSplitResDirs(),
+ packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles,
+ displayId,
+ overrideConfiguration,
+ compatInfo,
+ packageInfo.getClassLoader());
+ context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
context.mResources.getDisplayAdjustments());
return context;
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 3464c4d..10d584f 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -19,6 +19,8 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.app.SharedElementCallback.OnSharedElementsReadyListener;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -61,6 +63,7 @@
private Transition mEnterViewsTransition;
private OneShotPreDrawListener mViewsReadyListener;
private final boolean mIsCrossTask;
+ private Drawable mReplacedBackground;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
@@ -87,7 +90,7 @@
decorView.getViewTreeObserver().removeOnPreDrawListener(this);
}
}
- return mIsReadyForTransition;
+ return false;
}
});
}
@@ -332,12 +335,15 @@
if (!mIsReturning) {
mWasOpaque = mActivity.convertToTranslucent(null, null);
Drawable background = decorView.getBackground();
- if (background != null) {
+ if (background == null) {
+ background = new ColorDrawable(Color.TRANSPARENT);
+ mReplacedBackground = background;
+ } else {
getWindow().setBackgroundDrawable(null);
background = background.mutate();
background.setAlpha(0);
- getWindow().setBackgroundDrawable(background);
}
+ getWindow().setBackgroundDrawable(background);
} else {
mActivity = null; // all done with it now.
}
@@ -553,6 +559,11 @@
final ViewGroup decorView = getDecor();
if (decorView != null) {
decorView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+
+ Window window = getWindow();
+ if (window != null && mReplacedBackground == decorView.getBackground()) {
+ window.setBackgroundDrawable(null);
+ }
}
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 6a79e6c..21e3aee 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -236,7 +236,7 @@
delayCancel();
moveSharedElementsToOverlay();
if (decorView != null && decorView.getBackground() == null) {
- getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
final boolean targetsM = decorView == null || decorView.getContext()
.getApplicationInfo().targetSdkVersion >= VERSION_CODES.M;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 9ea3f83..92ba440 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1175,15 +1175,17 @@
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
container.addView(f.mView);
- f.mIsNewlyAdded = true;
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
- f.mIsNewlyAdded = false; // No animation required
}
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
+ // Only animate the view if it is visible. This is done after
+ // dispatchOnFragmentViewCreated in case visibility is changed
+ f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
+ && f.mContainer != null;
}
}
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 088fd08..3324448 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -367,9 +367,11 @@
}
if (exitingViews != null) {
- ArrayList<View> tempExiting = new ArrayList<>();
- tempExiting.add(nonExistentView);
- replaceTargets(exitTransition, exitingViews, tempExiting);
+ if (exitTransition != null) {
+ ArrayList<View> tempExiting = new ArrayList<>();
+ tempExiting.add(nonExistentView);
+ replaceTargets(exitTransition, exitingViews, tempExiting);
+ }
exitingViews.clear();
exitingViews.add(nonExistentView);
}
@@ -490,9 +492,17 @@
if (nameOverrides.isEmpty()) {
sharedElementTransition = null;
+ if (outSharedElements != null) {
+ outSharedElements.clear();
+ }
+ if (inSharedElements != null) {
+ inSharedElements.clear();
+ }
} else {
- sharedElementsOut.addAll(outSharedElements.values());
- sharedElementsIn.addAll(inSharedElements.values());
+ addSharedElementsWithMatchingNames(sharedElementsOut, outSharedElements,
+ nameOverrides.keySet());
+ addSharedElementsWithMatchingNames(sharedElementsIn, inSharedElements,
+ nameOverrides.values());
}
if (enterTransition == null && exitTransition == null && sharedElementTransition == null) {
@@ -538,6 +548,25 @@
}
/**
+ * Add Views from sharedElements into views that have the transitionName in the
+ * nameOverridesSet.
+ *
+ * @param views Views list to add shared elements to
+ * @param sharedElements List of shared elements
+ * @param nameOverridesSet The transition names for all views to be copied from
+ * sharedElements to views.
+ */
+ private static void addSharedElementsWithMatchingNames(ArrayList<View> views,
+ ArrayMap<String, View> sharedElements, Collection<String> nameOverridesSet) {
+ for (int i = sharedElements.size() - 1; i >= 0; i--) {
+ View view = sharedElements.valueAt(i);
+ if (view != null && nameOverridesSet.contains(view.getTransitionName())) {
+ views.add(view);
+ }
+ }
+ }
+
+ /**
* Configures the shared elements of an unoptimized fragment transaction's transition.
* This retrieves the shared elements of the incoming fragments, and schedules capturing
* the incoming fragment's shared elements. It also maps the views, and sets up the epicenter
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 82be7ab..1a36d1a 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -31,6 +31,7 @@
import android.app.ITaskStackListener;
import android.app.IUiAutomationConnection;
import android.app.IUidObserver;
+
import android.app.IUserSwitchObserver;
import android.app.Notification;
import android.app.PendingIntent;
@@ -65,6 +66,7 @@
import android.service.voice.IVoiceInteractionSession;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
import java.util.List;
@@ -571,6 +573,7 @@
void setPictureInPictureAspectRatio(in IBinder token, float aspectRatio);
boolean requestAutoFillData(in IResultReceiver receiver, in Bundle receiverExtras,
in IBinder activityToken);
+ void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback);
// WARNING: when these transactions are updated, check if they are any callers on the native
// side. If so, make sure they are using the correct transaction ids.
diff --git a/core/java/android/app/IInstrumentationWatcher.aidl b/core/java/android/app/IInstrumentationWatcher.aidl
index 405a3d8..6c8c4d6 100644
--- a/core/java/android/app/IInstrumentationWatcher.aidl
+++ b/core/java/android/app/IInstrumentationWatcher.aidl
@@ -21,7 +21,7 @@
import android.os.Bundle;
/** @hide */
-oneway interface IInstrumentationWatcher
+interface IInstrumentationWatcher
{
void instrumentationStatus(in ComponentName name, int resultCode,
in Bundle results);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 2a7341a..927ef6c 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -2,21 +2,22 @@
**
** Copyright 2007, 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
+** 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
+** 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
+** 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.app;
+import android.app.IOnNotificationChannelCreatedListener;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -58,7 +59,8 @@
int getImportance(String pkg, int uid);
int getPackageImportance(String pkg);
- void createNotificationChannel(String pkg, in NotificationChannel channel);
+ void createNotificationChannel(String pkg, in NotificationChannel channel,
+ in IOnNotificationChannelCreatedListener listener);
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
NotificationChannel getNotificationChannel(String pkg, String channelId);
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId);
diff --git a/core/java/android/app/IOnNotificationChannelCreatedListener.aidl b/core/java/android/app/IOnNotificationChannelCreatedListener.aidl
new file mode 100644
index 0000000..8e66542
--- /dev/null
+++ b/core/java/android/app/IOnNotificationChannelCreatedListener.aidl
@@ -0,0 +1,25 @@
+/*
+**
+** Copyright 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 android.app;
+
+import android.app.NotificationChannel;
+
+/** {@hide} */
+oneway interface IOnNotificationChannelCreatedListener {
+ void onNotificationChannelCreated(in NotificationChannel channel);
+}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 725cc29..036b47c 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -17,24 +17,32 @@
package android.app;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.trust.ITrustManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IUserManager;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.UserHandle;
-import android.os.UserManager;
+import android.util.Log;
import android.view.IWindowManager;
import android.view.IOnKeyguardExitResult;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
+import com.android.internal.policy.IKeyguardDismissCallback;
+
/**
* Class that can be used to lock and unlock the keyboard. Get an instance of this
* class by calling {@link android.content.Context#getSystemService(java.lang.String)}
@@ -43,10 +51,13 @@
* {@link android.app.KeyguardManager.KeyguardLock}.
*/
public class KeyguardManager {
- private IWindowManager mWM;
- private ITrustManager mTrustManager;
- private IUserManager mUserManager;
- private Context mContext;
+
+ private static final String TAG = "KeyguardManager";
+
+ private final Context mContext;
+ private final IWindowManager mWM;
+ private final IActivityManager mAm;
+ private final ITrustManager mTrustManager;
/**
* Intent used to prompt user for device credentials.
@@ -125,8 +136,8 @@
}
/**
- * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
- * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+ * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+ * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
* instead; this allows you to seamlessly hide the keyguard as your application
* moves in and out of the foreground and does not require that any special
* permissions be requested.
@@ -190,9 +201,11 @@
}
/**
+ * @deprecated Use {@link KeyguardDismissCallback}
* Callback passed to {@link KeyguardManager#exitKeyguardSecurely} to notify
* caller of result.
*/
+ @Deprecated
public interface OnKeyguardExitResult {
/**
@@ -202,19 +215,41 @@
void onKeyguardExitResult(boolean success);
}
+ /**
+ * Callback passed to {@link KeyguardManager#dismissKeyguard} to notify caller of result.
+ */
+ public static abstract class KeyguardDismissCallback {
+
+ /**
+ * Called when dismissing Keyguard is currently not feasible, i.e. when Keyguard is not
+ * available, not showing or when the activity requesting the Keyguard dismissal isn't
+ * showing or isn't showing behind Keyguard.
+ */
+ public void onDismissError() { }
+
+ /**
+ * Called when dismissing Keyguard has succeeded and the device is now unlocked.
+ */
+ public void onDismissSucceeded() { }
+
+ /**
+ * Called when dismissing Keyguard has been cancelled, i.e. when the user cancelled the
+ * operation or the bouncer was hidden for some other reason.
+ */
+ public void onDismissCancelled() { }
+ }
KeyguardManager(Context context) throws ServiceNotFoundException {
mContext = context;
mWM = WindowManagerGlobal.getWindowManagerService();
+ mAm = ActivityManager.getService();
mTrustManager = ITrustManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
- mUserManager = IUserManager.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.USER_SERVICE));
}
/**
- * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
- * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+ * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+ * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
* instead; this allows you to seamlessly hide the keyguard as your application
* moves in and out of the foreground and does not require that any special
* permissions be requested.
@@ -296,9 +331,8 @@
* @hide
*/
public boolean isDeviceLocked(int userId) {
- ITrustManager trustManager = getTrustManager();
try {
- return trustManager.isDeviceLocked(userId);
+ return mTrustManager.isDeviceLocked(userId);
} catch (RemoteException e) {
return false;
}
@@ -322,25 +356,63 @@
* @hide
*/
public boolean isDeviceSecure(int userId) {
- ITrustManager trustManager = getTrustManager();
try {
- return trustManager.isDeviceSecure(userId);
+ return mTrustManager.isDeviceSecure(userId);
} catch (RemoteException e) {
return false;
}
}
- private synchronized ITrustManager getTrustManager() {
- if (mTrustManager == null) {
- mTrustManager = ITrustManager.Stub.asInterface(
- ServiceManager.getService(Context.TRUST_SERVICE));
+ /**
+ * If the device is currently locked (see {@link #isKeyguardLocked()}, requests the Keyguard to
+ * be dismissed.
+ * <p>
+ * If the Keyguard is not secure or the device is currently in a trusted state, calling this
+ * method will immediately dismiss the Keyguard without any user interaction.
+ * <p>
+ * If the Keyguard is secure and the device is not in a trusted state, this will bring up the
+ * UI so the user can enter their credentials.
+ *
+ * @param activity The activity requesting the dismissal. The activity must be either visible
+ * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in
+ * which it would be visible if Keyguard would not be hiding it. If that's not
+ * the case, the request will fail immediately and
+ * {@link KeyguardDismissCallback#onDismissError} will be invoked.
+ * @param callback The callback to be called if the request to dismiss Keyguard was successful
+ * or {@code null} if the caller isn't interested in knowing the result.
+ * @param handler The handler to invoke the callback on, or {@code null} to use the main
+ * handler.
+ */
+ public void dismissKeyguard(@NonNull Activity activity,
+ @Nullable KeyguardDismissCallback callback, @Nullable Handler handler) {
+ try {
+ final Handler actualHandler = handler != null
+ ? handler
+ : new Handler(Looper.getMainLooper());
+ mAm.dismissKeyguard(activity.getActivityToken(), new IKeyguardDismissCallback.Stub() {
+ @Override
+ public void onDismissError() throws RemoteException {
+ actualHandler.post(callback::onDismissError);
+ }
+
+ @Override
+ public void onDismissSucceeded() throws RemoteException {
+ actualHandler.post(callback::onDismissSucceeded);
+ }
+
+ @Override
+ public void onDismissCancelled() throws RemoteException {
+ actualHandler.post(callback::onDismissCancelled);
+ }
+ });
+ } catch (RemoteException e) {
+ Log.i(TAG, "Failed to dismiss keyguard: " + e);
}
- return mTrustManager;
}
/**
- * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
- * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
+ * @deprecated Use {@link LayoutParams#FLAG_DISMISS_KEYGUARD}
+ * and/or {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED}
* instead; this allows you to seamlessly hide the keyguard as your application
* moves in and out of the foreground and does not require that any special
* permissions be requested.
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index bfabc0d..79a01c2 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -28,6 +28,7 @@
import android.text.TextUtils;
import java.io.IOException;
+import java.util.Arrays;
/**
* A representation of settings that apply to a collection of similarly themed notifications.
@@ -48,10 +49,12 @@
private static final String ATT_IMPORTANCE = "importance";
private static final String ATT_LIGHTS = "lights";
private static final String ATT_VIBRATION = "vibration";
+ private static final String ATT_VIBRATION_ENABLED = "vibration_enabled";
private static final String ATT_SOUND = "sound";
//TODO: add audio attributes support
private static final String ATT_AUDIO_ATTRIBUTES = "audio_attributes";
private static final String ATT_USER_LOCKED = "locked";
+ private static final String DELIMITER = ",";
/**
* @hide
@@ -96,8 +99,9 @@
private int mLockscreenVisibility = DEFAULT_VISIBILITY;
private Uri mSound;
private boolean mLights;
- private boolean mVibration;
+ private long[] mVibration;
private int mUserLockedFields;
+ private boolean mVibrationEnabled;
/**
* Creates a notification channel.
@@ -130,8 +134,9 @@
mSound = null;
}
mLights = in.readByte() != 0;
- mVibration = in.readByte() != 0;
+ mVibration = in.createLongArray();
mUserLockedFields = in.readInt();
+ mVibrationEnabled = in.readByte() != 0;
}
@Override
@@ -153,8 +158,9 @@
dest.writeByte((byte) 0);
}
dest.writeByte(mLights ? (byte) 1 : (byte) 0);
- dest.writeByte(mVibration ? (byte) 1 : (byte) 0);
+ dest.writeLongArray(mVibration);
dest.writeInt(mUserLockedFields);
+ dest.writeByte(mVibrationEnabled ? (byte) 1 : (byte) 0);
}
/**
@@ -221,12 +227,20 @@
}
/**
- * Sets whether notification posted to this channel should vibrate, even if individual
- * notifications are marked as having vibration only modifiable before the channel is submitted
- * to the NotificationManager.
+ * Sets whether notification posted to this channel should vibrate. The vibration pattern can
+ * be set with {@link #setVibrationPattern(long[])}. Only modifiable before the channel is
+ * submitted to the NotificationManager.
*/
- public void setVibration(boolean vibration) {
- this.mVibration = vibration;
+ public void enableVibration(boolean vibration) {
+ this.mVibrationEnabled = vibration;
+ }
+
+ /**
+ * Sets whether notification posted to this channel should vibrate. Only modifiable before the
+ * channel is submitted to the NotificationManager.
+ */
+ public void setVibrationPattern(long[] vibrationPattern) {
+ this.mVibration = vibrationPattern;
}
/**
@@ -277,6 +291,14 @@
* Returns whether notifications posted to this channel always vibrate.
*/
public boolean shouldVibrate() {
+ return mVibrationEnabled;
+ }
+
+ /**
+ * Returns the vibration pattern for notifications posted to this channel. Will be ignored if
+ * vibration is not enabled ({@link #shouldVibrate()}.
+ */
+ public long[] getVibrationPattern() {
return mVibration;
}
@@ -307,7 +329,8 @@
setLockscreenVisibility(safeInt(parser, ATT_VISIBILITY, DEFAULT_VISIBILITY));
setSound(safeUri(parser, ATT_SOUND));
setLights(safeBool(parser, ATT_LIGHTS, false));
- setVibration(safeBool(parser, ATT_VIBRATION, false));
+ enableVibration(safeBool(parser, ATT_VIBRATION_ENABLED, false));
+ setVibrationPattern(safeLongArray(parser, ATT_VIBRATION, null));
lockFields(safeInt(parser, ATT_USER_LOCKED, 0));
}
@@ -338,7 +361,10 @@
out.attribute(null, ATT_LIGHTS, Boolean.toString(shouldShowLights()));
}
if (shouldVibrate()) {
- out.attribute(null, ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+ out.attribute(null, ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
+ }
+ if (getVibrationPattern() != null) {
+ out.attribute(null, ATT_VIBRATION, longArrayToString(getVibrationPattern()));
}
if (getUserLockedFields() != 0) {
out.attribute(null, ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
@@ -369,8 +395,9 @@
record.put(ATT_SOUND, getSound().toString());
}
record.put(ATT_LIGHTS, Boolean.toString(shouldShowLights()));
- record.put(ATT_VIBRATION, Boolean.toString(shouldVibrate()));
+ record.put(ATT_VIBRATION_ENABLED, Boolean.toString(shouldVibrate()));
record.put(ATT_USER_LOCKED, Integer.toString(getUserLockedFields()));
+ record.put(ATT_VIBRATION, longArrayToString(getVibrationPattern()));
return record;
}
@@ -400,6 +427,30 @@
return Boolean.parseBoolean(value);
}
+ private static long[] safeLongArray(XmlPullParser parser, String att, long[] defValue) {
+ final String attributeValue = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(attributeValue)) return defValue;
+ String[] values = attributeValue.split(DELIMITER);
+ long[] longValues = new long[values.length];
+ for (int i = 0; i < values.length; i++) {
+ try {
+ longValues[i] = Long.parseLong(values[i]);
+ } catch (NumberFormatException e) {
+ longValues[i] = 0;
+ }
+ }
+ return longValues;
+ }
+
+ private static String longArrayToString(long[] values) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < values.length - 1; i++) {
+ sb.append(values[i]).append(DELIMITER);
+ }
+ sb.append(values[values.length - 1]);
+ return sb.toString();
+ }
+
public static final Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
@Override
public NotificationChannel createFromParcel(Parcel in) {
@@ -424,34 +475,35 @@
NotificationChannel that = (NotificationChannel) o;
- if (getImportance() != that.getImportance()) return false;
+ if (mImportance != that.mImportance) return false;
if (mBypassDnd != that.mBypassDnd) return false;
- if (getLockscreenVisibility() != that.getLockscreenVisibility()) return false;
+ if (mLockscreenVisibility != that.mLockscreenVisibility) return false;
if (mLights != that.mLights) return false;
- if (mVibration != that.mVibration) return false;
- if (getUserLockedFields() != that.getUserLockedFields()) return false;
- if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
- if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null)
- return false;
- return getSound() != null ? getSound().equals(
- that.getSound()) : that.getSound() == null;
+ if (mUserLockedFields != that.mUserLockedFields) return false;
+ if (mVibrationEnabled != that.mVibrationEnabled) return false;
+ if (mId != null ? !mId.equals(that.mId) : that.mId != null) return false;
+ if (mName != null ? !mName.equals(that.mName) : that.mName != null) return false;
+ if (mSound != null ? !mSound.equals(that.mSound) : that.mSound != null) return false;
+ return Arrays.equals(mVibration, that.mVibration);
}
@Override
public int hashCode() {
- int result = getId() != null ? getId().hashCode() : 0;
- result = 31 * result + (getName() != null ? getName().hashCode() : 0);
- result = 31 * result + getImportance();
+ int result = mId != null ? mId.hashCode() : 0;
+ result = 31 * result + (mName != null ? mName.hashCode() : 0);
+ result = 31 * result + mImportance;
result = 31 * result + (mBypassDnd ? 1 : 0);
- result = 31 * result + getLockscreenVisibility();
- result = 31 * result + (getSound() != null ? getSound().hashCode() : 0);
+ result = 31 * result + mLockscreenVisibility;
+ result = 31 * result + (mSound != null ? mSound.hashCode() : 0);
result = 31 * result + (mLights ? 1 : 0);
- result = 31 * result + (mVibration ? 1 : 0);
- result = 31 * result + getUserLockedFields();
+ result = 31 * result + Arrays.hashCode(mVibration);
+ result = 31 * result + mUserLockedFields;
+ result = 31 * result + (mVibrationEnabled ? 1 : 0);
return result;
}
+
@Override
public String toString() {
return "NotificationChannel{" +
@@ -462,8 +514,9 @@
", mLockscreenVisibility=" + mLockscreenVisibility +
", mSound=" + mSound +
", mLights=" + mLights +
- ", mVibration=" + mVibration +
+ ", mVibration=" + Arrays.toString(mVibration) +
", mUserLockedFields=" + mUserLockedFields +
+ ", mVibrationEnabled=" + mVibrationEnabled +
'}';
}
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 047f349..7693d76 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.TestApi;
import android.app.Notification.Builder;
@@ -30,6 +31,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -379,12 +381,42 @@
}
/**
- * Creates a notification channel that notifications can be posted to.
+ * Listener passed to {@link NotificationManager#createNotificationChannel} to notify
+ * caller of result.
*/
- public void createNotificationChannel(NotificationChannel channel) {
+ public interface OnNotificationChannelCreatedListener {
+ /**
+ * @param createdChannel NotificationChannel created by the system. Value is null iff an
+ * exception was thrown during channel creation.
+ */
+ public void onNotificationChannelCreated(NotificationChannel createdChannel);
+ }
+
+ /**
+ * Creates a notification channel that notifications can be posted to.
+ *
+ * @param channel the channel to attempt to create. Note that the created channel may differ
+ * from this value.
+ * @param listener Called when operation is finished.
+ * @param handler The handler to invoke the listener on, or {@code null} to use the main
+ * handler.
+ */
+ public void createNotificationChannel(
+ @NonNull NotificationChannel channel,
+ @NonNull OnNotificationChannelCreatedListener listener,
+ @Nullable Handler handler) {
INotificationManager service = getService();
try {
- service.createNotificationChannel(mContext.getPackageName(), channel);
+ final Handler actualHandler =
+ handler != null ? handler : new Handler(Looper.getMainLooper());
+ service.createNotificationChannel(mContext.getPackageName(), channel,
+ new IOnNotificationChannelCreatedListener.Stub() {
+ @Override public void onNotificationChannelCreated(
+ NotificationChannel channel) {
+ actualHandler.post(
+ () -> { listener.onNotificationChannelCreated(channel); });
+ }
+ });
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -583,7 +615,7 @@
* <p>
* Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
* @param id The id of the rule to update
- * @param automaticZenRule the rule to update.
+ * @param automaticZenRule the rule to update.
* @return Whether the rule was successfully updated.
*/
public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3ecc309..67ce342 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -514,7 +514,7 @@
new CachedServiceFetcher<WifiAwareManager>() {
@Override
public WifiAwareManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getService(Context.WIFI_AWARE_SERVICE);
+ IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_AWARE_SERVICE);
IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(b);
if (service == null) {
return null;
@@ -831,7 +831,7 @@
service = createService(ctx);
cache[mCacheIndex] = service;
} catch (ServiceNotFoundException e) {
- Log.wtf(TAG, e.getMessage(), e);
+ onServiceNotFound(e);
}
}
return (T)service;
@@ -849,13 +849,13 @@
private T mCachedInstance;
@Override
- public final T getService(ContextImpl unused) {
+ public final T getService(ContextImpl ctx) {
synchronized (StaticServiceFetcher.this) {
if (mCachedInstance == null) {
try {
mCachedInstance = createService();
} catch (ServiceNotFoundException e) {
- Log.wtf(TAG, e.getMessage(), e);
+ onServiceNotFound(e);
}
}
return mCachedInstance;
@@ -888,7 +888,7 @@
try {
mCachedInstance = createService(appContext != null ? appContext : ctx);
} catch (ServiceNotFoundException e) {
- Log.wtf(TAG, e.getMessage(), e);
+ onServiceNotFound(e);
}
}
return mCachedInstance;
@@ -897,4 +897,15 @@
public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
}
+
+ public static void onServiceNotFound(ServiceNotFoundException e) {
+ // We're mostly interested in tracking down long-lived core system
+ // components that might stumble if they obtain bad references; just
+ // emit a tidy log message for normal apps
+ if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
+ Log.wtf(TAG, e.getMessage(), e);
+ } else {
+ Log.w(TAG, e.getMessage());
+ }
+ }
}
diff --git a/core/java/android/app/admin/ConnectEvent.java b/core/java/android/app/admin/ConnectEvent.java
index e05feaf..c1646bb 100644
--- a/core/java/android/app/admin/ConnectEvent.java
+++ b/core/java/android/app/admin/ConnectEvent.java
@@ -75,6 +75,11 @@
};
@Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
public void writeToParcel(Parcel out, int flags) {
// write parcel token first
out.writeInt(PARCEL_TOKEN_CONNECT_EVENT);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0ec1b1..39c8b79 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -79,7 +79,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
/**
* Public interface for managing policies enforced on a device. Most clients of this class must be
@@ -151,6 +150,7 @@
* <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LOGO_URI}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_MAIN_COLOR}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_SKIP_USER_CONSENT}, optional</li>
* </ul>
*
* <p>When managed provisioning has completed, broadcasts are sent to the application specified
@@ -739,8 +739,13 @@
* <p>The broadcast is limited to the primary profile, to the app specified in the provisioning
* intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE}.
*
- * <p>This intent will contain the extra {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} which
- * corresponds to the account requested to be migrated at provisioning time, if any.
+ * <p>This intent will contain the following extras
+ * <ul>
+ * <li>{@link Intent#EXTRA_USER}, corresponds to the {@link UserHandle} of the managed
+ * profile.</li>
+ * <li>{@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE}, corresponds to the account requested to
+ * be migrated at provisioning time, if any.</li>
+ * </ul>
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGED_PROFILE_PROVISIONED
@@ -813,6 +818,16 @@
"android.app.extra.PROVISIONING_SKIP_USER_SETUP";
/**
+ * A boolean extra indicating if the user consent steps from the provisioning flow should be
+ * skipped. If unspecified, defaults to {@code false}.
+ *
+ * It can only be used by an existing device owner trying to create a managed profile via
+ * {@link #ACTION_PROVISION_MANAGED_PROFILE}. Otherwise it is ignored.
+ */
+ public static final String EXTRA_PROVISIONING_SKIP_USER_CONSENT =
+ "android.app.extra.PROVISIONING_SKIP_USER_CONSENT";
+
+ /**
* This MIME type is used for starting the device owner provisioning.
*
* <p>During device owner provisioning a device admin app is set as the owner of the device.
@@ -3834,14 +3849,22 @@
}
/**
- * @return true if the device is managed by any device owner.
+ * Called by the system to find out whether the device is managed by a Device Owner.
*
- * <p>Requires the MANAGE_USERS permission.
+ * @return whether the device is managed by a Device Owner.
+ * @throws SecurityException if the caller is not the device owner, does not hold the
+ * MANAGE_USERS permission and is not the system.
*
* @hide
*/
+ @SystemApi
+ @TestApi
public boolean isDeviceManaged() {
- return getDeviceOwnerComponentOnAnyUser() != null;
+ try {
+ return mService.hasDeviceOwner();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
@@ -6401,7 +6424,7 @@
}
/**
- * Called by a profile owner of a managed profile to set the name of the organization under
+ * Called by the device owner or profile owner to set the name of the organization under
* management.
* <p>
* If the organization name needs to be localized, it is the responsibility of the
@@ -6410,7 +6433,7 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param title The organization name or {@code null} to clear a previously set name.
- * @throws SecurityException if {@code admin} is not a profile owner.
+ * @throws SecurityException if {@code admin} is not a device or profile owner.
*/
public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
throwIfParentInstance("setOrganizationName");
@@ -6439,6 +6462,25 @@
}
/**
+ * Called by the system to retrieve the name of the organization managing the device.
+ *
+ * @return The organization name or {@code null} if none is set.
+ * @throws SecurityException if the caller is not the device owner, does not hold the
+ * MANAGE_USERS permission and is not the system.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public @Nullable CharSequence getDeviceOwnerOrganizationName() {
+ try {
+ return mService.getDeviceOwnerOrganizationName();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Retrieve the default title message used in the confirm credentials screen for a given user.
*
* @param userHandle The user id of the user we're interested in.
@@ -6491,27 +6533,32 @@
}
/**
- * @hide
- * Indicates the entity that controls the device or profile owner. A user/profile is considered
- * affiliated if it is managed by the same entity as the device.
- *
- * <p> By definition, the user that the device owner runs on is always affiliated. Any other
- * user/profile is considered affiliated if the following conditions are both met:
- * <ul>
- * <li>The device owner and the user's/profile's profile owner have called this method,
- * specifying a set of opaque affiliation ids each. If the sets specified by the device owner
- * and a profile owner intersect, they must have come from the same source, which means that
- * the device owner and profile owner are controlled by the same entity.</li>
- * <li>The device owner's and profile owner's package names are the same.</li>
- * </ul>
+ * Indicates the entity that controls the device or profile owner. Two users/profiles are
+ * affiliated if the set of ids set by their device or profile owners intersect.
*
* @param admin Which profile or device owner this request is associated with.
- * @param ids A set of opaque affiliation ids.
+ * @param ids A list of opaque non-empty affiliation ids. Duplicate elements will be ignored.
+ *
+ * @throws NullPointerException if {@code ids} is null or contains null elements.
+ * @throws IllegalArgumentException if {@code ids} contains an empty string.
*/
- public void setAffiliationIds(@NonNull ComponentName admin, Set<String> ids) {
+ public void setAffiliationIds(@NonNull ComponentName admin, @NonNull List<String> ids) {
throwIfParentInstance("setAffiliationIds");
try {
- mService.setAffiliationIds(admin, new ArrayList<String>(ids));
+ mService.setAffiliationIds(admin, ids);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the list of affiliation ids previously set via {@link #setAffiliationIds}, or an
+ * empty list if none have been set.
+ */
+ public @NonNull List<String> getAffiliationIds(@NonNull ComponentName admin) {
+ throwIfParentInstance("getAffiliationIds");
+ try {
+ return mService.getAffiliationIds(admin);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6519,15 +6566,17 @@
/**
* @hide
- * Returns whether this user/profile is affiliated with the device. See
- * {@link #setAffiliationIds} for the definition of affiliation.
+ * Returns whether this user/profile is affiliated with the device.
+ * <p>
+ * By definition, the user that the device owner runs on is always affiliated with the device.
+ * Any other user/profile is considered affiliated with the device if the set specified by its
+ * profile owner via {@link #setAffiliationIds} intersects with the device owner's.
*
- * @return whether this user/profile is affiliated with the device.
*/
public boolean isAffiliatedUser() {
throwIfParentInstance("isAffiliatedUser");
try {
- return mService != null && mService.isAffiliatedUser();
+ return mService.isAffiliatedUser();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/DnsEvent.java b/core/java/android/app/admin/DnsEvent.java
index 0ec134a..63ea8db 100644
--- a/core/java/android/app/admin/DnsEvent.java
+++ b/core/java/android/app/admin/DnsEvent.java
@@ -95,6 +95,11 @@
};
@Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
public void writeToParcel(Parcel out, int flags) {
// write parcel token first
out.writeInt(PARCEL_TOKEN_DNS_EVENT);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b7e0e92..f303bbc 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -132,6 +132,7 @@
boolean setDeviceOwner(in ComponentName who, String ownerName, int userId);
ComponentName getDeviceOwnerComponent(boolean callingUserOnly);
+ boolean hasDeviceOwner();
String getDeviceOwnerName();
void clearDeviceOwner(String packageName);
int getDeviceOwnerUserId();
@@ -293,12 +294,14 @@
void setOrganizationName(in ComponentName admin, in CharSequence title);
CharSequence getOrganizationName(in ComponentName admin);
+ CharSequence getDeviceOwnerOrganizationName();
CharSequence getOrganizationNameForUser(int userHandle);
int getUserProvisioningState();
void setUserProvisioningState(int state, int userHandle);
void setAffiliationIds(in ComponentName admin, in List<String> ids);
+ List<String> getAffiliationIds(in ComponentName admin);
boolean isAffiliatedUser();
void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled);
diff --git a/core/java/android/app/admin/NetworkEvent.java b/core/java/android/app/admin/NetworkEvent.java
index ec7ed00..1dbff20 100644
--- a/core/java/android/app/admin/NetworkEvent.java
+++ b/core/java/android/app/admin/NetworkEvent.java
@@ -26,14 +26,14 @@
*/
public abstract class NetworkEvent implements Parcelable {
- protected static final int PARCEL_TOKEN_DNS_EVENT = 1;
- protected static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
+ static final int PARCEL_TOKEN_DNS_EVENT = 1;
+ static final int PARCEL_TOKEN_CONNECT_EVENT = 2;
/** The package name of the UID that performed the query. */
- protected String packageName;
+ String packageName;
/** The timestamp of the event being reported in milliseconds. */
- protected long timestamp;
+ long timestamp;
protected NetworkEvent() {
//empty constructor
@@ -81,5 +81,8 @@
return new NetworkEvent[size];
}
};
+
+ @Override
+ public abstract void writeToParcel(Parcel out, int flags);
}
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 5162a73..ca3658b 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -853,14 +853,29 @@
* @hide
*/
public void prepareToLeaveProcess(boolean leavingPackage) {
+ prepareToLeaveProcess(leavingPackage, 0);
+ }
+
+ /**
+ * Prepare this {@link ClipData} to leave an app process.
+ *
+ * @hide
+ */
+ public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) {
final int size = mItems.size();
for (int i = 0; i < size; i++) {
final Item item = mItems.get(i);
if (item.mIntent != null) {
item.mIntent.prepareToLeaveProcess(leavingPackage);
}
- if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
- item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+ if (item.mUri != null && leavingPackage) {
+ if (StrictMode.vmFileUriExposureEnabled()) {
+ item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
+ }
+ if (StrictMode.vmContentUriWithoutPermissionEnabled()) {
+ item.mUri.checkContentUriWithoutPermission("ClipData.Item.getUri()",
+ intentFlags);
+ }
}
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 50589fe..a5d7999 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9009,7 +9009,7 @@
mSelector.prepareToLeaveProcess(leavingPackage);
}
if (mClipData != null) {
- mClipData.prepareToLeaveProcess(leavingPackage);
+ mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
}
if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
@@ -9036,6 +9036,17 @@
mData.checkFileUriExposed("Intent.getData()");
}
}
+
+ if (mAction != null && mData != null && StrictMode.vmContentUriWithoutPermissionEnabled()
+ && leavingPackage) {
+ switch (mAction) {
+ case ACTION_PROVIDER_CHANGED:
+ // Ignore actions that don't need to grant
+ break;
+ default:
+ mData.checkContentUriWithoutPermission("Intent.getData()", getFlags());
+ }
+ }
}
/**
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 2beca7b..358787e 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -89,6 +89,7 @@
* @return The label for the activity.
*/
public CharSequence getLabel() {
+ // TODO: Go through LauncherAppsService
return mActivityInfo.loadLabel(mPm);
}
@@ -101,6 +102,7 @@
* @return The drawable associated with the activity.
*/
public Drawable getIcon(int density) {
+ // TODO: Go through LauncherAppsService
final int iconRes = mActivityInfo.getIconResource();
Drawable icon = null;
// Get the preferred density icon from the app's resources
@@ -144,8 +146,9 @@
*/
public long getFirstInstallTime() {
try {
+ // TODO: Go through LauncherAppsService
return mPm.getPackageInfo(mActivityInfo.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
+ PackageManager.MATCH_UNINSTALLED_PACKAGES).firstInstallTime;
} catch (NameNotFoundException nnfe) {
// Sorry, can't find package
return 0;
@@ -171,6 +174,7 @@
Drawable originalIcon = getIcon(density);
if (originalIcon instanceof BitmapDrawable) {
+ // TODO: Go through LauncherAppsService
return mPm.getUserBadgedIcon(originalIcon, mUser);
} else {
Log.e(TAG, "Unable to create badged icon for " + mActivityInfo);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 6b23da9..7fc8044 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -447,12 +447,12 @@
/**
* Retrieve all of the information we know about a particular package / application.
*
- * @param packageName The package of the application
+ * @param packageName The package name of the application
* @param flags Additional option flags {@link PackageManager#getApplicationInfo}
* @param user The UserHandle of the profile.
*
* @return An {@link ApplicationInfo} containing information about the package or
- * null of the package isn't found.
+ * null if the package isn't installed for the given user.
* @hide
*/
public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b3dd0e5..3f052d38 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -435,6 +435,20 @@
public static final int MATCH_FACTORY_ONLY = 0x00200000;
/**
+ * Allows querying of packages installed for any user, not just the specific one. This flag
+ * is only meant for use by apps that have INTERACT_ACROSS_USERS_FULL permission.
+ * @hide
+ */
+ public static final int MATCH_ANY_USER = 0x00400000;
+
+ /**
+ * Combination of MATCH_ANY_USER and MATCH_UNINSTALLED_PACKAGES to mean any known
+ * package.
+ * @hide
+ */
+ public static final int MATCH_KNOWN_PACKAGES = MATCH_UNINSTALLED_PACKAGES | MATCH_ANY_USER;
+
+ /**
* Internal flag used to indicate that a system component has done their
* homework and verified that they correctly handle packages and components
* that come and go over time. In particular:
@@ -4522,32 +4536,6 @@
throws NameNotFoundException;
/**
- * Returns a managed-user-style badged copy of the given drawable allowing the user to
- * distinguish it from the original drawable.
- * The caller can specify the location in the bounds of the drawable to be
- * badged where the badge should be applied as well as the density of the
- * badge to be used.
- * <p>
- * If the original drawable is a BitmapDrawable and the backing bitmap is
- * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
- * is performed in place and the original drawable is returned.
- * </p>
- *
- * @param drawable The drawable to badge.
- * @param badgeLocation Where in the bounds of the badged drawable to place
- * the badge. If it's {@code null}, the badge is applied on top of the entire
- * drawable being badged.
- * @param badgeDensity The optional desired density for the badge as per
- * {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
- * the density of the display is used.
- * @return A drawable that combines the original drawable and a badge as
- * determined by the system.
- * @hide
- */
- public abstract Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
- int badgeDensity);
-
- /**
* If the target user is a managed profile, then this returns a badged copy of the given icon
* to be able to distinguish it from the original icon. For badging an arbitrary drawable use
* {@link #getUserBadgedDrawableForDensity(
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bb9c18a..f363bd8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -478,20 +478,25 @@
/**
* Returns true if the package is installed and not hidden, or if the caller
* explicitly wanted all uninstalled and hidden packages as well.
+ * @param appInfo The applicationInfo of the app being checked.
*/
- private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state) {
- return (state.installed && !state.hidden)
- || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
+ ApplicationInfo appInfo) {
+ // If available for the target user, or trying to match uninstalled packages and it's
+ // a system app.
+ return state.isAvailable(flags)
+ || (appInfo != null && appInfo.isSystemApp()
+ && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
}
public static boolean isAvailable(PackageUserState state) {
- return checkUseInstalledOrHidden(0, state);
+ return checkUseInstalledOrHidden(0, state, null);
}
public static PackageInfo generatePackageInfo(PackageParser.Package p,
int gids[], int flags, long firstInstallTime, long lastUpdateTime,
Set<String> grantedPermissions, PackageUserState state, int userId) {
- if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
+ if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
return null;
}
PackageInfo pi = new PackageInfo();
@@ -1696,6 +1701,11 @@
String str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
if (str != null && str.length() > 0) {
+ if ((flags & PARSE_IS_EPHEMERAL) != 0) {
+ outError[0] = "sharedUserId not allowed in ephemeral application";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
+ return null;
+ }
String nameError = validateName(str, true, false);
if (nameError != null && !"android".equals(pkg.packageName)) {
outError[0] = "<manifest> specifies bad sharedUserId name \""
@@ -5445,7 +5455,7 @@
public static ApplicationInfo generateApplicationInfo(Package p, int flags,
PackageUserState state, int userId) {
if (p == null) return null;
- if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) {
+ if (!checkUseInstalledOrHidden(flags, state, p.applicationInfo) || !p.isMatch(flags)) {
return null;
}
if (!copyNeeded(flags, p, state, null, userId)
@@ -5483,7 +5493,7 @@
public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags,
PackageUserState state, int userId) {
if (ai == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
+ if (!checkUseInstalledOrHidden(flags, state, ai)) {
return null;
}
// This is only used to return the ResolverActivity; we will just always
@@ -5549,7 +5559,7 @@
public static final ActivityInfo generateActivityInfo(Activity a, int flags,
PackageUserState state, int userId) {
if (a == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
+ if (!checkUseInstalledOrHidden(flags, state, a.owner.applicationInfo)) {
return null;
}
if (!copyNeeded(flags, a.owner, state, a.metaData, userId)) {
@@ -5565,7 +5575,7 @@
public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags,
PackageUserState state, int userId) {
if (ai == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
+ if (!checkUseInstalledOrHidden(flags, state, ai.applicationInfo)) {
return null;
}
// This is only used to return the ResolverActivity; we will just always
@@ -5603,7 +5613,7 @@
public static final ServiceInfo generateServiceInfo(Service s, int flags,
PackageUserState state, int userId) {
if (s == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
+ if (!checkUseInstalledOrHidden(flags, state, s.owner.applicationInfo)) {
return null;
}
if (!copyNeeded(flags, s.owner, state, s.metaData, userId)) {
@@ -5652,7 +5662,7 @@
public static final ProviderInfo generateProviderInfo(Provider p, int flags,
PackageUserState state, int userId) {
if (p == null) return null;
- if (!checkUseInstalledOrHidden(flags, state)) {
+ if (!checkUseInstalledOrHidden(flags, state, p.owner.applicationInfo)) {
return null;
}
if (!copyNeeded(flags, p.owner, state, p.metaData, userId)
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 8ce8a13..1821458 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,7 +29,6 @@
import android.util.ArraySet;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
/**
@@ -80,9 +79,14 @@
/**
* Test if this package is installed.
*/
- public boolean isInstalled(int flags) {
- return (this.installed && !this.hidden)
- || (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+ public boolean isAvailable(int flags) {
+ // True if it is installed for this user and it is not hidden. If it is hidden,
+ // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
+ final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+ return matchAnyUser
+ || (this.installed
+ && (!this.hidden || matchUninstalled));
}
/**
@@ -95,11 +99,14 @@
* </p>
*/
public boolean isMatch(ComponentInfo componentInfo, int flags) {
- if (!isInstalled(flags)) return false;
+ final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
+ if (!isAvailable(flags)
+ && !(isSystemApp && matchUninstalled)) return false;
if (!isEnabled(componentInfo, flags)) return false;
if ((flags & MATCH_SYSTEM_ONLY) != 0) {
- if (!componentInfo.applicationInfo.isSystemApp()) {
+ if (!isSystemApp) {
return false;
}
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index e796fa7..f34b590 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -109,6 +109,8 @@
*/
public int profileGroupId;
public int restrictedProfileParentId;
+ /** Which profile badge color/label to use. */
+ public int profileBadge;
/** User is only partially created. */
public boolean partial;
@@ -233,6 +235,7 @@
profileGroupId = orig.profileGroupId;
restrictedProfileParentId = orig.restrictedProfileParentId;
guestToRemove = orig.guestToRemove;
+ profileBadge = orig.profileBadge;
}
public UserHandle getUserHandle() {
@@ -261,6 +264,7 @@
dest.writeInt(profileGroupId);
dest.writeInt(guestToRemove ? 1 : 0);
dest.writeInt(restrictedProfileParentId);
+ dest.writeInt(profileBadge);
}
public static final Parcelable.Creator<UserInfo> CREATOR
@@ -286,5 +290,6 @@
profileGroupId = source.readInt();
guestToRemove = source.readInt() != 0;
restrictedProfileParentId = source.readInt();
+ profileBadge = source.readInt();
}
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 9e00b65..45cd084 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -440,7 +440,7 @@
*/
public abstract void createCaptureSessionByOutputConfigurations(
List<OutputConfiguration> outputConfigurations,
- CameraCaptureSession.StateCallback callback, Handler handler)
+ CameraCaptureSession.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException;
/**
* Create a new reprocessable camera capture session by providing the desired reprocessing
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index cdf7013..aa109de 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -26,6 +26,7 @@
import android.os.CancellationSignal.OnCancelListener;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -757,20 +758,22 @@
new IFingerprintServiceLockoutResetCallback.Stub() {
@Override
- public void onLockoutReset(long deviceId) throws RemoteException {
- final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
- wakeLock.acquire();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
+ public void onLockoutReset(long deviceId, IRemoteCallback serverCallback)
+ throws RemoteException {
+ try {
+ final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
+ wakeLock.acquire();
+ mHandler.post(() -> {
try {
callback.onLockoutReset();
} finally {
wakeLock.release();
}
- }
- });
+ });
+ } finally {
+ serverCallback.sendResult(null /* data */);
+ }
}
});
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
index e027a2b3..971e14c 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -17,14 +17,17 @@
import android.hardware.fingerprint.Fingerprint;
import android.os.Bundle;
+import android.os.IRemoteCallback;
import android.os.UserHandle;
/**
* Callback when lockout period expired and clients are allowed to authenticate again.
* @hide
*/
-interface IFingerprintServiceLockoutResetCallback {
+oneway interface IFingerprintServiceLockoutResetCallback {
- /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */
- void onLockoutReset(long deviceId);
+ /**
+ * A wakelock will be held until the reciever calls back into {@param callback}
+ */
+ void onLockoutReset(long deviceId, IRemoteCallback callback);
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index c2286ad..a0f74ec 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -144,7 +144,7 @@
* scorer.
*/
public String getActiveScorerPackage() {
- NetworkScorerAppData app = NetworkScorerAppManager.getActiveScorer(mContext);
+ NetworkScorerAppData app = new NetworkScorerAppManager(mContext).getActiveScorer();
if (app == null) {
return null;
}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 29291ca..ebb31c9 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -41,14 +41,17 @@
*
* @hide
*/
-public final class NetworkScorerAppManager {
+public class NetworkScorerAppManager {
private static final String TAG = "NetworkScorerAppManager";
private static final Intent SCORE_INTENT =
new Intent(NetworkScoreManager.ACTION_SCORE_NETWORKS);
- /** This class cannot be instantiated. */
- private NetworkScorerAppManager() {}
+ private final Context mContext;
+
+ public NetworkScorerAppManager(Context context) {
+ mContext = context;
+ }
public static class NetworkScorerAppData {
/** Package name of this scorer app. */
@@ -108,7 +111,7 @@
*
* @return the list of scorers, or the empty list if there are no valid scorers.
*/
- public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
+ public Collection<NetworkScorerAppData> getAllValidScorers() {
// Network scorer apps can only run as the primary user so exit early if we're not the
// primary user.
if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
@@ -116,7 +119,7 @@
}
List<NetworkScorerAppData> scorers = new ArrayList<>();
- PackageManager pm = context.getPackageManager();
+ PackageManager pm = mContext.getPackageManager();
// Only apps installed under the primary user of the device can be scorers.
// TODO: http://b/23422763
List<ResolveInfo> receivers =
@@ -179,10 +182,10 @@
* selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
* it was disabled or uninstalled).
*/
- public static NetworkScorerAppData getActiveScorer(Context context) {
- String scorerPackage = Settings.Global.getString(context.getContentResolver(),
+ public NetworkScorerAppData getActiveScorer() {
+ String scorerPackage = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP);
- return getScorer(context, scorerPackage);
+ return getScorer(scorerPackage);
}
/**
@@ -190,13 +193,12 @@
*
* <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
*
- * @param context the context of the calling application
* @param packageName the packageName of the new scorer to use. If null, scoring will be
* disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
* @return true if the scorer was changed, or false if the package is not a valid scorer.
*/
- public static boolean setActiveScorer(Context context, String packageName) {
- String oldPackageName = Settings.Global.getString(context.getContentResolver(),
+ public boolean setActiveScorer(String packageName) {
+ String oldPackageName = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP);
if (TextUtils.equals(oldPackageName, packageName)) {
// No change.
@@ -206,13 +208,13 @@
Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
if (packageName == null) {
- Settings.Global.putString(context.getContentResolver(),
+ Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP, null);
return true;
} else {
// We only make the change if the new package is valid.
- if (getScorer(context, packageName) != null) {
- Settings.Global.putString(context.getContentResolver(),
+ if (getScorer(packageName) != null) {
+ Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NETWORK_SCORER_APP, packageName);
return true;
} else {
@@ -223,8 +225,8 @@
}
/** Determine whether the application with the given UID is the enabled scorer. */
- public static boolean isCallerActiveScorer(Context context, int callingUid) {
- NetworkScorerAppData defaultApp = getActiveScorer(context);
+ public boolean isCallerActiveScorer(int callingUid) {
+ NetworkScorerAppData defaultApp = getActiveScorer();
if (defaultApp == null) {
return false;
}
@@ -233,16 +235,16 @@
}
// To be extra safe, ensure the caller holds the SCORE_NETWORKS permission. It always
// should, since it couldn't become the active scorer otherwise, but this can't hurt.
- return context.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) ==
+ return mContext.checkCallingPermission(Manifest.permission.SCORE_NETWORKS) ==
PackageManager.PERMISSION_GRANTED;
}
/** Returns the {@link NetworkScorerAppData} for the given app, or null if it's not a scorer. */
- public static NetworkScorerAppData getScorer(Context context, String packageName) {
+ public NetworkScorerAppData getScorer(String packageName) {
if (TextUtils.isEmpty(packageName)) {
return null;
}
- Collection<NetworkScorerAppData> applications = getAllValidScorers(context);
+ Collection<NetworkScorerAppData> applications = getAllValidScorers();
for (NetworkScorerAppData app : applications) {
if (packageName.equals(app.mPackageName)) {
return app;
diff --git a/core/java/android/net/RoughtimeClient.java b/core/java/android/net/RoughtimeClient.java
deleted file mode 100644
index cf4d8a2..0000000
--- a/core/java/android/net/RoughtimeClient.java
+++ /dev/null
@@ -1,499 +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 android.net;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.security.MessageDigest;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-
-/**
- * {@hide}
- *
- * Simple Roughtime client class for retrieving network time.
- */
-public class RoughtimeClient
-{
- private static final String TAG = "RoughtimeClient";
- private static final boolean ENABLE_DEBUG = true;
-
- private static final int ROUGHTIME_PORT = 5333;
-
- private static final int MIN_REQUEST_SIZE = 1024;
-
- private static final int NONCE_SIZE = 64;
-
- private static final int MAX_DATAGRAM_SIZE = 65507;
-
- private final SecureRandom random = new SecureRandom();
-
- /**
- * Tag values. Exposed for use in tests only.
- */
- protected static enum Tag {
- /**
- * Nonce used to initiate a transaction.
- */
- NONC(0x434e4f4e),
-
- /**
- * Signed portion of a response.
- **/
- SREP(0x50455253),
-
- /**
- * Pad data. Always the largest tag lexicographically.
- */
- PAD(0xff444150),
-
- /**
- * A signature for a neighboring SREP.
- */
- SIG(0x474953),
-
- /**
- * Server certificate.
- */
- CERT(0x54524543),
-
- /**
- * Position in the Merkle tree.
- */
- INDX(0x58444e49),
-
- /**
- * Upward path in the Merkle tree.
- */
- PATH(0x48544150),
-
- /**
- * Midpoint of the time interval in the response.
- */
- MIDP(0x5044494d),
-
- /**
- * Radius of the time interval in the response.
- */
- RADI(0x49444152),
-
- /**
- * Root of the Merkle tree.
- */
- ROOT(0x544f4f52),
-
- /**
- * Delegation from the long term key to an online key.
- */
- DELE(0x454c4544),
-
- /**
- * Online public key.
- */
- PUBK(0x4b425550),
-
- /**
- * Earliest midpoint time the given PUBK can authenticate.
- */
- MINT(0x544e494d),
-
- /**
- * Latest midpoint time the given PUBK can authenticate.
- */
- MAXT(0x5458414d);
-
- private final int value;
-
- Tag(int value) {
- this.value = value;
- }
-
- private int value() {
- return value;
- }
- }
-
- /**
- * A result retrieved from a roughtime server.
- */
- private static class Result {
- public long midpoint;
- public int radius;
- public long collectionTime;
- }
-
- /**
- * A Roughtime protocol message. Functionally a serializable map from Tags
- * to byte arrays.
- */
- protected static class Message {
- private HashMap<Integer,byte[]> items = new HashMap<Integer,byte[]>();
- public int padSize = 0;
-
- public Message() {}
-
- /**
- * Set the given data for the given tag.
- */
- public void put(Tag tag, byte[] data) {
- put(tag.value(), data);
- }
-
- private void put(int tag, byte[] data) {
- items.put(tag, data);
- }
-
- /**
- * Get the data associated with the given tag.
- */
- public byte[] get(Tag tag) {
- return items.get(tag.value());
- }
-
- /**
- * Get the data associated with the given tag and decode it as a 64-bit
- * integer.
- */
- public long getLong(Tag tag) {
- ByteBuffer b = ByteBuffer.wrap(get(tag));
- return b.getLong();
- }
-
- /**
- * Get the data associated with the given tag and decode it as a 32-bit
- * integer.
- */
- public int getInt(Tag tag) {
- ByteBuffer b = ByteBuffer.wrap(get(tag));
- return b.getInt();
- }
-
- /**
- * Encode the given long value as a 64-bit little-endian value and
- * associate it with the given tag.
- */
- public void putLong(Tag tag, long l) {
- ByteBuffer b = ByteBuffer.allocate(8);
- b.putLong(l);
- put(tag, b.array());
- }
-
- /**
- * Encode the given int value as a 32-bit little-endian value and
- * associate it with the given tag.
- */
- public void putInt(Tag tag, int l) {
- ByteBuffer b = ByteBuffer.allocate(4);
- b.putInt(l);
- put(tag, b.array());
- }
-
- /**
- * Get a packed representation of this message suitable for the wire.
- */
- public byte[] serialize() {
- if (items.size() == 0) {
- if (padSize > 4)
- return new byte[padSize];
- else
- return new byte[4];
- }
-
- int size = 0;
-
- ArrayList<Integer> offsets = new ArrayList<Integer>();
- ArrayList<Integer> tagList = new ArrayList<Integer>(items.keySet());
- Collections.sort(tagList);
-
- boolean first = true;
- for (int tag : tagList) {
- if (! first) {
- offsets.add(size);
- }
-
- first = false;
- size += items.get(tag).length;
- }
-
- ByteBuffer dataBuf = ByteBuffer.allocate(size);
- dataBuf.order(ByteOrder.LITTLE_ENDIAN);
-
- int valueDataSize = size;
- size += 4 + offsets.size() * 4 + tagList.size() * 4;
-
- int tagCount = items.size();
-
- if (size < padSize) {
- offsets.add(valueDataSize);
- tagList.add(Tag.PAD.value());
-
- if (size + 8 > padSize) {
- size = size + 8;
- } else {
- size = padSize;
- }
-
- tagCount += 1;
- }
-
- ByteBuffer buf = ByteBuffer.allocate(size);
- buf.order(ByteOrder.LITTLE_ENDIAN);
- buf.putInt(tagCount);
-
- for (int offset : offsets) {
- buf.putInt(offset);
- }
-
- for (int tag : tagList) {
- buf.putInt(tag);
-
- if (tag != Tag.PAD.value()) {
- dataBuf.put(items.get(tag));
- }
- }
-
- buf.put(dataBuf.array());
-
- return buf.array();
- }
-
- /**
- * Given a byte stream from the wire, unpack it into a Message object.
- */
- public static Message deserialize(byte[] data) {
- ByteBuffer buf = ByteBuffer.wrap(data);
- buf.order(ByteOrder.LITTLE_ENDIAN);
-
- Message msg = new Message();
-
- int count = buf.getInt();
-
- if (count == 0) {
- return msg;
- }
-
- ArrayList<Integer> offsets = new ArrayList<Integer>();
- offsets.add(0);
-
- for (int i = 1; i < count; i++) {
- offsets.add(buf.getInt());
- }
-
- ArrayList<Integer> tags = new ArrayList<Integer>();
- for (int i = 0; i < count; i++) {
- int tag = buf.getInt();
- tags.add(tag);
- }
-
- offsets.add(buf.remaining());
-
- for (int i = 0; i < count; i++) {
- int tag = tags.get(i);
- int start = offsets.get(i);
- int end = offsets.get(i+1);
- byte[] content = new byte[end - start];
-
- buf.get(content);
- if (tag != Tag.PAD.value()) {
- msg.put(tag, content);
- }
- }
-
- return msg;
- }
-
- /**
- * Send this message over the given socket to the given address and port.
- */
- public void send(DatagramSocket socket, InetAddress address, int port)
- throws IOException {
- byte[] buffer = serialize();
- DatagramPacket message = new DatagramPacket(buffer, buffer.length,
- address, port);
- socket.send(message);
- }
-
- /**
- * Receive a Message object from the given socket.
- */
- public static Message receive(DatagramSocket socket)
- throws IOException {
- byte[] buffer = new byte[MAX_DATAGRAM_SIZE];
- DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
-
- socket.receive(packet);
-
- return deserialize(Arrays.copyOf(buffer, packet.getLength()));
- }
- }
-
- private MessageDigest messageDigest = null;
-
- private final ArrayList<Result> results = new ArrayList<Result>();
- private long lastRequest = 0;
-
- private Message createRequestMessage() {
- byte[] nonce = new byte[NONCE_SIZE];
- random.nextBytes(nonce); // TODO: Chain nonces
-
- assert nonce.length == NONCE_SIZE :
- "Nonce must be " + NONCE_SIZE + " bytes.";
-
- Message msg = new Message();
-
- msg.put(Tag.NONC, nonce);
- msg.padSize = MIN_REQUEST_SIZE;
-
- return msg;
- }
-
- /**
- * Contact the Roughtime server at the given address and port and collect a
- * result time to add to our collection.
- *
- * @param host host name of the server.
- * @param timeout network timeout in milliseconds.
- * @return true if the transaction was successful.
- */
- public boolean requestTime(String host, int timeout) {
- InetAddress address = null;
- try {
- address = InetAddress.getByName(host);
- } catch (Exception e) {
- if (ENABLE_DEBUG) {
- Log.d(TAG, "request time failed", e);
- }
-
- return false;
- }
- return requestTime(address, ROUGHTIME_PORT, timeout);
- }
-
- /**
- * Contact the Roughtime server at the given address and port and collect a
- * result time to add to our collection.
- *
- * @param address address for the server.
- * @param port port to talk to the server on.
- * @param timeout network timeout in milliseconds.
- * @return true if the transaction was successful.
- */
- public boolean requestTime(InetAddress address, int port, int timeout) {
-
- final long rightNow = SystemClock.elapsedRealtime();
-
- if ((rightNow - lastRequest) > timeout) {
- results.clear();
- }
-
- lastRequest = rightNow;
-
- DatagramSocket socket = null;
- try {
- if (messageDigest == null) {
- messageDigest = MessageDigest.getInstance("SHA-512");
- }
-
- socket = new DatagramSocket();
- socket.setSoTimeout(timeout);
- final long startTime = SystemClock.elapsedRealtime();
- Message request = createRequestMessage();
- request.send(socket, address, port);
- final long endTime = SystemClock.elapsedRealtime();
- Message response = Message.receive(socket);
- byte[] signedData = response.get(Tag.SREP);
- Message signedResponse = Message.deserialize(signedData);
-
- final Result result = new Result();
- result.midpoint = signedResponse.getLong(Tag.MIDP);
- result.radius = signedResponse.getInt(Tag.RADI);
- result.collectionTime = (startTime + endTime) / 2;
-
- final byte[] root = signedResponse.get(Tag.ROOT);
- final byte[] path = response.get(Tag.PATH);
- final byte[] nonce = request.get(Tag.NONC);
- final int index = response.getInt(Tag.INDX);
-
- if (! verifyNonce(root, path, nonce, index)) {
- Log.w(TAG, "failed to authenticate roughtime response.");
- return false;
- }
-
- results.add(result);
- } catch (Exception e) {
- if (ENABLE_DEBUG) {
- Log.d(TAG, "request time failed", e);
- }
-
- return false;
- } finally {
- if (socket != null) {
- socket.close();
- }
- }
-
- return true;
- }
-
- /**
- * Verify that a reply message corresponds to the nonce sent in the request.
- *
- * @param root Root of the Merkle tree used to sign the nonce. Received in
- * the ROOT tag of the reply.
- * @param path Sibling hashes along the path to the root of the Merkle tree.
- * Received in the PATH tag of the reply.
- * @param nonce The nonce we sent in the request.
- * @param index Bitfield indicating whether chunks of the path are left or
- * right children.
- * @return true if the verification is successful.
- */
- private boolean verifyNonce(byte[] root, byte[] path, byte[] nonce,
- int index) {
- messageDigest.update(new byte[]{ 0 });
- byte[] hash = messageDigest.digest(nonce);
- int pos = 0;
- byte[] one = new byte[]{ 1 };
-
- while (pos < path.length) {
- messageDigest.update(one);
-
- if ((index&1) != 0) {
- messageDigest.update(path, pos, 64);
- hash = messageDigest.digest(hash);
- } else {
- messageDigest.update(hash);
- messageDigest.update(path, pos, 64);
- hash = messageDigest.digest();
- }
-
- pos += 64;
- index >>>= 1;
- }
-
- return Arrays.equals(root, hash);
- }
-}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 67378bd..7396189 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,6 +16,7 @@
package android.net;
+import android.content.Intent;
import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
@@ -2342,12 +2343,25 @@
* @hide
*/
public void checkFileUriExposed(String location) {
- if ("file".equals(getScheme()) && !getPath().startsWith("/system/")) {
+ if ("file".equals(getScheme())
+ && (getPath() != null) && !getPath().startsWith("/system/")) {
StrictMode.onFileUriExposed(this, location);
}
}
/**
+ * If this is a {@code content://} Uri without access flags, it will be
+ * reported to {@link StrictMode}.
+ *
+ * @hide
+ */
+ public void checkContentUriWithoutPermission(String location, int flags) {
+ if ("content".equals(getScheme()) && !Intent.isAccessUriMode(flags)) {
+ StrictMode.onContentUriWithoutPermission(this, location);
+ }
+ }
+
+ /**
* Test if this is a path prefix match against the given Uri. Verifies that
* scheme, authority, and atomic path segments match.
*
diff --git a/core/java/android/os/IProxyFileDescriptorCallback.java b/core/java/android/os/IProxyFileDescriptorCallback.java
new file mode 100644
index 0000000..e41e194
--- /dev/null
+++ b/core/java/android/os/IProxyFileDescriptorCallback.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.os;
+
+import android.system.ErrnoException;
+
+/**
+ * Callback that handles file system requests from ProxyFileDescriptor.
+ * @hide
+ */
+public interface IProxyFileDescriptorCallback {
+ /**
+ * Returns size of bytes provided by the file descriptor.
+ * @return Size of bytes
+ * @throws ErrnoException
+ */
+ long onGetSize() throws ErrnoException;
+
+ /**
+ * Provides bytes read from file descriptor.
+ * It needs to return exact requested size of bytes unless it reaches file end.
+ * @param offset Where to read bytes from.
+ * @param size Size for read bytes.
+ * @param data Byte array to store read bytes.
+ * @return Size of bytes returned by the function.
+ * @throws ErrnoException
+ */
+ int onRead(long offset, int size, byte[] data) throws ErrnoException;
+
+ /**
+ * Handles bytes written to file descriptor.
+ * @param offset Where to write bytes to.
+ * @param size Size for write bytes.
+ * @param data Byte array to be written to somewhere.
+ * @return Size of bytes processed by the function.
+ * @throws ErrnoException
+ */
+ int onWrite(long offset, int size, byte[] data) throws ErrnoException;
+
+ /**
+ * Processes fsync request.
+ * @throws ErrnoException
+ */
+ void onFsync() throws ErrnoException;
+}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 65c6093..9dafe29 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -86,4 +86,5 @@
UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle,
in String[] disallowedPackages);
boolean isUserUnlockingOrUnlocked(int userId);
+ int getManagedProfileBadge(int userId);
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index ef79b66..f2519be 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1800,6 +1800,13 @@
/**
* @hide
*/
+ public static boolean vmContentUriWithoutPermissionEnabled() {
+ return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
+ }
+
+ /**
+ * @hide
+ */
public static boolean vmCleartextNetworkEnabled() {
return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
}
@@ -1847,6 +1854,16 @@
/**
* @hide
*/
+ public static void onContentUriWithoutPermission(Uri uri, String location) {
+ final String message = uri + " exposed beyond app through " + location
+ + " without permission grant flags; did you forget"
+ + " FLAG_GRANT_READ_URI_PERMISSION?";
+ onVmPolicyViolation(null, new Throwable(message));
+ }
+
+ /**
+ * @hide
+ */
public static void onCleartextNetworkDetected(byte[] firstPacket) {
byte[] rawAddr = null;
if (firstPacket != null) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 50eb7cf..a79b0c4 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -948,6 +948,23 @@
}
/**
+ * Gets badge for a managed profile.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission, otherwise the caller
+ * must be in the same profile group of specified user.
+ *
+ * @return which badge to use for the managed profile badge id will be less than
+ * UserManagerService.getMaxManagedProfiles()
+ * @hide
+ */
+ public int getManagedProfileBadge(@UserIdInt int userId) {
+ try {
+ return mService.getManagedProfileBadge(userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks if the calling app is running as an ephemeral user.
*
* @return whether the caller is an ephemeral user.
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 98cbce6..27c0526 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -288,4 +288,5 @@
ParcelFileDescriptor mountAppFuse(in String name) = 69;
void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
-}
\ No newline at end of file
+ void fstrim(int flags) = 72;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0472e02..3fc7dba 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -134,6 +134,11 @@
/** {@hide} */
public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
+ /** {@hide} */
+ public static final int FSTRIM_FLAG_DEEP = 1 << 0;
+ /** {@hide} */
+ public static final int FSTRIM_FLAG_BENCHMARK = 1 << 1;
+
/** @hide The volume is not encrypted. */
public static final int ENCRYPTION_STATE_NONE = 1;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 2bfe33b..8303bca 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -21,6 +21,7 @@
import android.annotation.DrawableRes;
import android.annotation.LayoutRes;
+import android.annotation.Nullable;
import android.annotation.StringRes;
import android.content.Context;
import android.content.Intent;
@@ -88,9 +89,19 @@
public static final int DEFAULT_ORDER = Integer.MAX_VALUE;
private Context mContext;
+
+ @Nullable
private PreferenceManager mPreferenceManager;
/**
+ * The data store that should be used by this Preference to store / retrieve data. If null then
+ * {@link PreferenceManager#getPreferenceDataStore()} needs to be checked. If that one is null
+ * too it means that we are using {@link android.content.SharedPreferences} to store the data.
+ */
+ @Nullable
+ private PreferenceDataStore mPreferenceDataStore;
+
+ /**
* Set when added to hierarchy since we need a unique ID within that
* hierarchy.
*/
@@ -395,6 +406,36 @@
}
/**
+ * Sets a {@link PreferenceDataStore} to be used by this Preference instead of using
+ * {@link android.content.SharedPreferences}.
+ * <p>
+ * The data store will remain assigned even if the Preference is moved between multiple
+ * instances of {@link PreferenceFragment}.
+ *
+ * @param dataStore The {@link PreferenceDataStore} to be used by this Preference.
+ */
+ public void setPreferenceDataStore(PreferenceDataStore dataStore) {
+ mPreferenceDataStore = dataStore;
+ }
+
+ /**
+ * Returns {@link PreferenceDataStore} used by this Preference. Returns {@code null} if
+ * {@link android.content.SharedPreferences} is used instead.
+ *
+ * @return The {@link PreferenceDataStore} used by this Preference or {@code null} if none.
+ */
+ @Nullable
+ public PreferenceDataStore getPreferenceDataStore() {
+ if (mPreferenceDataStore != null) {
+ return mPreferenceDataStore;
+ } else if (mPreferenceManager != null) {
+ return mPreferenceManager.getPreferenceDataStore();
+ }
+
+ return null;
+ }
+
+ /**
* Return the extras Bundle object associated with this preference, creating
* a new Bundle if there currently isn't one. You can use this to get and
* set individual extra key/value pairs.
@@ -1426,44 +1467,42 @@
}
/**
- * Attempts to persist a String to the {@link android.content.SharedPreferences}.
- * <p>
- * This will check if this Preference is persistent, get an editor from
- * the {@link PreferenceManager}, put in the string, and check if we should commit (and
- * commit if so).
+ * Attempts to persist a String if this Preference is persistent.
*
* @param value The value to persist.
- * @return True if the Preference is persistent. (This is not whether the
+ * @return True if this Preference is persistent. (This is not whether the
* value was persisted, since we may not necessarily commit if there
* will be a batch commit later.)
* @see #getPersistedString(String)
*/
protected boolean persistString(String value) {
- if (shouldPersist()) {
- // Shouldn't store null
- if (TextUtils.equals(value, getPersistedString(null))) {
- // It's already there, so the same as persisting
- return true;
- }
+ if (!shouldPersist()) {
+ return false;
+ }
+ // Shouldn't store null
+ if (TextUtils.equals(value, getPersistedString(null))) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putString(mKey, value);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putString(mKey, value);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted String from the {@link android.content.SharedPreferences}.
- * <p>
- * This will check if this Preference is persistent, get the SharedPreferences
- * from the {@link PreferenceManager}, and get the value.
+ * Attempts to get a persisted String if this Preference is persistent.
*
- * @param defaultReturnValue The default value to return if either the
- * Preference is not persistent or the Preference is not in the
- * shared preferences.
- * @return The value from the SharedPreferences or the default return
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #persistString(String)
*/
@@ -1472,49 +1511,51 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getString(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getString(mKey, defaultReturnValue);
}
/**
- * Attempts to persist a set of Strings to the {@link android.content.SharedPreferences}.
- * <p>
- * This will check if this Preference is persistent, get an editor from
- * the {@link PreferenceManager}, put in the strings, and check if we should commit (and
- * commit if so).
+ * Attempts to persist a set of Strings if this Preference is persistent.
*
* @param values The values to persist.
- * @return True if the Preference is persistent. (This is not whether the
+ * @return True if this Preference is persistent. (This is not whether the
* value was persisted, since we may not necessarily commit if there
* will be a batch commit later.)
* @see #getPersistedStringSet(Set)
*/
- public boolean persistStringSet(Set<String> values) {
- if (shouldPersist()) {
- // Shouldn't store null
- if (values.equals(getPersistedStringSet(null))) {
- // It's already there, so the same as persisting
- return true;
- }
+ public boolean persistStringSet(Set<String> values) {
+ if (!shouldPersist()) {
+ return false;
+ }
+ // Shouldn't store null
+ if (values.equals(getPersistedStringSet(null))) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putStringSet(mKey, values);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putStringSet(mKey, values);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted set of Strings from the
- * {@link android.content.SharedPreferences}.
- * <p>
- * This will check if this Preference is persistent, get the SharedPreferences
- * from the {@link PreferenceManager}, and get the value.
+ * Attempts to get a persisted set of Strings if this Preference is persistent.
*
- * @param defaultReturnValue The default value to return if either the
- * Preference is not persistent or the Preference is not in the
- * shared preferences.
- * @return The value from the SharedPreferences or the default return
+ * @param defaultReturnValue The default value to return if either this
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #persistStringSet(Set)
*/
@@ -1523,41 +1564,51 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getStringSet(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getStringSet(mKey, defaultReturnValue);
}
/**
- * Attempts to persist an int to the {@link android.content.SharedPreferences}.
+ * Attempts to persist an int if this Preference is persistent.
*
* @param value The value to persist.
- * @return True if the Preference is persistent. (This is not whether the
+ * @return True if this Preference is persistent. (This is not whether the
* value was persisted, since we may not necessarily commit if there
* will be a batch commit later.)
* @see #persistString(String)
* @see #getPersistedInt(int)
*/
protected boolean persistInt(int value) {
- if (shouldPersist()) {
- if (value == getPersistedInt(~value)) {
- // It's already there, so the same as persisting
- return true;
- }
+ if (!shouldPersist()) {
+ return false;
+ }
+ if (value == getPersistedInt(~value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putInt(mKey, value);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putInt(mKey, value);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted int from the {@link android.content.SharedPreferences}.
+ * Attempts to get a persisted int if this Preference is persistent.
*
* @param defaultReturnValue The default value to return if either this
- * Preference is not persistent or this Preference is not in the
- * SharedPreferences.
- * @return The value from the SharedPreferences or the default return
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #getPersistedString(String)
* @see #persistInt(int)
@@ -1567,11 +1618,16 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getInt(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getInt(mKey, defaultReturnValue);
}
/**
- * Attempts to persist a float to the {@link android.content.SharedPreferences}.
+ * Attempts to persist a long if this Preference is persistent.
*
* @param value The value to persist.
* @return True if this Preference is persistent. (This is not whether the
@@ -1581,27 +1637,32 @@
* @see #getPersistedFloat(float)
*/
protected boolean persistFloat(float value) {
- if (shouldPersist()) {
- if (value == getPersistedFloat(Float.NaN)) {
- // It's already there, so the same as persisting
- return true;
- }
+ if (!shouldPersist()) {
+ return false;
+ }
+ if (value == getPersistedFloat(Float.NaN)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putFloat(mKey, value);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putFloat(mKey, value);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted float from the {@link android.content.SharedPreferences}.
+ * Attempts to get a persisted float if this Preference is persistent.
*
* @param defaultReturnValue The default value to return if either this
- * Preference is not persistent or this Preference is not in the
- * SharedPreferences.
- * @return The value from the SharedPreferences or the default return
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #getPersistedString(String)
* @see #persistFloat(float)
@@ -1611,11 +1672,16 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getFloat(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getFloat(mKey, defaultReturnValue);
}
/**
- * Attempts to persist a long to the {@link android.content.SharedPreferences}.
+ * Attempts to persist a long if this Preference is persistent.
*
* @param value The value to persist.
* @return True if this Preference is persistent. (This is not whether the
@@ -1625,27 +1691,32 @@
* @see #getPersistedLong(long)
*/
protected boolean persistLong(long value) {
- if (shouldPersist()) {
- if (value == getPersistedLong(~value)) {
- // It's already there, so the same as persisting
- return true;
- }
+ if (!shouldPersist()) {
+ return false;
+ }
+ if (value == getPersistedLong(~value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putLong(mKey, value);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putLong(mKey, value);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted long from the {@link android.content.SharedPreferences}.
+ * Attempts to get a persisted long if this Preference is persistent.
*
* @param defaultReturnValue The default value to return if either this
- * Preference is not persistent or this Preference is not in the
- * SharedPreferences.
- * @return The value from the SharedPreferences or the default return
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #getPersistedString(String)
* @see #persistLong(long)
@@ -1655,11 +1726,16 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getLong(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getLong(mKey, defaultReturnValue);
}
/**
- * Attempts to persist a boolean to the {@link android.content.SharedPreferences}.
+ * Attempts to persist a boolean if this Preference is persistent.
*
* @param value The value to persist.
* @return True if this Preference is persistent. (This is not whether the
@@ -1669,27 +1745,32 @@
* @see #getPersistedBoolean(boolean)
*/
protected boolean persistBoolean(boolean value) {
- if (shouldPersist()) {
- if (value == getPersistedBoolean(!value)) {
- // It's already there, so the same as persisting
- return true;
- }
+ if (!shouldPersist()) {
+ return false;
+ }
+ if (value == getPersistedBoolean(!value)) {
+ // It's already there, so the same as persisting
+ return true;
+ }
+
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ dataStore.putBoolean(mKey, value);
+ } else {
SharedPreferences.Editor editor = mPreferenceManager.getEditor();
editor.putBoolean(mKey, value);
tryCommit(editor);
- return true;
}
- return false;
+ return true;
}
/**
- * Attempts to get a persisted boolean from the {@link android.content.SharedPreferences}.
+ * Attempts to get a persisted boolean if this Preference is persistent.
*
* @param defaultReturnValue The default value to return if either this
- * Preference is not persistent or this Preference is not in the
- * SharedPreferences.
- * @return The value from the SharedPreferences or the default return
+ * Preference is not persistent or this Preference is not present.
+ * @return The value from the data store or the default return
* value.
* @see #getPersistedString(String)
* @see #persistBoolean(boolean)
@@ -1699,6 +1780,11 @@
return defaultReturnValue;
}
+ PreferenceDataStore dataStore = getPreferenceDataStore();
+ if (dataStore != null) {
+ return dataStore.getBoolean(mKey, defaultReturnValue);
+ }
+
return mPreferenceManager.getSharedPreferences().getBoolean(mKey, defaultReturnValue);
}
diff --git a/core/java/android/preference/PreferenceDataStore.java b/core/java/android/preference/PreferenceDataStore.java
new file mode 100644
index 0000000..e1a08ac
--- /dev/null
+++ b/core/java/android/preference/PreferenceDataStore.java
@@ -0,0 +1,164 @@
+/*
+ * 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 android.preference;
+
+import android.annotation.Nullable;
+
+import java.util.Set;
+
+/**
+ * A data store interface to be implemented and provided to the Preferences framework.
+ *
+ * Use this to replace the default {@link android.content.SharedPreferences}. By default, all "put"
+ * methods throw {@link UnsupportedOperationException}.
+ */
+public interface PreferenceDataStore {
+
+ /**
+ * Set a String value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #getString(String, String)
+ */
+ default void putString(String key, @Nullable String value) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Set a set of String value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param values The set of new values for the preference.
+ * @see #getStringSet(String, Set)
+ */
+ default void putStringSet(String key, @Nullable Set<String> values) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Set an int value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #getInt(String, int)
+ */
+ default void putInt(String key, int value) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Set a long value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #getLong(String, long)
+ */
+ default void putLong(String key, long value) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Set a float value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #getFloat(String, float)
+ */
+ default void putFloat(String key, float value) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Set a boolean value to the data store.
+ *
+ * @param key The name of the preference to modify.
+ * @param value The new value for the preference.
+ * @see #getBoolean(String, boolean)
+ */
+ default void putBoolean(String key, boolean value) {
+ throw new UnsupportedOperationException("Not implemented on this data store");
+ }
+
+ /**
+ * Retrieve a String value from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @see #putString(String, String)
+ */
+ @Nullable
+ default String getString(String key, @Nullable String defValue) {
+ return defValue;
+ }
+
+ /**
+ * Retrieve a set of String values from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValues Values to return if this preference does not exist.
+ * @see #putStringSet(String, Set)
+ */
+ @Nullable
+ default Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
+ return defValues;
+ }
+
+ /**
+ * Retrieve an int value from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @see #putInt(String, int)
+ */
+ default int getInt(String key, int defValue) {
+ return defValue;
+ }
+
+ /**
+ * Retrieve a long value from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @see #putLong(String, long)
+ */
+ default long getLong(String key, long defValue) {
+ return defValue;
+ }
+
+ /**
+ * Retrieve a float value from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @see #putFloat(String, float)
+ */
+ default float getFloat(String key, float defValue) {
+ return defValue;
+ }
+
+ /**
+ * Retrieve a boolean value from the data store.
+ *
+ * @param key The name of the preference to retrieve.
+ * @param defValue Value to return if this preference does not exist.
+ * @see #getBoolean(String, boolean)
+ */
+ default boolean getBoolean(String key, boolean defValue) {
+ return defValue;
+ }
+}
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 1a6b06f..a2f4db6 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.XmlRes;
import android.app.Activity;
@@ -42,37 +43,39 @@
* In most cases, clients should use
* {@link PreferenceActivity#addPreferencesFromIntent} or
* {@link PreferenceActivity#addPreferencesFromResource(int)}.
- *
+ *
* @see PreferenceActivity
*/
public class PreferenceManager {
-
+
private static final String TAG = "PreferenceManager";
/**
* The Activity meta-data key for its XML preference hierarchy.
*/
public static final String METADATA_KEY_PREFERENCES = "android.preference";
-
+
public static final String KEY_HAS_SET_DEFAULT_VALUES = "_has_set_default_values";
-
+
/**
* @see #getActivity()
*/
+ @Nullable
private Activity mActivity;
/**
* Fragment that owns this instance.
*/
+ @Nullable
private PreferenceFragment mFragment;
/**
* The context to use. This should always be set.
- *
+ *
* @see #mActivity
*/
private Context mContext;
-
+
/**
* The counter for unique IDs.
*/
@@ -86,26 +89,35 @@
/**
* Cached shared preferences.
*/
+ @Nullable
private SharedPreferences mSharedPreferences;
-
+
+ /**
+ * Data store to be used by the Preferences or null if {@link android.content.SharedPreferences}
+ * should be used.
+ */
+ @Nullable
+ private PreferenceDataStore mPreferenceDataStore;
+
/**
* If in no-commit mode, the shared editor to give out (which will be
* committed when exiting no-commit mode).
*/
+ @Nullable
private SharedPreferences.Editor mEditor;
-
+
/**
* Blocks commits from happening on the shared editor. This is used when
* inflating the hierarchy. Do not set this directly, use {@link #setNoCommit(boolean)}
*/
private boolean mNoCommit;
-
+
/**
* The SharedPreferences name that will be used for all {@link Preference}s
* managed by this instance.
*/
private String mSharedPreferencesName;
-
+
/**
* The SharedPreferences mode that will be used for all {@link Preference}s
* managed by this instance.
@@ -121,38 +133,43 @@
/**
* The {@link PreferenceScreen} at the root of the preference hierarchy.
*/
+ @Nullable
private PreferenceScreen mPreferenceScreen;
/**
* List of activity result listeners.
*/
+ @Nullable
private List<OnActivityResultListener> mActivityResultListeners;
/**
* List of activity stop listeners.
*/
+ @Nullable
private List<OnActivityStopListener> mActivityStopListeners;
/**
* List of activity destroy listeners.
*/
+ @Nullable
private List<OnActivityDestroyListener> mActivityDestroyListeners;
/**
* List of dialogs that should be dismissed when we receive onNewIntent in
* our PreferenceActivity.
*/
+ @Nullable
private List<DialogInterface> mPreferencesScreens;
-
+
private OnPreferenceTreeClickListener mOnPreferenceTreeClickListener;
-
+
/**
* @hide
*/
public PreferenceManager(Activity activity, int firstRequestCode) {
mActivity = activity;
mNextRequestCode = firstRequestCode;
-
+
init(activity);
}
@@ -170,7 +187,7 @@
private void init(Context context) {
mContext = context;
-
+
setSharedPreferencesName(getDefaultSharedPreferencesName(context));
}
@@ -184,14 +201,37 @@
/**
* Returns the owning preference fragment, if any.
*/
+ @Nullable
PreferenceFragment getFragment() {
return mFragment;
}
/**
+ * Sets a {@link PreferenceDataStore} to be used by all Preferences associated with this manager
+ * that don't have a custom {@link PreferenceDataStore} assigned. Also if the data store is set,
+ * the Preferences will no longer use {@link android.content.SharedPreferences}.
+ *
+ * @param dataStore The {@link PreferenceDataStore} to be used by this manager.
+ */
+ public void setPreferenceDataStore(PreferenceDataStore dataStore) {
+ mPreferenceDataStore = dataStore;
+ }
+
+ /**
+ * Returns the {@link PreferenceDataStore} associated with this manager or {@code null} if
+ * {@link android.content.SharedPreferences} are used instead.
+ *
+ * @return The {@link PreferenceDataStore} associated with this manager or {@code null} if none.
+ */
+ @Nullable
+ public PreferenceDataStore getPreferenceDataStore() {
+ return mPreferenceDataStore;
+ }
+
+ /**
* Returns a list of {@link Activity} (indirectly) that match a given
* {@link Intent}.
- *
+ *
* @param queryIntent The Intent to match.
* @return The list of {@link ResolveInfo} that point to the matched
* activities.
@@ -200,7 +240,7 @@
return mContext.getPackageManager().queryIntentActivities(queryIntent,
PackageManager.GET_META_DATA);
}
-
+
/**
* Inflates a preference hierarchy from the preference hierarchies of
* {@link Activity Activities} that match the given {@link Intent}. An
@@ -209,7 +249,7 @@
* <p>
* If a preference hierarchy is given, the new preference hierarchies will
* be merged in.
- *
+ *
* @param queryIntent The intent to match activities.
* @param rootPreferences Optional existing hierarchy to merge the new
* hierarchies into.
@@ -232,7 +272,7 @@
// can be re-used across contexts
final String uniqueResId = activityInfo.packageName + ":"
+ activityInfo.metaData.getInt(METADATA_KEY_PREFERENCES);
-
+
if (!inflatedRes.contains(uniqueResId)) {
inflatedRes.add(uniqueResId);
@@ -244,7 +284,7 @@
+ Log.getStackTraceString(e));
continue;
}
-
+
final PreferenceInflater inflater = new PreferenceInflater(context, this);
final XmlResourceParser parser = activityInfo.loadXmlMetaData(context
.getPackageManager(), METADATA_KEY_PREFERENCES);
@@ -255,14 +295,14 @@
}
rootPreferences.onAttachedToHierarchy(this);
-
+
return rootPreferences;
}
/**
* Inflates a preference hierarchy from XML. If a preference hierarchy is
* given, the new preference hierarchies will be merged in.
- *
+ *
* @param context The context of the resource.
* @param resId The resource ID of the XML to inflate.
* @param rootPreferences Optional existing hierarchy to merge the new
@@ -285,16 +325,16 @@
return rootPreferences;
}
-
+
public PreferenceScreen createPreferenceScreen(Context context) {
final PreferenceScreen preferenceScreen = new PreferenceScreen(context, null);
preferenceScreen.onAttachedToHierarchy(this);
return preferenceScreen;
}
-
+
/**
* Called by a preference to get a unique ID in its hierarchy.
- *
+ *
* @return A unique ID.
*/
long getNextId() {
@@ -302,11 +342,11 @@
return mNextId++;
}
}
-
+
/**
* Returns the current name of the SharedPreferences file that preferences managed by
* this will use.
- *
+ *
* @return The name that can be passed to {@link Context#getSharedPreferences(String, int)}.
* @see Context#getSharedPreferences(String, int)
*/
@@ -317,7 +357,7 @@
/**
* Sets the name of the SharedPreferences file that preferences managed by this
* will use.
- *
+ *
* @param sharedPreferencesName The name of the SharedPreferences file.
* @see Context#getSharedPreferences(String, int)
*/
@@ -329,7 +369,7 @@
/**
* Returns the current mode of the SharedPreferences file that preferences managed by
* this will use.
- *
+ *
* @return The mode that can be passed to {@link Context#getSharedPreferences(String, int)}.
* @see Context#getSharedPreferences(String, int)
*/
@@ -340,7 +380,7 @@
/**
* Sets the mode of the SharedPreferences file that preferences managed by this
* will use.
- *
+ *
* @param sharedPreferencesMode The mode of the SharedPreferences file.
* @see Context#getSharedPreferences(String, int)
*/
@@ -449,7 +489,7 @@
/**
* Gets a SharedPreferences instance that preferences managed by this will
* use.
- *
+ *
* @return A SharedPreferences instance pointing to the file that contains
* the values of preferences that are managed by this.
*/
@@ -471,14 +511,14 @@
mSharedPreferences = storageContext.getSharedPreferences(mSharedPreferencesName,
mSharedPreferencesMode);
}
-
+
return mSharedPreferences;
}
-
+
/**
* Gets a SharedPreferences instance that points to the default file that is
* used by the preference framework in the given context.
- *
+ *
* @param context The context of the preferences whose values are wanted.
* @return A SharedPreferences instance that can be used to retrieve and
* listen to values of the preferences.
@@ -504,49 +544,51 @@
/**
* Returns the root of the preference hierarchy managed by this class.
- *
+ *
* @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
*/
+ @Nullable
PreferenceScreen getPreferenceScreen() {
return mPreferenceScreen;
}
-
+
/**
* Sets the root of the preference hierarchy.
- *
+ *
* @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
- * @return Whether the {@link PreferenceScreen} given is different than the previous.
+ * @return Whether the {@link PreferenceScreen} given is different than the previous.
*/
boolean setPreferences(PreferenceScreen preferenceScreen) {
if (preferenceScreen != mPreferenceScreen) {
mPreferenceScreen = preferenceScreen;
return true;
}
-
+
return false;
}
-
+
/**
* Finds a {@link Preference} based on its key.
- *
+ *
* @param key The key of the preference to retrieve.
* @return The {@link Preference} with the key, or null.
* @see PreferenceGroup#findPreference(CharSequence)
*/
+ @Nullable
public Preference findPreference(CharSequence key) {
if (mPreferenceScreen == null) {
return null;
}
-
+
return mPreferenceScreen.findPreference(key);
}
-
+
/**
* Sets the default values from an XML preference file by reading the values defined
* by each {@link Preference} item's {@code android:defaultValue} attribute. This should
* be called by the application's main activity.
* <p>
- *
+ *
* @param context The context of the shared preferences.
* @param resId The resource ID of the preference XML file.
* @param readAgain Whether to re-read the default values.
@@ -563,12 +605,12 @@
* parameter set to true.
*/
public static void setDefaultValues(Context context, @XmlRes int resId, boolean readAgain) {
-
+
// Use the default shared preferences name and mode
setDefaultValues(context, getDefaultSharedPreferencesName(context),
getDefaultSharedPreferencesMode(), resId, readAgain);
}
-
+
/**
* Similar to {@link #setDefaultValues(Context, int, boolean)} but allows
* the client to provide the filename and mode of the shared preferences
@@ -592,7 +634,7 @@
* {@link PreferenceManager#getDefaultSharedPreferences(Context)}
* and clear it followed by a call to this method with this
* parameter set to true.
- *
+ *
* @see #setDefaultValues(Context, int, boolean)
* @see #setSharedPreferencesName(String)
* @see #setSharedPreferencesMode(int)
@@ -601,7 +643,7 @@
int sharedPreferencesMode, int resId, boolean readAgain) {
final SharedPreferences defaultValueSp = context.getSharedPreferences(
KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
-
+
if (readAgain || !defaultValueSp.getBoolean(KEY_HAS_SET_DEFAULT_VALUES, false)) {
final PreferenceManager pm = new PreferenceManager(context);
pm.setSharedPreferencesName(sharedPreferencesName);
@@ -620,33 +662,33 @@
}
}
}
-
+
/**
* Returns an editor to use when modifying the shared preferences.
* <p>
* Do NOT commit unless {@link #shouldCommit()} returns true.
- *
+ *
* @return An editor to use to write to shared preferences.
* @see #shouldCommit()
*/
SharedPreferences.Editor getEditor() {
-
+
if (mNoCommit) {
if (mEditor == null) {
mEditor = getSharedPreferences().edit();
}
-
+
return mEditor;
} else {
return getSharedPreferences().edit();
}
}
-
+
/**
* Whether it is the client's responsibility to commit on the
* {@link #getEditor()}. This will return false in cases where the writes
* should be batched, for example when inflating preferences from XML.
- *
+ *
* @return Whether the client should commit.
*/
boolean shouldCommit() {
@@ -674,18 +716,19 @@
* <p>
* This will return null if this class was instantiated with a Context
* instead of Activity. For example, when setting the default values.
- *
+ *
* @return The activity that shows the preferences.
* @see #mContext
*/
+ @Nullable
Activity getActivity() {
return mActivity;
}
-
+
/**
* Returns the context. This is preferred over {@link #getActivity()} when
* possible.
- *
+ *
* @return The context.
*/
Context getContext() {
@@ -694,7 +737,7 @@
/**
* Registers a listener.
- *
+ *
* @see OnActivityResultListener
*/
void registerOnActivityResultListener(OnActivityResultListener listener) {
@@ -702,7 +745,7 @@
if (mActivityResultListeners == null) {
mActivityResultListeners = new ArrayList<OnActivityResultListener>();
}
-
+
if (!mActivityResultListeners.contains(listener)) {
mActivityResultListeners.add(listener);
}
@@ -711,7 +754,7 @@
/**
* Unregisters a listener.
- *
+ *
* @see OnActivityResultListener
*/
void unregisterOnActivityResultListener(OnActivityResultListener listener) {
@@ -727,7 +770,7 @@
*/
void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
List<OnActivityResultListener> list;
-
+
synchronized (this) {
if (mActivityResultListeners == null) return;
list = new ArrayList<OnActivityResultListener>(mActivityResultListeners);
@@ -743,7 +786,7 @@
/**
* Registers a listener.
- *
+ *
* @see OnActivityStopListener
* @hide
*/
@@ -752,16 +795,16 @@
if (mActivityStopListeners == null) {
mActivityStopListeners = new ArrayList<OnActivityStopListener>();
}
-
+
if (!mActivityStopListeners.contains(listener)) {
mActivityStopListeners.add(listener);
}
}
}
-
+
/**
* Unregisters a listener.
- *
+ *
* @see OnActivityStopListener
* @hide
*/
@@ -772,14 +815,14 @@
}
}
}
-
+
/**
* Called by the {@link PreferenceManager} to dispatch the activity stop
* event.
*/
void dispatchActivityStop() {
List<OnActivityStopListener> list;
-
+
synchronized (this) {
if (mActivityStopListeners == null) return;
list = new ArrayList<OnActivityStopListener>(mActivityStopListeners);
@@ -793,7 +836,7 @@
/**
* Registers a listener.
- *
+ *
* @see OnActivityDestroyListener
*/
void registerOnActivityDestroyListener(OnActivityDestroyListener listener) {
@@ -807,10 +850,10 @@
}
}
}
-
+
/**
* Unregisters a listener.
- *
+ *
* @see OnActivityDestroyListener
*/
void unregisterOnActivityDestroyListener(OnActivityDestroyListener listener) {
@@ -820,14 +863,14 @@
}
}
}
-
+
/**
* Called by the {@link PreferenceManager} to dispatch the activity destroy
* event.
*/
void dispatchActivityDestroy() {
List<OnActivityDestroyListener> list = null;
-
+
synchronized (this) {
if (mActivityDestroyListeners != null) {
list = new ArrayList<OnActivityDestroyListener>(mActivityDestroyListeners);
@@ -844,11 +887,11 @@
// Dismiss any PreferenceScreens still showing
dismissAllScreens();
}
-
+
/**
* Returns a request code that is unique for the activity. Each subsequent
* call to this method should return another unique request code.
- *
+ *
* @return A unique request code that will never be used by anyone other
* than the caller of this method.
*/
@@ -857,32 +900,32 @@
return mNextRequestCode++;
}
}
-
+
void addPreferencesScreen(DialogInterface screen) {
synchronized (this) {
-
+
if (mPreferencesScreens == null) {
mPreferencesScreens = new ArrayList<DialogInterface>();
}
-
+
mPreferencesScreens.add(screen);
}
}
-
+
void removePreferencesScreen(DialogInterface screen) {
synchronized (this) {
-
+
if (mPreferencesScreens == null) {
return;
}
-
+
mPreferencesScreens.remove(screen);
}
}
-
+
/**
* Called by {@link PreferenceActivity} to dispatch the new Intent event.
- *
+ *
* @param intent The new Intent.
*/
void dispatchNewIntent(Intent intent) {
@@ -894,34 +937,35 @@
ArrayList<DialogInterface> screensToDismiss;
synchronized (this) {
-
+
if (mPreferencesScreens == null) {
return;
}
-
+
screensToDismiss = new ArrayList<DialogInterface>(mPreferencesScreens);
mPreferencesScreens.clear();
}
-
+
for (int i = screensToDismiss.size() - 1; i >= 0; i--) {
screensToDismiss.get(i).dismiss();
}
}
-
+
/**
* Sets the callback to be invoked when a {@link Preference} in the
* hierarchy rooted at this {@link PreferenceManager} is clicked.
- *
+ *
* @param listener The callback to be invoked.
*/
void setOnPreferenceTreeClickListener(OnPreferenceTreeClickListener listener) {
mOnPreferenceTreeClickListener = listener;
}
+ @Nullable
OnPreferenceTreeClickListener getOnPreferenceTreeClickListener() {
return mOnPreferenceTreeClickListener;
}
-
+
/**
* Interface definition for a callback to be invoked when a
* {@link Preference} in the hierarchy rooted at this {@link PreferenceScreen} is
@@ -933,7 +977,7 @@
/**
* Called when a preference in the tree rooted at this
* {@link PreferenceScreen} has been clicked.
- *
+ *
* @param preferenceScreen The {@link PreferenceScreen} that the
* preference is located in.
* @param preference The preference that was clicked.
@@ -947,22 +991,22 @@
* receives an activity result.
*/
public interface OnActivityResultListener {
-
+
/**
* See Activity's onActivityResult.
- *
+ *
* @return Whether the request code was handled (in which case
* subsequent listeners will not be called.
*/
boolean onActivityResult(int requestCode, int resultCode, Intent data);
}
-
+
/**
* Interface definition for a class that will be called when the container's activity
* is stopped.
*/
public interface OnActivityStopListener {
-
+
/**
* See Activity's onStop.
*/
@@ -974,7 +1018,7 @@
* is destroyed.
*/
public interface OnActivityDestroyListener {
-
+
/**
* See Activity's onDestroy.
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 02ab30a..37674a6 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -78,9 +78,7 @@
*/
public abstract class NotificationListenerService extends Service {
- // TAG = "NotificationListenerService[MySubclass]"
- private final String TAG = NotificationListenerService.class.getSimpleName()
- + "[" + getClass().getSimpleName() + "]";
+ private final String TAG = getClass().getSimpleName();
/**
* {@link #getCurrentInterruptionFilter() Interruption filter} constant -
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index dfb6b86..b0b2065 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -349,7 +349,8 @@
if (mContext == null) {
try {
ApplicationInfo ai = context.getPackageManager()
- .getApplicationInfo(pkg, PackageManager.GET_UNINSTALLED_PACKAGES);
+ .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ getUserId());
mContext = context.createApplicationContext(ai,
Context.CONTEXT_RESTRICTED);
} catch (PackageManager.NameNotFoundException e) {
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0f92ed0..cb021bc 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -68,6 +68,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface FlashLockState {}
+ /** @hide */
public PersistentDataBlockManager(IPersistentDataBlockService service) {
sService = service;
}
@@ -79,6 +80,9 @@
* Returns the number of bytes written or -1 on error. If the block is too big
* to fit on the partition, returns -MAX_BLOCK_SIZE.
*
+ * {@link #wipe} will block any further {@link #write} operation until reboot,
+ * in which case -1 will be returned.
+ *
* @param data the data to write
*/
public int write(byte[] data) {
@@ -129,6 +133,8 @@
/**
* Zeroes the previously written block in its entirety. Calling this method
* will erase all data written to the persistent data partition.
+ * It will also prevent any further {@link #write} operation until reboot,
+ * in order to prevent a potential race condition. See b/30352311.
*/
public void wipe() {
try {
diff --git a/core/java/android/view/GraphicBuffer.java b/core/java/android/view/GraphicBuffer.java
index 5f2a9cd..64611d0 100644
--- a/core/java/android/view/GraphicBuffer.java
+++ b/core/java/android/view/GraphicBuffer.java
@@ -16,6 +16,7 @@
package android.view;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -264,6 +265,16 @@
nWriteGraphicBufferToParcel(mNativeObject, dest);
}
+ /**
+ * Create hardware bitmap backed by this GraphicBuffer.
+ *
+ * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
+ * currently PIXEL_FORMAT_RGBA_8888 is the only supported format
+ */
+ public Bitmap createHardwareBitmap() {
+ return nCreateHardwareBitmap(mNativeObject);
+ }
+
public static final Parcelable.Creator<GraphicBuffer> CREATOR =
new Parcelable.Creator<GraphicBuffer>() {
public GraphicBuffer createFromParcel(Parcel in) {
@@ -289,4 +300,5 @@
private static native long nReadGraphicBufferFromParcel(Parcel in);
private static native boolean nLockCanvas(long nativeObject, Canvas canvas, Rect dirty);
private static native boolean nUnlockCanvasAndPost(long nativeObject, Canvas canvas);
+ private static native Bitmap nCreateHardwareBitmap(long nativeObject);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index bccb822..bd1ad8e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -20,6 +20,7 @@
import com.android.internal.os.IResultReceiver;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import android.content.res.CompatibilityInfo;
@@ -210,8 +211,7 @@
boolean isKeyguardLocked();
boolean isKeyguardSecure();
boolean inKeyguardRestrictedInputMode();
- void dismissKeyguard();
- void keyguardGoingAway(int flags);
+ void dismissKeyguard(IKeyguardDismissCallback callback);
// Requires INTERACT_ACROSS_USERS_FULL permission
void setSwitchingUser(boolean switching);
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index c46acae..0da710a 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -28,6 +28,8 @@
import android.widget.ImageView;
import android.widget.RemoteViews;
+import com.android.internal.widget.CachingIconView;
+
import java.util.ArrayList;
/**
@@ -45,7 +47,7 @@
private OnClickListener mExpandClickListener;
private HeaderTouchListener mTouchListener = new HeaderTouchListener();
private ImageView mExpandButton;
- private View mIcon;
+ private CachingIconView mIcon;
private View mProfileBadge;
private View mInfo;
private int mIconColor;
@@ -123,7 +125,7 @@
if (mExpandButton != null) {
mExpandButton.setAccessibilityDelegate(mExpandDelegate);
}
- mIcon = findViewById(com.android.internal.R.id.icon);
+ mIcon = (CachingIconView) findViewById(com.android.internal.R.id.icon);
mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
}
@@ -311,6 +313,10 @@
return mProfileBadge;
}
+ public CachingIconView getIcon() {
+ return mIcon;
+ }
+
public class HeaderTouchListener implements View.OnTouchListener {
private final ArrayList<Rect> mTouchRects = new ArrayList<>();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 84d7548..f9a03c0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4194,6 +4194,8 @@
int endPadding = UNDEFINED_PADDING;
int padding = -1;
+ int paddingHorizontal = -1;
+ int paddingVertical = -1;
int viewFlagValues = 0;
int viewFlagMasks = 0;
@@ -4240,6 +4242,16 @@
leftPaddingDefined = true;
rightPaddingDefined = true;
break;
+ case com.android.internal.R.styleable.View_paddingHorizontal:
+ paddingHorizontal = a.getDimensionPixelSize(attr, -1);
+ mUserPaddingLeftInitial = paddingHorizontal;
+ mUserPaddingRightInitial = paddingHorizontal;
+ leftPaddingDefined = true;
+ rightPaddingDefined = true;
+ break;
+ case com.android.internal.R.styleable.View_paddingVertical:
+ paddingVertical = a.getDimensionPixelSize(attr, -1);
+ break;
case com.android.internal.R.styleable.View_paddingLeft:
leftPadding = a.getDimensionPixelSize(attr, -1);
mUserPaddingLeftInitial = leftPadding;
@@ -4647,6 +4659,17 @@
bottomPadding = padding;
mUserPaddingLeftInitial = padding;
mUserPaddingRightInitial = padding;
+ } else {
+ if (paddingHorizontal >= 0) {
+ leftPadding = paddingHorizontal;
+ rightPadding = paddingHorizontal;
+ mUserPaddingLeftInitial = paddingHorizontal;
+ mUserPaddingRightInitial = paddingHorizontal;
+ }
+ if (paddingVertical >= 0) {
+ topPadding = paddingVertical;
+ bottomPadding = paddingVertical;
+ }
}
if (isRtlCompatibilityMode()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c0191ce..0f8200d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7357,34 +7357,48 @@
rightMargin= margin;
bottomMargin = margin;
} else {
- leftMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
- UNDEFINED_MARGIN);
- if (leftMargin == UNDEFINED_MARGIN) {
- mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
- leftMargin = DEFAULT_MARGIN_RESOLVED;
- }
- rightMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginRight,
- UNDEFINED_MARGIN);
- if (rightMargin == UNDEFINED_MARGIN) {
- mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
- rightMargin = DEFAULT_MARGIN_RESOLVED;
+ int horizontalMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
+ int verticalMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
+
+ if (horizontalMargin >= 0) {
+ leftMargin = horizontalMargin;
+ rightMargin = horizontalMargin;
+ } else {
+ leftMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
+ UNDEFINED_MARGIN);
+ if (leftMargin == UNDEFINED_MARGIN) {
+ mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
+ leftMargin = DEFAULT_MARGIN_RESOLVED;
+ }
+ rightMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginRight,
+ UNDEFINED_MARGIN);
+ if (rightMargin == UNDEFINED_MARGIN) {
+ mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
+ rightMargin = DEFAULT_MARGIN_RESOLVED;
+ }
+ startMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginStart,
+ DEFAULT_MARGIN_RELATIVE);
+ endMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
+ DEFAULT_MARGIN_RELATIVE);
}
- topMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginTop,
- DEFAULT_MARGIN_RESOLVED);
- bottomMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
- DEFAULT_MARGIN_RESOLVED);
-
- startMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginStart,
- DEFAULT_MARGIN_RELATIVE);
- endMargin = a.getDimensionPixelSize(
- R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
- DEFAULT_MARGIN_RELATIVE);
+ if (verticalMargin >= 0) {
+ topMargin = verticalMargin;
+ bottomMargin = verticalMargin;
+ } else {
+ topMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginTop,
+ DEFAULT_MARGIN_RESOLVED);
+ bottomMargin = a.getDimensionPixelSize(
+ R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
+ DEFAULT_MARGIN_RESOLVED);
+ }
if (isMarginRelative()) {
mMarginFlags |= NEED_RESOLUTION_MASK;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2971280..b8408dd 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.app.KeyguardManager;
import android.app.Presentation;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -911,16 +912,17 @@
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
/** Window flag: when set the window will cause the keyguard to
- * be dismissed, only if it is not a secure lock keyguard. Because such
+ * be dismissed, only if it is not a secure lock keyguard. Because such
* a keyguard is not needed for security, it will never re-appear if
* the user navigates to another window (in contrast to
* {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
* hide both secure and non-secure keyguards but ensure they reappear
* when the user moves to another UI that doesn't hide them).
* If the keyguard is currently active and is secure (requires an
- * unlock pattern) than the user will still need to confirm it before
+ * unlock credential) than the user will still need to confirm it before
* seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
* also been set.
+ * @see KeyguardManager#dismissKeyguard
*/
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 82379c4..2f55fc9 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityManager.StackId;
import android.content.Context;
@@ -31,6 +32,7 @@
import android.os.RemoteException;
import android.view.animation.Animation;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import java.io.PrintWriter;
@@ -480,6 +482,16 @@
*/
public void switchInputMethod(boolean forwardDirection);
+ /**
+ * Returns the visibility of the current input method window (false if there is none).
+ */
+ public boolean isInputMethodWindowVisible();
+
+ /**
+ * Hides the current input method, if visible.
+ */
+ public void hideCurrentInputMethod();
+
public void shutdown(boolean confirm);
public void reboot(boolean confirm);
public void rebootSafeMode(boolean confirm);
@@ -1162,8 +1174,10 @@
/**
* Ask the policy to dismiss the keyguard, if it is currently shown.
+ *
+ * @param callback Callback to be informed about the result.
*/
- public void dismissKeyguardLw();
+ public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback);
/**
* Ask the policy whether the Keyguard has drawn. If the Keyguard is disabled, this method
diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java
index eec5555..924437a 100644
--- a/core/java/android/view/animation/PathInterpolator.java
+++ b/core/java/android/view/animation/PathInterpolator.java
@@ -25,6 +25,9 @@
import android.view.InflateException;
import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
/**
* An interpolator that can traverse a Path that extends from <code>Point</code>
@@ -42,7 +45,8 @@
* path.lineTo(1f, 1f);
* </pre></blockquote></p>
*/
-public class PathInterpolator extends BaseInterpolator {
+@HasNativeInterpolator
+public class PathInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
// This governs how accurate the approximation of the Path is.
private static final float PRECISION = 0.002f;
@@ -229,4 +233,11 @@
float endY = mY[endIndex];
return startY + (fraction * (endY - startY));
}
+
+ /** @hide **/
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createPathInterpolator(mX, mY);
+ }
+
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index d5a933c..8cedb17 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2168,7 +2168,6 @@
}
layoutChildren();
- mInLayout = false;
mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
@@ -2176,6 +2175,7 @@
if (mFastScroll != null) {
mFastScroll.onItemCountChanged(getChildCount(), mItemCount);
}
+ mInLayout = false;
}
/**
@@ -2705,6 +2705,9 @@
* fail to relayout them properly to accommodate for new bounds.
*/
void handleBoundsChange() {
+ if (mInLayout) {
+ return;
+ }
final int childCount = getChildCount();
if (childCount > 0) {
mDataChanged = true;
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index a3134b3b..98d87d3 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -355,7 +355,7 @@
ApplicationInfo existingInfo = null;
try {
existingInfo = context.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
} catch (NameNotFoundException ignored) {
}
@@ -445,7 +445,7 @@
ApplicationInfo existingInfo = null;
try {
existingInfo = context.getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
} catch (NameNotFoundException ignored) {
}
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
new file mode 100644
index 0000000..34253ce
--- /dev/null
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -0,0 +1,222 @@
+/*
+ * 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.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IProxyFileDescriptorCallback;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.util.Log;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public class FuseAppLoop {
+ private static final String TAG = "FuseAppLoop";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ public static final int ROOT_INODE = 1;
+ private static final int MIN_INODE = 2;
+
+ private final Object mLock = new Object();
+ private final File mParent;
+
+ @GuardedBy("mLock")
+ private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
+
+ @GuardedBy("mLock")
+ private boolean mActive = true;
+
+ /**
+ * Sequential number can be used as file name and inode in AppFuse.
+ * 0 is regarded as an error, 1 is mount point. So we start the number from 2.
+ */
+ @GuardedBy("mLock")
+ private int mNextInode = MIN_INODE;
+
+ private FuseAppLoop(@NonNull File parent) {
+ mParent = parent;
+ }
+
+ public static @NonNull FuseAppLoop open(
+ @NonNull File parent, @NonNull ParcelFileDescriptor fd) {
+ Preconditions.checkNotNull(parent);
+ Preconditions.checkNotNull(fd);
+ final FuseAppLoop bridge = new FuseAppLoop(parent);
+ final int rawFd = fd.detachFd();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ bridge.native_start_loop(rawFd);
+ }
+ }, TAG).start();
+ return bridge;
+ }
+
+ public @NonNull ParcelFileDescriptor openFile(int mode, IProxyFileDescriptorCallback callback)
+ throws UnmountedException, IOException {
+ int id;
+ synchronized (mLock) {
+ if (!mActive) {
+ throw new UnmountedException();
+ }
+ if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) {
+ throw new IOException("Too many opened files.");
+ }
+ while (true) {
+ id = mNextInode;
+ mNextInode++;
+ if (mNextInode < 0) {
+ mNextInode = MIN_INODE;
+ }
+ if (mCallbackMap.get(id) == null) {
+ break;
+ }
+ }
+
+ // Register callback after we succeed to create pfd.
+ mCallbackMap.put(id, new CallbackEntry(callback));
+ }
+ try {
+ return ParcelFileDescriptor.open(new File(mParent, String.valueOf(id)), mode);
+ } catch (FileNotFoundException error) {
+ synchronized (mLock) {
+ mCallbackMap.remove(id);
+ }
+ throw error;
+ }
+ }
+
+ public @Nullable File getMountPoint() {
+ synchronized (mLock) {
+ return mActive ? mParent : null;
+ }
+ }
+
+ private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
+ final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
+ if (entry != null) {
+ return entry;
+ } else {
+ throw new ErrnoException("getCallbackEntry", OsConstants.ENOENT);
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private long onGetSize(long inode) {
+ synchronized(mLock) {
+ try {
+ return getCallbackEntryOrThrowLocked(inode).callback.onGetSize();
+ } catch (ErrnoException exp) {
+ return -exp.errno;
+ }
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private int onOpen(long inode) {
+ synchronized(mLock) {
+ try {
+ final CallbackEntry entry = getCallbackEntryOrThrowLocked(inode);
+ if (entry.opened) {
+ throw new ErrnoException("onOpen", OsConstants.EMFILE);
+ }
+ entry.opened = true;
+ // Use inode as file handle. It's OK because AppFuse does not allow to open the same
+ // file twice.
+ return (int) inode;
+ } catch (ErrnoException exp) {
+ return -exp.errno;
+ }
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private int onFsync(long inode) {
+ synchronized(mLock) {
+ try {
+ getCallbackEntryOrThrowLocked(inode).callback.onFsync();
+ return 0;
+ } catch (ErrnoException exp) {
+ return -exp.errno;
+ }
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private int onRelease(long inode) {
+ synchronized(mLock) {
+ mCallbackMap.remove(checkInode(inode));
+ if (mCallbackMap.size() == 0) {
+ mActive = false;
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private int onRead(long inode, long offset, int size, byte[] bytes) {
+ synchronized(mLock) {
+ try {
+ return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes);
+ } catch (ErrnoException exp) {
+ return -exp.errno;
+ }
+ }
+ }
+
+ // Called by JNI.
+ @SuppressWarnings("unused")
+ private int onWrite(long inode, long offset, int size, byte[] bytes) {
+ synchronized(mLock) {
+ try {
+ return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes);
+ } catch (ErrnoException exp) {
+ return -exp.errno;
+ }
+ }
+ }
+
+ native boolean native_start_loop(int fd);
+
+ private static int checkInode(long inode) {
+ Preconditions.checkArgumentInRange(inode, MIN_INODE, Integer.MAX_VALUE, "checkInode");
+ return (int) inode;
+ }
+
+ public static class UnmountedException extends Exception {}
+
+ private static class CallbackEntry {
+ final IProxyFileDescriptorCallback callback;
+ boolean opened;
+ CallbackEntry(IProxyFileDescriptorCallback callback) {
+ Preconditions.checkNotNull(callback);
+ this.callback = callback;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 7591488..1d26df0 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -27,8 +27,8 @@
SystemProperties.getInt("ro.debuggable", 0) == 1;
public static final int FACTORYTEST =
SystemProperties.getInt("ro.factorytest", 0);
- public static final boolean CONTROL_PRIVAPP_PERMISSIONS =
- SystemProperties.getBoolean("ro.control_privapp_permissions", false);
+ public static final String CONTROL_PRIVAPP_PERMISSIONS =
+ SystemProperties.get("ro.control_privapp_permissions");
// ------ ro.config.* -------- //
public static final boolean CONFIG_LOW_RAM =
@@ -50,4 +50,12 @@
"file".equalsIgnoreCase(CRYPTO_TYPE);
public static final boolean CRYPTO_BLOCK_ENCRYPTED =
"block".equalsIgnoreCase(CRYPTO_TYPE);
+
+ public static final boolean CONTROL_PRIVAPP_PERMISSIONS_LOG =
+ "log".equalsIgnoreCase(CONTROL_PRIVAPP_PERMISSIONS);
+ public static final boolean CONTROL_PRIVAPP_PERMISSIONS_ENFORCE =
+ "enforce".equalsIgnoreCase(CONTROL_PRIVAPP_PERMISSIONS);
+ public static final boolean CONTROL_PRIVAPP_PERMISSIONS_DISABLE =
+ !CONTROL_PRIVAPP_PERMISSIONS_LOG && !CONTROL_PRIVAPP_PERMISSIONS_ENFORCE;
+
}
diff --git a/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
new file mode 100644
index 0000000..635c504
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.policy;
+
+oneway interface IKeyguardDismissCallback {
+ void onDismissError();
+ void onDismissSucceeded();
+ void onDismissCancelled();
+}
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 788103d..a019ea1 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -16,6 +16,7 @@
package com.android.internal.policy;
import com.android.internal.policy.IKeyguardDrawnCallback;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -34,7 +35,7 @@
void addStateMonitorCallback(IKeyguardStateCallback callback);
void verifyUnlock(IKeyguardExitCallback callback);
- void dismiss(boolean allowWhileOccluded);
+ void dismiss(IKeyguardDismissCallback callback);
void onDreamingStarted();
void onDreamingStopped();
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index b0d45e1d1..be10608df 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -1190,6 +1190,26 @@
}
/**
+ * Remove a state from the state machine. Will not remove the state if it is currently
+ * active or if it has any children in the hierarchy.
+ * @param state the state to remove
+ */
+ private void removeState(State state) {
+ StateInfo stateInfo = mStateInfo.get(state);
+ if (stateInfo == null || stateInfo.active) {
+ return;
+ }
+ boolean isParent = mStateInfo.values().stream()
+ .filter(si -> si.parentStateInfo == stateInfo)
+ .findAny()
+ .isPresent();
+ if (isParent) {
+ return;
+ }
+ mStateInfo.remove(state);
+ }
+
+ /**
* Constructor
*
* @param looper for dispatching messages
@@ -1337,6 +1357,14 @@
}
/**
+ * Removes a state from the state machine, unless it is currently active or if it has children.
+ * @param state state to remove
+ */
+ public final void removeState(State state) {
+ mSmHandler.removeState(state);
+ }
+
+ /**
* Set the initial state. This must be invoked before
* and messages are sent to the state machine.
*
diff --git a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
index 7cd75f3..ebeec40 100644
--- a/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
+++ b/core/java/com/android/internal/view/animation/NativeInterpolatorFactoryHelper.java
@@ -32,5 +32,6 @@
public static native long createDecelerateInterpolator(float factor);
public static native long createLinearInterpolator();
public static native long createOvershootInterpolator(float tension);
+ public static native long createPathInterpolator(float[] x, float[] y);
public static native long createLutInterpolator(float[] values);
}
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 293b77b..20230cd 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -41,6 +41,8 @@
private String mLastPackage;
private int mLastResId;
private boolean mInternalSetDrawable;
+ private boolean mForceHidden;
+ private int mDesiredVisibility;
public CachingIconView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -175,4 +177,24 @@
mLastResId = 0;
mLastPackage = null;
}
+
+ /**
+ * Set the icon to be forcibly hidden, even when it's visibility is changed to visible.
+ */
+ public void setForceHidden(boolean forceHidden) {
+ mForceHidden = forceHidden;
+ updateVisibility();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mDesiredVisibility = visibility;
+ updateVisibility();
+ }
+
+ private void updateVisibility() {
+ int visibility = mDesiredVisibility == VISIBLE && mForceHidden ? INVISIBLE
+ : mDesiredVisibility;
+ super.setVisibility(visibility);
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index b0bc81b..63b700b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1432,7 +1432,8 @@
STRONG_AUTH_REQUIRED_AFTER_BOOT,
STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
SOME_AUTH_REQUIRED_AFTER_USER_REQUEST,
- STRONG_AUTH_REQUIRED_AFTER_LOCKOUT})
+ STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ STRONG_AUTH_REQUIRED_AFTER_TIMEOUT})
@Retention(RetentionPolicy.SOURCE)
public @interface StrongAuthFlags {}
@@ -1463,6 +1464,12 @@
public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
/**
+ * Strong authentication is required because it hasn't been used for a time required by
+ * a device admin.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_TIMEOUT = 0x10;
+
+ /**
* Strong auth flags that do not prevent fingerprint from being accepted as auth.
*
* If any other flags are set, fingerprint is disabled.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index a4e9576..77934fe 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -183,6 +183,7 @@
android_content_res_Configuration.cpp \
android_animation_PropertyValuesHolder.cpp \
com_android_internal_net_NetworkStatsFactory.cpp \
+ com_android_internal_os_FuseAppLoop.cpp \
com_android_internal_os_PathClassLoaderFactory.cpp \
com_android_internal_os_Zygote.cpp \
com_android_internal_util_VirtualRefBasePtr.cpp \
@@ -201,6 +202,7 @@
$(TOP)/frameworks/base/media/jni \
$(TOP)/system/core/base/include \
$(TOP)/system/core/include \
+ $(TOP)/system/core/libappfuse/include \
$(TOP)/system/media/camera/include \
$(TOP)/system/netd/include \
external/giflib \
@@ -215,7 +217,6 @@
external/skia/src/images \
external/sqlite/dist \
external/sqlite/android \
- external/expat/lib \
external/tremor/Tremor \
external/harfbuzz_ng/src \
libcore/include \
@@ -230,18 +231,16 @@
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
libandroidfw \
+ libappfuse \
libbase \
- libexpat \
libnativehelper \
liblog \
libcutils \
libutils \
libbinder \
- libnetutils \
libui \
libgui \
libinput \
- libinputflinger \
libcamera_client \
libcamera_metadata \
libskia \
@@ -254,18 +253,13 @@
libhardware \
libhardware_legacy \
libselinux \
- libsonivox \
- libcrypto \
- libssl \
libicuuc \
- libicui18n \
libmedia \
libaudioclient \
libjpeg \
libusbhost \
libharfbuzz_ng \
libz \
- libaudioutils \
libpdfium \
libimg_utils \
libnetd_client \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cdaa4dc..1f810ac 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -201,6 +201,7 @@
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
+extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_PathClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
@@ -1419,7 +1420,7 @@
REG_JNI(register_android_animation_PropertyValuesHolder),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
-
+ REG_JNI(register_com_android_internal_os_FuseAppLoop),
};
/*
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index ac3bf7a..b5c0b64 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -3084,15 +3084,16 @@
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (!infoLen) {
- return _env->NewStringUTF("");
+ infoLen = 512;
}
char* buf = (char*) malloc(infoLen);
if (buf == NULL) {
jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
return NULL;
}
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
- jstring result = _env->NewStringUTF(buf);
+ GLsizei outLen = 0;
+ glGetShaderInfoLog(shader, infoLen, &outLen, buf);
+ jstring result = _env->NewStringUTF(outLen == 0 ? "" : buf);
free(buf);
return result;
}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 173afd8..3219d59 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -16,16 +16,14 @@
#include <fcntl.h>
+#include <log/log_event_list.h>
+
#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include "jni.h"
-#include <log/logger.h>
#define UNUSED __attribute__((__unused__))
-// The size of the tag number comes out of the payload size.
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
namespace android {
static jclass gCollectionClass;
@@ -53,7 +51,9 @@
jobject clazz UNUSED,
jint tag, jint value)
{
- return android_btWriteLog(tag, EVENT_TYPE_INT, &value, sizeof(value));
+ android_log_event_list ctx(tag);
+ ctx << (int32_t)value;
+ return ctx.write();
}
/*
@@ -64,7 +64,9 @@
jobject clazz UNUSED,
jint tag, jlong value)
{
- return android_btWriteLog(tag, EVENT_TYPE_LONG, &value, sizeof(value));
+ android_log_event_list ctx(tag);
+ ctx << (int64_t)value;
+ return ctx.write();
}
/*
@@ -75,7 +77,9 @@
jobject clazz UNUSED,
jint tag, jfloat value)
{
- return android_btWriteLog(tag, EVENT_TYPE_FLOAT, &value, sizeof(value));
+ android_log_event_list ctx(tag);
+ ctx << (float)value;
+ return ctx.write();
}
/*
@@ -85,22 +89,17 @@
static jint android_util_EventLog_writeEvent_String(JNIEnv* env,
jobject clazz UNUSED,
jint tag, jstring value) {
- uint8_t buf[MAX_EVENT_PAYLOAD];
-
+ android_log_event_list ctx(tag);
// Don't throw NPE -- I feel like it's sort of mean for a logging function
// to be all crashy if you pass in NULL -- but make the NULL value explicit.
- const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
- uint32_t len = strlen(str);
- size_t max = sizeof(buf) - sizeof(len) - 2; // Type byte, final newline
- if (len > max) len = max;
-
- buf[0] = EVENT_TYPE_STRING;
- memcpy(&buf[1], &len, sizeof(len));
- memcpy(&buf[1 + sizeof(len)], str, len);
- buf[1 + sizeof(len) + len] = '\n';
-
- if (value != NULL) env->ReleaseStringUTFChars(value, str);
- return android_bWriteLog(tag, buf, 2 + sizeof(len) + len);
+ if (value != NULL) {
+ const char *str = env->GetStringUTFChars(value, NULL);
+ ctx << str;
+ env->ReleaseStringUTFChars(value, str);
+ } else {
+ ctx << "NULL";
+ }
+ return ctx.write();
}
/*
@@ -109,45 +108,29 @@
*/
static jint android_util_EventLog_writeEvent_Array(JNIEnv* env, jobject clazz,
jint tag, jobjectArray value) {
- if (value == NULL) {
- return android_util_EventLog_writeEvent_String(env, clazz, tag, NULL);
- }
+ android_log_event_list ctx(tag);
- uint8_t buf[MAX_EVENT_PAYLOAD];
- const size_t max = sizeof(buf) - 1; // leave room for final newline
- size_t pos = 2; // Save room for type tag & array count
+ if (value == NULL) {
+ ctx << "[NULL]";
+ return ctx.write();
+ }
jsize copied = 0, num = env->GetArrayLength(value);
for (; copied < num && copied < 255; ++copied) {
+ if (ctx.status()) break;
jobject item = env->GetObjectArrayElement(value, copied);
- if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
- if (pos + 1 + sizeof(jint) > max) break;
- const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
- jint len = strlen(str);
- if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
- buf[pos++] = EVENT_TYPE_STRING;
- memcpy(&buf[pos], &len, sizeof(len));
- memcpy(&buf[pos + sizeof(len)], str, len);
- pos += sizeof(len) + len;
- if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+ if (item == NULL) {
+ ctx << "NULL";
+ } else if (env->IsInstanceOf(item, gStringClass)) {
+ const char *str = env->GetStringUTFChars((jstring) item, NULL);
+ ctx << str;
+ env->ReleaseStringUTFChars((jstring) item, str);
} else if (env->IsInstanceOf(item, gIntegerClass)) {
- jint intVal = env->GetIntField(item, gIntegerValueID);
- if (pos + 1 + sizeof(intVal) > max) break;
- buf[pos++] = EVENT_TYPE_INT;
- memcpy(&buf[pos], &intVal, sizeof(intVal));
- pos += sizeof(intVal);
+ ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
} else if (env->IsInstanceOf(item, gLongClass)) {
- jlong longVal = env->GetLongField(item, gLongValueID);
- if (pos + 1 + sizeof(longVal) > max) break;
- buf[pos++] = EVENT_TYPE_LONG;
- memcpy(&buf[pos], &longVal, sizeof(longVal));
- pos += sizeof(longVal);
+ ctx << (int64_t)env->GetLongField(item, gLongValueID);
} else if (env->IsInstanceOf(item, gFloatClass)) {
- jfloat floatVal = env->GetFloatField(item, gFloatValueID);
- if (pos + 1 + sizeof(floatVal) > max) break;
- buf[pos++] = EVENT_TYPE_FLOAT;
- memcpy(&buf[pos], &floatVal, sizeof(floatVal));
- pos += sizeof(floatVal);
+ ctx << (float)env->GetFloatField(item, gFloatValueID);
} else {
jniThrowException(env,
"java/lang/IllegalArgumentException",
@@ -156,11 +139,7 @@
}
env->DeleteLocalRef(item);
}
-
- buf[0] = EVENT_TYPE_LIST;
- buf[1] = copied;
- buf[pos++] = '\n';
- return android_bWriteLog(tag, buf, pos);
+ return ctx.write();
}
/*
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index b9376d8..4b105ca 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -22,6 +22,7 @@
#include "android_os_Parcel.h"
#include "android_view_GraphicBuffer.h"
#include "android/graphics/GraphicsJNI.h"
+#include "Bitmap.h"
#include <android_runtime/AndroidRuntime.h>
@@ -32,6 +33,7 @@
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
+#include <hwui/Bitmap.h>
#include <SkCanvas.h>
#include <SkBitmap.h>
@@ -247,6 +249,17 @@
return NULL;
}
+static jobject android_view_GraphicBuffer_createHardwareBitmap(JNIEnv* env, jobject,
+ jlong wrapperHandle) {
+ GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
+ sk_sp<Bitmap> bitmap = Bitmap::createFrom(wrapper->buffer);
+ if (!bitmap.get()) {
+ ALOGW("failed to create hardware bitmap from graphic buffer");
+ return NULL;
+ }
+ return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+}
+
// ----------------------------------------------------------------------------
// External helpers
// ----------------------------------------------------------------------------
@@ -282,6 +295,9 @@
(void*) android_view_GraphicBuffer_lockCanvas },
{ "nUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)Z",
(void*) android_view_GraphicBuffer_unlockCanvasAndPost },
+ { "nCreateHardwareBitmap", "(J)Landroid/graphics/Bitmap;",
+ (void*) android_view_GraphicBuffer_createHardwareBitmap
+ }
};
int register_android_view_GraphicBuffer(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp
new file mode 100644
index 0000000..92a6934
--- /dev/null
+++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FuseAppLoopJNI"
+#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <android_runtime/Log.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <jni.h>
+#include <libappfuse/FuseAppLoop.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+namespace {
+
+constexpr const char* CLASS_NAME = "com/android/internal/os/FuseAppLoop";
+
+jclass gFuseAppLoopClass;
+jmethodID gOnGetSizeMethod;
+jmethodID gOnOpenMethod;
+jmethodID gOnFsyncMethod;
+jmethodID gOnReleaseMethod;
+jmethodID gOnReadMethod;
+jmethodID gOnWriteMethod;
+
+class Callback : public fuse::FuseAppLoopCallback {
+private:
+ static constexpr size_t kBufferSize = std::max(fuse::kFuseMaxWrite, fuse::kFuseMaxRead);
+ static_assert(kBufferSize <= INT32_MAX, "kBufferSize should be fit in int32_t.");
+
+ JNIEnv* const mEnv;
+ jobject const mSelf;
+ ScopedLocalRef<jbyteArray> mJniBuffer;
+ bool mActive;
+
+ template <typename T>
+ T checkException(T result) const {
+ if (mEnv->ExceptionCheck()) {
+ LOGE_EX(mEnv, nullptr);
+ mEnv->ExceptionClear();
+ return -EIO;
+ }
+ return result;
+ }
+
+public:
+ Callback(JNIEnv* env, jobject self) :
+ mEnv(env),
+ mSelf(self),
+ mJniBuffer(env, nullptr),
+ mActive(true) {}
+
+ bool Init() {
+ mJniBuffer.reset(mEnv->NewByteArray(kBufferSize));
+ return mJniBuffer.get();
+ }
+
+ bool IsActive() override {
+ return mActive;
+ }
+
+ int64_t OnGetSize(uint64_t inode) override {
+ return checkException(mEnv->CallLongMethod(mSelf, gOnGetSizeMethod, inode));
+ }
+
+ int32_t OnOpen(uint64_t inode) override {
+ return checkException(mEnv->CallIntMethod(mSelf, gOnOpenMethod, inode));
+ }
+
+ int32_t OnFsync(uint64_t inode) override {
+ return checkException(mEnv->CallIntMethod(mSelf, gOnFsyncMethod, inode));
+ }
+
+ int32_t OnRelease(uint64_t inode) override {
+ if (checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode)) == -1) {
+ mActive = false;
+ }
+ return fuse::kFuseSuccess;
+ }
+
+ int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override {
+ CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
+ const int32_t result = checkException(mEnv->CallIntMethod(
+ mSelf, gOnReadMethod, inode, offset, size, mJniBuffer.get()));
+ if (result <= 0) {
+ return result;
+ }
+ if (result > static_cast<int32_t>(size)) {
+ LOG(ERROR) << "Returned size is too large.";
+ return -EIO;
+ }
+
+ mEnv->GetByteArrayRegion(mJniBuffer.get(), 0, result, static_cast<jbyte*>(buffer));
+ CHECK(!mEnv->ExceptionCheck());
+
+ return checkException(result);
+ }
+
+ int32_t OnWrite(uint64_t inode, uint64_t offset, uint32_t size, const void* buffer) override {
+ CHECK_LE(size, static_cast<uint32_t>(kBufferSize));
+
+ mEnv->SetByteArrayRegion(mJniBuffer.get(), 0, size, static_cast<const jbyte*>(buffer));
+ CHECK(!mEnv->ExceptionCheck());
+
+ return checkException(mEnv->CallIntMethod(
+ mSelf, gOnWriteMethod, inode, offset, size, mJniBuffer.get()));
+ }
+};
+
+jboolean com_android_internal_os_FuseAppLoop_start_loop(JNIEnv* env, jobject self, jint jfd) {
+ base::unique_fd fd(jfd);
+ Callback callback(env, self);
+
+ if (!callback.Init()) {
+ LOG(ERROR) << "Failed to init callback";
+ return JNI_FALSE;
+ }
+
+ return fuse::StartFuseAppLoop(fd.release(), &callback);
+}
+
+const JNINativeMethod methods[] = {
+ {
+ "native_start_loop",
+ "(I)Z",
+ (void *) com_android_internal_os_FuseAppLoop_start_loop
+ }
+};
+
+} // namespace
+
+int register_com_android_internal_os_FuseAppLoop(JNIEnv* env) {
+ gFuseAppLoopClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, CLASS_NAME));
+ gOnGetSizeMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onGetSize", "(J)J");
+ gOnOpenMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onOpen", "(J)I");
+ gOnFsyncMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onFsync", "(J)I");
+ gOnReleaseMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRelease", "(J)I");
+ gOnReadMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onRead", "(JJI[B)I");
+ gOnWriteMethod = GetMethodIDOrDie(env, gFuseAppLoopClass, "onWrite", "(JJI[B)I");
+ RegisterMethodsOrDie(env, CLASS_NAME, methods, NELEM(methods));
+ return 0;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 6781e13..f4d2e7b 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -18,6 +18,7 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
+#include <cutils/log.h>
#include "core_jni_helpers.h"
#include <Interpolator.h>
@@ -62,6 +63,19 @@
return reinterpret_cast<jlong>(new OvershootInterpolator(tension));
}
+static jlong createPathInterpolator(JNIEnv* env, jobject clazz, jfloatArray jX, jfloatArray jY) {
+ jsize lenX = env->GetArrayLength(jX);
+ jsize lenY = env->GetArrayLength(jY);
+ LOG_ALWAYS_FATAL_IF(lenX != lenY || lenX <= 0, "Invalid path interpolator, x size: %d,"
+ " y size: %d", lenX, lenY);
+ std::vector<float> x(lenX);
+ std::vector<float> y(lenY);
+ env->GetFloatArrayRegion(jX, 0, lenX, x.data());
+ env->GetFloatArrayRegion(jY, 0, lenX, y.data());
+
+ return reinterpret_cast<jlong>(new PathInterpolator(std::move(x), std::move(y)));
+}
+
static jlong createLutInterpolator(JNIEnv* env, jobject clazz, jfloatArray jlut) {
jsize len = env->GetArrayLength(jlut);
if (len <= 0) {
@@ -88,6 +102,7 @@
{ "createDecelerateInterpolator", "(F)J", (void*) createDecelerateInterpolator },
{ "createLinearInterpolator", "()J", (void*) createLinearInterpolator },
{ "createOvershootInterpolator", "(F)J", (void*) createOvershootInterpolator },
+ { "createPathInterpolator", "([F[F)J", (void*) createPathInterpolator },
{ "createLutInterpolator", "([F)J", (void*) createLutInterpolator },
};
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 3d63b01..56bec18 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -254,59 +254,11 @@
return reinterpret_cast<jlong>(sur);
}
-static PixelFormat convertPixelFormat(SkColorType format)
-{
- switch (format) {
- case kN32_SkColorType: return PIXEL_FORMAT_RGBA_8888;
- case kARGB_4444_SkColorType: return PIXEL_FORMAT_RGBA_4444;
- case kRGB_565_SkColorType: return PIXEL_FORMAT_RGB_565;
- default: return PIXEL_FORMAT_NONE;
- }
-}
-
static void jni_eglCreatePixmapSurface(JNIEnv *_env, jobject _this, jobject out_sur,
jobject display, jobject config, jobject native_pixmap,
jintArray attrib_list)
{
- if (display == NULL || config == NULL || native_pixmap == NULL
- || !validAttribList(_env, attrib_list)) {
- jniThrowException(_env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
- EGLDisplay dpy = getDisplay(_env, display);
- EGLConfig cnf = getConfig(_env, config);
- jint* base = 0;
-
- SkBitmap nativeBitmap;
- GraphicsJNI::getSkBitmap(_env, native_pixmap, &nativeBitmap);
- SkPixelRef* ref = nativeBitmap.pixelRef();
- if (ref == NULL) {
- jniThrowException(_env, "java/lang/IllegalArgumentException", "Bitmap has no PixelRef");
- return;
- }
-
- SkSafeRef(ref);
- ref->lockPixels();
-
- egl_native_pixmap_t pixmap;
- pixmap.version = sizeof(pixmap);
- pixmap.width = nativeBitmap.width();
- pixmap.height = nativeBitmap.height();
- pixmap.stride = nativeBitmap.rowBytes() / nativeBitmap.bytesPerPixel();
- pixmap.format = convertPixelFormat(nativeBitmap.colorType());
- pixmap.data = (uint8_t*)ref->pixels();
-
- base = beginNativeAttribList(_env, attrib_list);
- EGLSurface sur = eglCreatePixmapSurface(dpy, cnf, &pixmap, base);
- endNativeAttributeList(_env, attrib_list, base);
-
- if (sur != EGL_NO_SURFACE) {
- _env->SetLongField(out_sur, gSurface_EGLSurfaceFieldID, reinterpret_cast<jlong>(sur));
- _env->SetLongField(out_sur, gSurface_NativePixelRefFieldID, reinterpret_cast<jlong>(ref));
- } else {
- ref->unlockPixels();
- SkSafeUnref(ref);
- }
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePixmapSurface");
}
static jlong jni_eglCreateWindowSurface(JNIEnv *_env, jobject _this, jobject display,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fbad143..62ff85d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -182,6 +182,10 @@
android:name="android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS" />
<protected-broadcast
android:name="android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY" />
<protected-broadcast
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
<protected-broadcast
@@ -189,6 +193,7 @@
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.intent.action.PBAP_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.btopp.intent.action.INCOMING_FILE_NOTIFICATION" />
<protected-broadcast android:name="android.btopp.intent.action.USER_CONFIRMATION_TIMEOUT" />
@@ -769,6 +774,15 @@
android:permissionGroup="android.permission-group.PHONE"
android:label="@string/permlab_readPhoneState"
android:description="@string/permdesc_readPhoneState"
+ android:protectionLevel="dangerous" />
+
+ <!-- Allows read access to the device's phone number. This is a subset of the capabilities
+ granted by {@link #READ_PHONE_STATE} but is exposed to ephemeral applications.
+ <p>Protection level: dangerous-->
+ <permission android:name="android.permission.READ_PHONE_NUMBER"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_readPhoneNumber"
+ android:description="@string/permdesc_readPhoneNumber"
android:protectionLevel="dangerous|ephemeral" />
<!-- Allows an application to initiate a phone call without going through
@@ -928,7 +942,7 @@
android:permissionGroup="android.permission-group.CAMERA"
android:label="@string/permlab_camera"
android:description="@string/permdesc_camera"
- android:protectionLevel="dangerous" />
+ android:protectionLevel="dangerous|ephemeral" />
<!-- ====================================================================== -->
@@ -1178,7 +1192,7 @@
<permission android:name="android.permission.ACCESS_NETWORK_STATE"
android:description="@string/permdesc_accessNetworkState"
android:label="@string/permlab_accessNetworkState"
- android:protectionLevel="normal" />
+ android:protectionLevel="normal|ephemeral" />
<!-- Allows applications to access information about Wi-Fi networks.
<p>Protection level: normal
diff --git a/core/res/res/anim/slide_in_enter_micro.xml b/core/res/res/anim/slide_in_enter_micro.xml
index c70874c..6e7df4f 100644
--- a/core/res/res/anim/slide_in_enter_micro.xml
+++ b/core/res/res/anim/slide_in_enter_micro.xml
@@ -19,7 +19,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:zAdjustment="top">
- <translate android:fromYDelta="5%p" android:toYDelta="0"
+ <translate android:fromXDelta="5%p" android:toXDelta="0"
android:duration="417"
android:interpolator="@android:interpolator/launch_task_micro_ydelta" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
diff --git a/core/res/res/anim/slide_out_micro.xml b/core/res/res/anim/slide_out_micro.xml
index c647093..cccf697 100644
--- a/core/res/res/anim/slide_out_micro.xml
+++ b/core/res/res/anim/slide_out_micro.xml
@@ -19,8 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:zAdjustment="top">
- <translate android:fromYDelta="0" android:toYDelta="5%p"
+ android:zAdjustment="normal">
+ <translate android:fromXDelta="0" android:toXDelta="5%p"
android:duration="250"
android:interpolator="@android:interpolator/fast_out_slow_in"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml
new file mode 100644
index 0000000..0b6028c
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_case.xml
@@ -0,0 +1,30 @@
+<!--
+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="20.0dp"
+ android:height="20.0dp"
+ android:viewportWidth="20.0"
+ android:viewportHeight="20.0">
+ <path
+ android:pathData="M15.2,6.2L4.8,6.2c-0.5,0.0 -0.9,0.4 -0.9,1.0L3.9,10.0c0.0,0.5 0.4,1.0 0.9,1.0l3.8,0.0l0.0,-1.0l2.9,0.0l0.0,1.0l3.8,0.0c0.5,0.0 1.0,-0.4 1.0,-1.0L16.3,7.1C16.2,6.6 15.8,6.2 15.2,6.2z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M8.6,12.9l0.0,-1.0L4.3,11.9l0.0,2.4c0.0,0.5 0.4,0.9 0.9,0.9l9.5,0.0c0.5,0.0 0.9,-0.4 0.9,-0.9l0.0,-2.4l-4.3,0.0l0.0,1.0L8.6,12.9z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M7.1,5.2l0.0,1.0 1.0,0.0 0.0,-1.0 3.799999,0.0 0.0,1.0 1.0,0.0 0.0,-1.0 -1.0,-0.9 -3.799999,0.0z"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge_color.xml b/core/res/res/drawable/ic_corp_badge_color.xml
new file mode 100644
index 0000000..b6c7969
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_color.xml
@@ -0,0 +1,24 @@
+<!--
+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="20.0dp"
+ android:height="20.0dp"
+ android:viewportWidth="20.0"
+ android:viewportHeight="20.0">
+ <path
+ android:pathData="M10.0,10.0m-10.0,0.0a10.0,10.0 0.0,1.0 1.0,20.0 0.0a10.0,10.0 0.0,1.0 1.0,-20.0 0.0"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_badge_no_background.xml b/core/res/res/drawable/ic_corp_badge_no_background.xml
index b1bddfc..78322a9 100644
--- a/core/res/res/drawable/ic_corp_badge_no_background.xml
+++ b/core/res/res/drawable/ic_corp_badge_no_background.xml
@@ -20,11 +20,11 @@
android:viewportHeight="24.0">
<path
android:pathData="M20.801,5.981L17.13,5.98l0.001,-1.471l-2.053,-2.055L8.969,2.453L6.915,4.506L6.914,5.977L3.203,5.976c-1.216,0.0 -2.189,0.983 -2.189,2.199L1.0,12.406c0.0,1.216 0.983,2.2 2.199,2.2L10.0,14.608l0.0,-1.644l0.291,0.0l3.351,0.0l0.291,0.0l0.0,1.645l6.863,0.002c1.216,0.0 2.2,-0.983 2.2,-2.199L23.0,8.181C23.0,6.965 22.017,5.981 20.801,5.981zM15.076,5.979L8.968,5.978l0.001,-1.471l6.108,0.001L15.076,5.979z"
- android:fillColor="#FF5722"/>
+ android:fillColor="#FFFFFF"/>
<path
android:pathData="M13.911,16.646L9.978,16.646L9.978,15.48L1.673,15.48l0.0,4.105c0.0,1.216 0.959,2.2 2.175,2.2l16.13,0.004c1.216,0.0 2.203,-0.983 2.203,-2.199l0.0,-4.11l-8.27,0.0L13.910999,16.646z"
- android:fillColor="#FF5722"/>
+ android:fillColor="#FFFFFF"/>
<path
android:pathData="M23.657,6.55 h4.72 v1.137 h-4.72z"
android:fillColor="#00000000"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge.xml b/core/res/res/drawable/ic_corp_icon_badge_case.xml
similarity index 71%
rename from core/res/res/drawable/ic_corp_icon_badge.xml
rename to core/res/res/drawable/ic_corp_icon_badge_case.xml
index 0273545..d62eda4 100644
--- a/core/res/res/drawable/ic_corp_icon_badge.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_case.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+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.
@@ -19,17 +19,6 @@
android:viewportWidth="64.0"
android:viewportHeight="64.0">
<path
- android:fillColor="#FF000000"
- android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillAlpha="0.2"/>
- <path
- android:fillColor="#FF000000"
- android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillAlpha="0.2"/>
- <path
- android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
- android:fillColor="#FF5722"/>
- <path
android:pathData="M56.4,43.5L41.8,43.5c-0.7,0.0 -1.3,0.6 -1.3,1.3l0.0,4.0c0.0,0.7 0.6,1.3 1.3,1.3L47.0,50.1l0.0,-1.3l4.0,0.0l0.0,1.4l5.4,0.0c0.7,0.0 1.3,-0.6 1.3,-1.3l0.0,-4.0C57.6,44.1 57.0,43.5 56.4,43.5z"
android:fillColor="#FFFFFF"/>
<path
diff --git a/core/res/res/drawable/ic_corp_icon_badge_color.xml b/core/res/res/drawable/ic_corp_icon_badge_color.xml
new file mode 100644
index 0000000..3bc4e67
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_icon_badge_color.xml
@@ -0,0 +1,24 @@
+<!--
+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="64.0dp"
+ android:height="64.0dp"
+ android:viewportWidth="64.0"
+ android:viewportHeight="64.0">
+ <path
+ android:pathData="M49.1,48.8m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+ android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
new file mode 100644
index 0000000..a546cdd
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
@@ -0,0 +1,29 @@
+<!--
+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="64.0dp"
+ android:height="64.0dp"
+ android:viewportWidth="64.0"
+ android:viewportHeight="64.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M49.1,50.1m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+ android:fillAlpha="0.2"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M49.1,49.4m-13.9,0.0a13.9,13.9 0.0,1.0 1.0,27.8 0.0a13.9,13.9 0.0,1.0 1.0,-27.8 0.0"
+ android:fillAlpha="0.2"/>
+</vector>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e43f1ba..a24bce1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Kennisgewing-volume"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Verstekluitoon"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Verstek (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Luitone"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Wekkerklanke"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Kennisgewingsklanke"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi netwerke beskikbaar</item>
<item quantity="one">Wi-Fi-netwerk beskikbaar</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Kies jaar"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> uitgevee"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Raak en hou Terug om hierdie skerm te ontspeld."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Program is vasgespeld: Dit mag nie op hierdie toestel ontspeld word nie."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skerm vasgespeld"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Jy sal enige veranderinge verloor en die demonstrasie sal oor <xliff:g id="TIMEOUT">%1$s</xliff:g> sekondes weer begin …"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Kanselleer"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Stel nou terug"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Doen \'n fabriekterugstelling om hierdie toestel sonder beperkinge te gebruik"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Raak om meer te wete te kom."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferensie-oproep"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Nutswenk-opspringer"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index af8c592..6bab82c 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">የWi-Fi አውታረ መረቦች አሉ</item>
<item quantity="other">የWi-Fi አውታረ መረቦች አሉ</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ይህን ማያ ገጽ ለመንቀል ተመለስን ይንኩትና ያዙት።"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"መተግበሪያ ተሰክቷል፦ በዚህ መሣሪያ ላይ ማላቀቅ አይፈቀድም።"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ማንኛቸውም ለውጦች ይጠፋሉ፣ እና ማሳያው በ<xliff:g id="TIMEOUT">%1$s</xliff:g> ሰከንዶች ውስጥ እንደገና ይጀምራል…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ይቅር"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"አሁን ዳግም አስጀምር"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ይህን መሣሪያ ያለምንም ገደብ ለመጠቀም የፋብሪካ ዳግም ያስጀምሩ"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"የበለጠ ለመረዳት ይንኩ።"</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="8101791425834697618">"የመሣሪያ ጥቆማ ብቅ-ባይ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b3c24e5..7c9baeb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1151,16 +1151,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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="zero">لا تتوفر أية شبكات Wi-Fi</item>
<item quantity="two">تتوفر شبكتا Wi-Fi</item>
@@ -1672,6 +1668,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"لإزالة تثبيت هذه الشاشة، يمكنك لمس زر الرجوع مع الاستمرار."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"التطبيق مقيد: ولا يسمح بإلغاء التقييد على هذا الجهاز."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"تم تثبيت الشاشة"</string>
@@ -1825,8 +1825,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ستفقد أي تغييرات وسيبدأ العرض التوضيحي مرة أخرى خلال <xliff:g id="TIMEOUT">%1$s</xliff:g> من الثواني…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"إلغاء"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"إعادة التعيين الآن"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"يمكنك إعادة تعيين بيانات المصنع لاستخدام هذا الجهاز بدون قيود"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"المس للتعرف على مزيد من المعلومات."</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="8101791425834697618">"نافذة منبثقة لتلميح"</string>
</resources>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 7e9c508..11133d1 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Media həcmi"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Bildiriş səsi"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Defolt rinqton"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Defolt (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Heç biri"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Zəng səsləri"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zəngli saat səsləri"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildiriş səsləri"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Naməlum"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Əlçatan Wi-Fi şəbəkələri</item>
<item quantity="one">Əlçatan Wi-Fi şəbəkəsi</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"İl seçin"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"İş <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Sancağı götürmək üçün Geri düyməsinə toxunun və saxlayın."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Tətbiq sancılıb: Açmağa bu cihazda icazə verilmir."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Hər hansı dəyişikliyi itirəcəksiniz və demo <xliff:g id="TIMEOUT">%1$s</xliff:g> saniyəyə yenidən başlayacaq…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ləğv edin"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"İndi sıfırlayın"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı məhdudiyyətsiz istifadə etmək üçün zavod sıfırlaması edin"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha çox məlumat üçün toxunun."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
<string name="conference_call" msgid="3751093130790472426">"Konfrans Zəngi"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Popap"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 6caf561..d2799c4 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1082,16 +1082,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka medija"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka obaveštenja"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Podrazumevani zvuk zvona"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Podrazumevano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Zvukovi zvona"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuci alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuci obaveštenja"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Wi-Fi mreže su dostupne</item>
<item quantity="few">Wi-Fi mreže su dostupne</item>
@@ -1591,6 +1587,10 @@
<string name="select_year" msgid="7952052866994196170">"Izaberite godinu"</string>
<string name="deleted_key" msgid="7659477886625566590">"Izbrisali ste <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> na poslu"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i zadržite Nazad."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je zakačena: otkačinjanje nije dozvoljeno na ovom uređaju."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
@@ -1717,8 +1717,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Izgubićete sve promene i demonstracija će ponovo početi za <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Otkaži"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Resetujte uređaj na fabrička podešavanja da biste ga koristili bez ograničenja"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Iskačuće objašnjenje"</string>
</resources>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index c076db2..a7be24e 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -1105,16 +1105,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">сетка Wi-Fi даступная</item>
<item quantity="few">сеткі Wi-Fi даступныя</item>
@@ -1618,6 +1614,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Каб адмацаваць гэты экран, дакраніцеся і ўтрымлівайце кнопку \"Назад\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Праграма замацавана: адмацаванне на гэтай прыладзе не дапускаецца."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Экран замацаваны"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Усе змены будуць страчаны, і дэманстрацыя пачнецца зноў праз <xliff:g id="TIMEOUT">%1$s</xliff:g> с…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Скасаваць"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Выканаць скід"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Выканайце скід да заводскіх налад, каб выкарыстоўваць гэту прыладу без абмежаванняў"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Краніце, каб даведацца больш."</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="8101791425834697618">"Усплывальная падказка"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2d6bdb2..1900b074 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Има достъпни Wi-Fi мрежи</item>
<item quantity="one">Има достъпна Wi-Fi мрежа</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"За да освободите този екран, докоснете и задръжте бутона за връщане назад."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Приложението е фиксирано. Освобождаването му не е разрешено на това устройство."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екранът е фиксиран"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ще загубите всички промени и демонстрацията ще започне отново след <xliff:g id="TIMEOUT">%1$s</xliff:g> секунди…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Отказ"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Нулиране сега"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Възстановете фабричните настройки на това устройство, за да го използвате без ограничения"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Докоснете, за да научите повече."</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="8101791425834697618">"Изскачащ прозорец с подсказка"</string>
</resources>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 21b737a..bdbea68 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' স্পর্শ করুন এবং ধরে রাখুন৷"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"অ্যাপ্লিকেশান পিন করা আছে: এই ডিভাইস এটিকে পিনমুক্ত করা মঞ্জুরিপ্রাপ্ত নয়৷"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"স্ক্রীন পিন করা হয়েছে"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"আপনার করা যে কোনো পরিবর্তন মুছে যাবে এবং <xliff:g id="TIMEOUT">%1$s</xliff:g> সেকেন্ডের মধ্যে ডেমো আবার শুরু হবে…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"বাতিল করুন"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"এখনই পুনরায় সেট করুন"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"কোনো বিধিনিষেধ ছাড়াই এই ডিভাইসটিকে ব্যবহার করতে ফ্যাক্টরি রিসেট করুন"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"আরো জানতে স্পর্শ করুন৷"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"কনফারেন্স কল"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index 80ee407..f62dac7 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -551,35 +551,35 @@
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Kuća"</item>
<item msgid="869923650527136615">"Mobilni"</item>
- <item msgid="7897544654242874543">"Poslovni"</item>
+ <item msgid="7897544654242874543">"Posao"</item>
<item msgid="1103601433382158155">"Poslovni faks"</item>
<item msgid="1735177144948329370">"Kućni faks"</item>
<item msgid="603878674477207394">"Pejdžer"</item>
<item msgid="1650824275177931637">"Ostalo"</item>
- <item msgid="9192514806975898961">"Dodatno"</item>
+ <item msgid="9192514806975898961">"Prilagođeno"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Kućni"</item>
- <item msgid="7084237356602625604">"Poslovni"</item>
- <item msgid="1112044410659011023">"Ostali"</item>
- <item msgid="2374913952870110618">"Dodatni"</item>
+ <item msgid="7084237356602625604">"Posao"</item>
+ <item msgid="1112044410659011023">"Ostalo"</item>
+ <item msgid="2374913952870110618">"Prilagođeno"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Kuća"</item>
<item msgid="5629153956045109251">"Posao"</item>
<item msgid="4966604264500343469">"Ostalo"</item>
- <item msgid="4932682847595299369">"Dodatno"</item>
+ <item msgid="4932682847595299369">"Prilagođeno"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="1738585194601476694">"Kućni"</item>
- <item msgid="1359644565647383708">"Poslovni"</item>
- <item msgid="7868549401053615677">"Ostali"</item>
- <item msgid="3145118944639869809">"Dodatni"</item>
+ <item msgid="1359644565647383708">"Posao"</item>
+ <item msgid="7868549401053615677">"Ostalo"</item>
+ <item msgid="3145118944639869809">"Prilagođeno"</item>
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Posao"</item>
<item msgid="4378074129049520373">"Ostalo"</item>
- <item msgid="3455047468583965104">"Dodatno"</item>
+ <item msgid="3455047468583965104">"Prilagođeno"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="8595261363518459565">"AIM"</item>
@@ -600,15 +600,15 @@
<string name="phoneTypePager" msgid="7582359955394921732">"Pejdžer"</string>
<string name="phoneTypeOther" msgid="1544425847868765990">"Ostalo"</string>
<string name="phoneTypeCallback" msgid="2712175203065678206">"Povratni poziv"</string>
- <string name="phoneTypeCar" msgid="8738360689616716982">"Auto"</string>
- <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Glavni broj kompanije"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"Automobil"</string>
+ <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Poslovni glavni"</string>
<string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
<string name="phoneTypeMain" msgid="6766137010628326916">"Glavni"</string>
<string name="phoneTypeOtherFax" msgid="8587657145072446565">"Drugi faks"</string>
<string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
<string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
<string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
- <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Posao mobilni"</string>
+ <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Poslovni mobilni"</string>
<string name="phoneTypeWorkPager" msgid="649938731231157056">"Poslovni pejdžer"</string>
<string name="phoneTypeAssistant" msgid="5596772636128562884">"Pomoćnik"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
@@ -616,10 +616,10 @@
<string name="eventTypeBirthday" msgid="2813379844211390740">"Rođendan"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Godišnjica"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Ostalo"</string>
- <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeni"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeno"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Kućni"</string>
- <string name="emailTypeWork" msgid="3548058059601149973">"Poslovni"</string>
- <string name="emailTypeOther" msgid="2923008695272639549">"Ostali"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"Posao"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"Ostalo"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Mobilni"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"Prilagođeno"</string>
<string name="postalTypeHome" msgid="8165756977184483097">"Kućna adresa"</string>
@@ -1084,16 +1084,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka za medijske sadržaje"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka za obavještenja"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Zadano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuci alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuci obavještenja"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Wi-Fi mreže su dostupne</item>
<item quantity="few">Wi-Fi mreže su dostupne</item>
@@ -1593,6 +1589,10 @@
<string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
<string name="deleted_key" msgid="7659477886625566590">"Broj <xliff:g id="KEY">%1$s</xliff:g> je izbrisan"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i držite dugme Nazad."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikačena. Na ovom uređaju nije dozvoljeno otkačivanje."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
@@ -1719,8 +1719,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Nestat će sve izmjene, a demonstracija će početi ponovo za <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Otkaži"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati sada na početne postavke"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Vratite uređaj na fabričke postavke kako biste ga koristili bez ograničenja"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da saznate više."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Iskočni prozor sa savjetom u vezi alata"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 35b2918..f335d44 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volum de multimèdia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volum de notificació"</string>
<string name="ringtone_default" msgid="3789758980357696936">"So predeterminat"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Cap"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Sons"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de l\'alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificació"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconegut"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Xarxes Wi-Fi disponibles</item>
<item quantity="one">Xarxa Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Selecciona un any"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> suprimit"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Toca i mantén premuda l\'opció Enrere per deixar de fixar aquesta pantalla."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"S\'ha fixat l\'aplicació. En aquest dispositiu no es permet anul·lar-ne la fixació."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perdràs els canvis, i la demostració tornarà a començar d\'aquí a <xliff:g id="TIMEOUT">%1$s</xliff:g> segons…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel·la"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restableix ara"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Restableix les dades de fàbrica del dispositiu per utilitzar-lo sense restriccions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca per obtenir més informació."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferència"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Descripció emergent"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 95a6728..0bdd212 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1105,16 +1105,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitost médií"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitost oznámení"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Výchozí vyzváněcí tón"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Výchozí (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Žádný"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Vyzváněcí tóny"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíku"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornění"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Neznámé"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="few">K dispozici jsou sítě Wi-Fi</item>
<item quantity="many">K dispozici jsou sítě Wi-Fi</item>
@@ -1618,6 +1614,10 @@
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
<string name="deleted_key" msgid="7659477886625566590">"Číslice <xliff:g id="KEY">%1$s</xliff:g> byla smazána"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Chcete-li tuto obrazovku uvolnit, klepněte na tlačítko Zpět a podržte jej."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikace je připnutá: Odepnutí v tomto zařízení není povoleno."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka připnuta"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ztratíte všechny provedené změny a ukázka se za <xliff:g id="TIMEOUT">%1$s</xliff:g> s spustí znovu…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Zrušit"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovat"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Chcete-li toto zařízení používat bez omezení, obnovte jej do továrního nastavení"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím zobrazíte další informace."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenční hovor"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Vyskakovací okno s popiskem"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a628e42..f80f5f0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Vælg år"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og holde fingeren nede."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen er fastgjort: Det er ikke tilladt at frigøre den på denne enhed."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skærmen blev fastgjort"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Du mister alle ændringer, og demoen starter igen om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuller"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nulstil nu"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Gendan fabriksdataene på enheden for at bruge den uden begrænsninger"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryk for at få flere oplysninger."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonmøde"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 86f2070..1ceb0cc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> gelöscht"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Um die Fixierung dieses Bildschirms aufzuheben, \"Zurück\" berühren und halten."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Die App ist fixiert. Das Aufheben der Fixierung ist auf diesem Gerät nicht zulässig."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Bildschirm fixiert"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Alle Änderungen gehen verloren und Demo wird in <xliff:g id="TIMEOUT">%1$s</xliff:g> Sekunden neu gestartet…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Abbrechen"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Jetzt zurücksetzen"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Gerät auf Werkseinstellungen zurücksetzen, um es ohne Einschränkungen zu nutzen"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Für weitere Informationen tippen."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonkonferenz"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4ce3a1f..b9d9503 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Υπάρχουν διαθέσιμα δίκτυα Wi-Fi</item>
<item quantity="one">Υπάρχει διαθέσιμο δίκτυο Wi-Fi</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, αγγίξτε παρατεταμένα \"Επιστροφή\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Η εφαρμογή καρφιτσώθηκε: Το ξεκαρφίτσωμα δεν επιτρέπεται σε αυτήν τη συσκευή."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Η οθόνη καρφιτσώθηκε"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Τυχόν αλλαγές που πραγματοποιήσατε θα χαθούν και η επίδειξη θα ξεκινήσει ξανά σε <xliff:g id="TIMEOUT">%1$s</xliff:g> δευτερόλεπτα…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ακύρωση"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Επαναφορά τώρα"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Επαναφέρετε τις εργοστασιακές ρυθμίσεις για να χρησιμοποιήσετε αυτήν τη συσκευή χωρίς περιορισμούς"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Αγγίξτε για να μάθετε περισσότερα."</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="8101791425834697618">"Αναδυόμενο παράθυρο επεξήγησης εργαλείου"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 72c1271..5bc43e0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi networks available</item>
<item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch & hold Back."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 72c1271..5bc43e0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi networks available</item>
<item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch & hold Back."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 72c1271..5bc43e0 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Media volume"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Notification volume"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Default ringtone"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"None"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtones"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi networks available</item>
<item quantity="one">Wi-Fi network available</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Select year"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"To unpin this screen, touch & hold Back."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is pinned: unpinning isn\'t allowed on this device."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Screen pinned"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"You\'ll lose any changes and the demo will start again in <xliff:g id="TIMEOUT">%1$s</xliff:g> seconds…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancel"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reset now"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Tooltip Pop-up"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 738af8c..cd2c5aa 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen de los medios"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificación"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Tono predeterminado"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos de llamada"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">redes de Wi-Fi disponibles</item>
<item quantity="one">red de Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> borrado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Para dejar de fijar esta pantalla, mantén presionado Atrás."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"La aplicación está fijada, no se puede anular la fijación en este dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fija"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Se perderán los cambios y la demostración volverá a iniciarse en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece la configuración de fábrica para usar este dispositivo sin restricciones"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Ventana emergente de la información sobre la herramienta"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 3c2915d..fe7d1ac 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volumen multimedia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volumen de notificaciones"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Tono por defecto"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ninguno"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tonos"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Redes Wi-Fi disponibles</item>
<item quantity="one">Red Wi-Fi disponible</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Mantén pulsado el botón Atrás para dejar de fijar esta pantalla."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"La aplicación está fijada: no se puede deshacer la fijación en este dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fijada"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Se perderán todos los cambios y la demostración volverá a empezar en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer ahora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece los datos de fábrica para usar este dispositivo sin restricciones"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Descripción emergente"</string>
</resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 96b060f..09668cb 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -650,7 +650,7 @@
<string name="relationTypeMother" msgid="4578571352962758304">"Ema"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"Vanem"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
- <string name="relationTypeReferredBy" msgid="101573059844135524">"Viitas:"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"Soovitaja"</string>
<string name="relationTypeRelative" msgid="1799819930085610271">"Sugulane"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Õde"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Abikaasa"</string>
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Aasta valimine"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> on kustutatud"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Ekraani vabastamiseks puudutage pikalt nuppu Tagasi."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Rakendus on kinnitatud: vabastamine pole selles seadmes lubatud."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekraan on kinnitatud"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Kõik muudatused lähevad kaotsi ja demo käivitub uuesti <xliff:g id="TIMEOUT">%1$s</xliff:g> sekundi möödudes …"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Tühista"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Lähtesta kohe"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Seadme piiranguteta kasutamiseks lähtestage see tehaseandmetele"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lisateabe saamiseks puudutage."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konverentskõne"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 6ccd864..2ea4bed 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Euskarriaren bolumena"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Jakinarazpenen bolumena"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Tonu lehenetsia"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Lehenetsia (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Bat ere ez"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tonuak"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarma-soinuak"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Jakinarazpen-soinuak"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Ezezaguna"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi sareak erabilgarri</item>
<item quantity="one">Wi-Fi sarea erabilgarri</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Hautatu urtea"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ezabatu da"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Pantailari aingura kentzeko, eduki sakatuta Atzera botoia."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikazioa ainguratuta dago. Gailu honetan ezin da aingura kendu."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantaila ainguratu da"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Aldaketak galduko dituzu eta <xliff:g id="TIMEOUT">%1$s</xliff:g> segundo barru hasiko da berriro demoa…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Utzi"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Berrezarri"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Berrezarri jatorrizko ezarpenak gailua murriztapenik gabe erabili ahal izateko"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sakatu informazio gehiago lortzeko."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferentzia-deia"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Aholkudun leiho gainerakorra"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e8e61f4..55e67bc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"برای برداشتن پین این صفحه، «برگشت» را لمس کنید و نگه دارید."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"برنامه پین شده است: برداشتن پین در این دستگاه مجاز نیست."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"صفحه پین شد"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"همه تغییرات را از دست خواهید داد و نسخه نمایشی دوباره تا <xliff:g id="TIMEOUT">%1$s</xliff:g> ثانیه دیگر شروع میشود…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"لغو"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"بازنشانی در این لحظه"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"برای استفاده بدون محدودیت از این دستگاه، بازنشانی کارخانهای انجام دهید"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"برای یادگیری بیشتر لمس کنید."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> غیرفعال شد"</string>
<string name="conference_call" msgid="3751093130790472426">"تماس کنفرانسی"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index dbfd8ba..6800fa8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Median äänenvoimakkuus"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Ilmoituksen äänenvoimakkuus"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Oletussoittoääni"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Oletus (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ei mitään"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Soittoäänet"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Hälytysäänet"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ilmoitusäänet"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Tuntematon"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi-verkkoja käytettävissä</item>
<item quantity="one">Wi-Fi-verkko käytettävissä</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Valitse vuosi"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> poistettiin"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Irrota näyttö koskettamalla Takaisin-painiketta pitkään."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Sovellus on kiinnitetty. Irrottaminen ei ole sallittua tällä laitteella."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Näyttö kiinnitetty"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Muutokset poistetaan ja esittely aloitetaan uudelleen <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunnin kuluttua…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Peruuta"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Palauta nyt"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Palauta tehdasasetukset, jotta voit käyttää tätä laitetta rajoituksitta"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lue lisätietoja koskettamalla."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
<string name="conference_call" msgid="3751093130790472426">"Puhelinneuvottelu"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Työkaluvinkki ponnahdusikkunassa"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 501627d..009b9eb 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Sélectionnez une année"</string>
<string name="deleted_key" msgid="7659477886625566590">"« <xliff:g id="KEY">%1$s</xliff:g> » a été supprimé"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Pour annuler l\'épinglage de cet écran, maintenez enfoncée la touche Retour."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée : l\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Vous perdrez vos modifications, et la démo recommencera dans <xliff:g id="TIMEOUT">%1$s</xliff:g> secondes…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuler"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Réinitialiser maintenant"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablissez la configuration d\'usine de cet appareil pour l\'utiliser sans restrictions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touchez ici pour en savoir plus."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ccff4f3..5b21dd4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Sélectionner une année"</string>
<string name="deleted_key" msgid="7659477886625566590">"\"<xliff:g id="KEY">%1$s</xliff:g>\" supprimé"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Retour\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée. L\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé."</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Vous perdrez vos modifications, et la démo recommencera dans <xliff:g id="TIMEOUT">%1$s</xliff:g> secondes…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuler"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Réinitialiser maintenant"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablir la configuration d\'usine pour utiliser cet appareil sans restrictions"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Appuyez ici pour en savoir plus."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
<string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 89a9471..10a7647 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume dos elementos multimedia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume das notificacións"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Ton de chamada predeterminado"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predeterminado (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ningún"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tons de chamada"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificación"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Descoñecido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Redes wifi dispoñibles</item>
<item quantity="one">Rede wifi dispoñible</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Seleccionar ano"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Para soltar a pantalla, mantén premido Volver."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"A aplicación está fixada: non se permite soltala neste dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Pantalla fixada"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderás os cambios que fixeses e a demostración volverá comezar en <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Restablecer agora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablecemento dos valores de fábrica para usar este dispositivo sen restricións"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para acceder a máis información"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferencia telefónica"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Ventá emerxente do cadro de información"</string>
</resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index cbb0d9e4a4..9a7d432 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item>
<item quantity="other">Wi-Fi નેટવર્ક્સ ઉપલબ્ધ</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"આ સ્ક્રીનને અનપિન કરવા માટે, પાછળને ટચ કરીને પકડી રાખો."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ઍપ્લિકેશન પિન કરેલ છે. આ ઉપકરણ પર અનપિન કરવાની મંજૂરી નથી."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"સ્ક્રીન પિન કરી"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"તમે કોઈપણ ફેરફારો ગુમાવશો અને ડેમો <xliff:g id="TIMEOUT">%1$s</xliff:g> સેકન્ડમાં ફરી શરૂ થશે…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"રદ કરો"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"હમણાં ફરીથી સેટ કરો"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"આ ઉપકરણનો પ્રતિબંધો વિના ઉપયોગ કરવા માટે ફેક્ટરી રીસેટ કરો"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"વધુ જાણવા માટે ટચ કરો."</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="8101791425834697618">"ટૂલટિપ પોપઅપ"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e833052..c46102b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"इस स्क्रीन को अनपिन करने के लिए, वापस जाएं को स्पर्श करके रखें."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ऐप पिन किया गया है: इस डिवाइस पर अनपिन करने की अनुमति नहीं है."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन की गई"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"आपके सभी बदलाव खो जाएंगे और डेमो <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकंड में फिर से शुरू हो जाएगा…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"अभी नहीं"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"अभी रीसेट करें"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"इस डिवाइस को प्रतिबंधों के बिना उपयोग करने के लिए फ़ैक्टरी रीसेट करें"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जानने के लिए स्पर्श करें."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"कॉन्फ़्रेंस कॉल"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e811b94..fa593acd 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1082,16 +1082,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Glasnoća medija"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Glasnoća obavijesti"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Zadano (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ništa"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvukovi alarma"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvukovi obavijesti"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Dostupne su Wi-Fi mreže</item>
<item quantity="few">Dostupne su Wi-Fi mreže</item>
@@ -1591,6 +1587,10 @@
<string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
<string name="deleted_key" msgid="7659477886625566590">"Izbrisan je broj <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> za posao"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkvačili ovaj zaslon, dodirnite i zadržite Natrag."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikvačena: otkvačivanje nije dopušteno na tom uređaju."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pričvršćen"</string>
@@ -1717,8 +1717,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Sve će se promjene izbrisati, a demonstracija će se ponovo pokrenuti za <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Odustani"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Vrati na zadano sada"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Uređaj je vraćen na tvorničke postavke da biste ga mogli upotrebljavati bez ograničenja"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Skočni prozor opisa"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b0ce160..d21e47e 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Média hangereje"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Értesítés hangereje"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Alapértelmezett csengőhang"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Alapértelmezett (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Egyik sem"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Csengőhangok"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ébresztőhangok"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Értesítőhangok"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Ismeretlen"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi hálózatok érhetők el</item>
<item quantity="one">Van elérhető Wi-Fi hálózat</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Válassza ki az évet"</string>
<string name="deleted_key" msgid="7659477886625566590">"A(z) <xliff:g id="KEY">%1$s</xliff:g> érték törölve"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza lehetőséget."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Az alkalmazás rögzítve van: a rögzítés feloldása nem engedélyezett ezen az eszközön."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Képernyő rögzítve"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"A módosítások elvesznek, és a bemutató újra elindul <xliff:g id="TIMEOUT">%1$s</xliff:g> másodperc múlva…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Mégse"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Visszaállítás most"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Állítsa vissza a gyári beállításokat az eszköz korlátozások nélküli használata érdekében"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Érintse meg a további információkért."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenciahívás"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Elemleíró előugró ablak"</string>
</resources>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 2ba22af..10072a2 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Այս էկրանն ապամրացնելու համար հպեք և պահեք Հետ կոճակը:"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Հավելվածն ամրացված է: Ապամրացումն այս սարքում չի թույլատրվում:"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Էկրանն ամրացված է"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Կատարված փոփոխությունները չեն պահվի, իսկ ցուցադրական նյութը կրկին կգործարկվի <xliff:g id="TIMEOUT">%1$s</xliff:g> վայրկյանից…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Չեղարկել"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Վերակայել հիմա"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Սարքն առանց սահմանափակումների օգտագործելու համար կատարեք գործարանային վերակայում"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Հպեք՝ ավելին իմանալու համար:"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Անջատած <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Կոնֆերանս զանգ"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 09223cd..29d820e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume media"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume pemberitahuan"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Nada dering default"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Default (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Tidak Ada"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Nada dering"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suara alarm"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suara notifikasi"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Jaringan Wi-Fi tersedia</item>
<item quantity="one">Jaringan Wi-Fi tersedia</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dihapus"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Untuk melepas pin layar ini, sentuh & tahan tombol Kembali."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Pin dipasang ke aplikasi. Melepas pin tidak diizinkan di perangkat ini."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Layar disematkan"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perubahan yang dibuat akan hilang dan demo akan dimulai lagi dalam <xliff:g id="TIMEOUT">%1$s</xliff:g> detik…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Batal"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setel ulang sekarang"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Dikembalikan ke setelan pabrik agar perangkat ini dapat digunakan tanpa batasan"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sentuh untuk mempelajari lebih lanjut."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferensi Telepon"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Munculan Keterangan Alat"</string>
</resources>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 105a647..655c521 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Hljóðstyrkur efnisspilunar"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Hljóðstyrkur tilkynninga"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Sjálfgefinn hringitónn"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Sjálfgefið (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ekkert"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Hringitónar"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Vekjarahljóð"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tilkynningarhljóð"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Óþekkt"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Wi-Fi net í boði</item>
<item quantity="other">Wi-Fi net í boði</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Veldu ár"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eytt"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Til að taka lásinn af þessari skjámynd skaltu halda inni bakkhnappinum."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Forritið er fest: Ekki er hægt að losa forrit í þessu tæki."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skjár festur"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Þú glatar öllum breytingum og kynningin byrjar aftur eftir <xliff:g id="TIMEOUT">%1$s</xliff:g> sekúndur…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Hætta við"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Endurstilla núna"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Núllstilltu til að nota þetta tæki án takmarkana"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Snertu til að fá frekari upplýsingar."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Símafundur"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Ábendingarsprettigluggi"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 564472e..446e367 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume contenuti multimediali"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume notifiche"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Suoneria predefinita"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predefinita (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Nessuna"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Suonerie"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suoni delle sveglie"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suoni di notifica"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Sconosciuta"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Reti Wi-Fi disponibili</item>
<item quantity="one">Rete Wi-Fi disponibile</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Seleziona anno"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminato"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Per sbloccare questa schermata tieni premuta l\'opzione Indietro."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'app è bloccata. Su questo dispositivo non è consentito lo sblocco."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Schermata bloccata"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderai tutte le modifiche e la demo verrà riavviata tra <xliff:g id="TIMEOUT">%1$s</xliff:g> secondi…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annulla"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ripristina ora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Esegui il ripristino dei dati di fabbrica per utilizzare il dispositivo senza limitazioni"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tocca per ulteriori informazioni."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
<string name="conference_call" msgid="3751093130790472426">"Audioconferenza"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Popup descrizione comando"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d4b9bf1..1881ae4 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1618,6 +1618,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"כדי לבטל את הצמדת המסך הזה, לחץ לחיצה ממושכת על הלחצן \'הקודם\'."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"האפליקציה מוצמדת: ביטול ההצמדה אסור במכשיר הזה."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"המסך מוצמד"</string>
@@ -1753,8 +1757,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"תאבד את כל השינויים וההדגמה תתחיל שוב בעוד <xliff:g id="TIMEOUT">%1$s</xliff:g> שניות…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"בטל"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"אפס עכשיו"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"איפוס להגדרות היצרן כדי לאפשר שימוש במכשיר ללא מגבלות"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"גע לקבלת מידע נוסף."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> הושבת"</string>
<string name="conference_call" msgid="3751093130790472426">"שיחת ועידה"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e2432f1..fdfb890 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"この画面の固定を解除するには [戻る] を押し続けます。"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"アプリは固定されています。この端末では固定を解除できません。"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"画面を固定しました"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"変更が失われ、<xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後にデモがもう一度開始されます…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"キャンセル"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"今すぐリセット"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"制限なしでこの端末を使用するには初期状態にリセットしてください"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"タップして詳細をご確認ください。"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"停止済みの「<xliff:g id="LABEL">%1$s</xliff:g>」"</string>
<string name="conference_call" msgid="3751093130790472426">"グループ通話"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 5e069b6..56f0a62 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">ხელმისაწვდომია Wi-Fi ქსელები</item>
<item quantity="one">ხელმისაწვდომია Wi-Fi ქსელი</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ამ ეკრანის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკს „უკან“."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"აპი მიმაგრებულია: მიმაგრების მოხსნა არ არის ნებადართული ამ მოწყობილობაზე."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ეკრანი დაფიქსირდა"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"შეტანილი ცვლილებები დაიკარგება, ხოლო დემონსტრაცია ხელახლა <xliff:g id="TIMEOUT">%1$s</xliff:g> წამში დაიწყება…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"გაუქმება"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ახლავე გადაყენება"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ამ მოწყობილობის შეზღუდვების გარეშე გამოსაყენებლად, დააბრუნეთ ქარხნული პარამეტრები"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"შეეხეთ მეტის გასაგებად."</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="8101791425834697618">"მინიშნების კონტექსტური სარკმელი"</string>
</resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 729f726..51d1dcc 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Осы экранды босату үшін \"Артқа\" түймесін басып тұрыңыз."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Бағдарлама белгіленді: Бұл құрылғыда белгіні алуға рұқсат берілмейді."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Экран түйрелді"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Барлық өзгеріс жоғалады және демо нұсқасы <xliff:g id="TIMEOUT">%1$s</xliff:g> секундтан кейін қайта қосылады…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Бас тарту"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Қазір бастапқы күйге қайтару"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Осы құрылғыны шектеусіз пайдалану үшін зауыттық параметрлерді қалпына келтіріңіз"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Қосымша мәліметтер алу үшін түртіңіз."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өшірулі"</string>
<string name="conference_call" msgid="3751093130790472426">"Конференциялық қоңырау"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index c3e939e..aa6cb77 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1566,6 +1566,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ដើម្បីផ្តាច់អេក្រង់នេះ សូមប៉ះ និងសង្កត់ប៊ូតុងថយក្រោយឲ្យជាប់។"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"កម្មវិធីនេះត្រូវបានខ្ទាស់។ មិនអនុញ្ញាតឲ្យដោះការខ្ទាស់នៅលើឧបករណ៍នេះទេ។"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"បានភ្ជាប់អេក្រង់"</string>
@@ -1683,8 +1687,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"អ្នកនឹងបាត់បង់ការផ្លាស់ប្តូរណាមួយ ហើយការបង្ហាញសាកល្បងនឹងចាប់ផ្តើមម្តងទៀតក្នុងរយៈពេល <xliff:g id="TIMEOUT">%1$s</xliff:g> វិនាទីទៀត…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"បោះបង់"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"កំណត់ឡើងវិញឥឡូវនេះ"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"កំណត់ដូចចេញពីរោងចក្រឡើងវិញដើម្បីប្រើឧបករណ៍នេះដោយគ្មានការរឹតបន្តឹង"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ប៉ះ ដើម្បីស្វែងយល់បន្ថែម។"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ដែលបានបិទដំណើរការ"</string>
<string name="conference_call" msgid="3751093130790472426">"ការហៅជាក្រុម"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 7f80a29..30d7e4e0 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ಈ ಪರದೆಯನ್ನು ಅನ್ಪಿನ್ ಮಾಡಲು, ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಂಂದೆ ಒತ್ತಿ ಹಿಡಿಯಿರಿ."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ಅಪ್ಲಿಕೇಶನ್ ಪಿನ್ ಮಾಡಲಾಗಿದೆ: ಈ ಸಾಧನದಲ್ಲಿ ಅನ್ಪಿನ್ ಮಾಡುವುದನ್ನು ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ಸ್ಕ್ರೀನ್ ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ನೀವು ಯಾವುದೇ ಬದಲಾವಣೆಗಳನ್ನು ಕಳೆದುಕೊಳ್ಳುತ್ತೀರಿ ಮತ್ತು <xliff:g id="TIMEOUT">%1$s</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಡೆಮೋ ಮತ್ತೆ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ರದ್ದುಮಾಡಿ"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ಈಗಲೇ ಮರುಹೊಂದಿಸು"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ನಿರ್ಬಂಧಗಳು ಇಲ್ಲದೆಯೇ ಈ ಸಾಧನವನ್ನು ಬಳಸಲು ಫ್ಯಾಕ್ಟರಿ ಮರುಹೊಂದಿಸಿ"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="conference_call" msgid="3751093130790472426">"ಕಾನ್ಫರೆನ್ಸ್ ಕರೆ"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 444c83d..dbb14890 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"이 화면을 고정 해제하려면 \'뒤로\'를 길게 터치합니다."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"앱이 고정되었습니다. 이 기기에서는 고정 해제를 허용하지 않습니다."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"화면 고정됨"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"변경사항이 사라지며 데모가 <xliff:g id="TIMEOUT">%1$s</xliff:g>초 후에 시작됩니다."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"취소"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"지금 초기화"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"제한 없이 기기를 사용하기 위한 초기화"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"자세한 내용을 보려면 터치하세요."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> 사용 중지됨"</string>
<string name="conference_call" msgid="3751093130790472426">"다자간 통화"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 2b592bd..3583189 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi тармагы жеткиликтүү</item>
<item quantity="one">Wi-Fi тармагы жеткиликтүү</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Бул экранды бошотуу үчүн \"Артка\" баскычын басып, кармап туруңуз."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Колдонмо кадалган: Бул түзмөктө бошотууга уруксат жок."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Экран кадалды"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Бардык өзгөртүүлөр жоголуп, демо режим <xliff:g id="TIMEOUT">%1$s</xliff:g> секунддан кийин кайра башталат…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Жокко чыгаруу"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Баштапкы абалга келтирүү"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Бул түзмөктү чектөөсүз колдонуу үчүн аны баштапкы абалга келтириңиз"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Көбүрөөк билүү үчүн тийип коюңуз."</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="8101791425834697618">"Калкып чыгуучу кеңеш"</string>
</resources>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 3a96743..baf6d51 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ກົດປຸ່ມກັບຄືນຄ້າງໄວ້ເພື່ອເຊົາປັກໝຸດໜ້າຈໍນີ້."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ແອັບຖືກປັກໝຸດແລ້ວ: ບໍ່ອະນຸຍາດໃຫ້ຖອນປັກໝຸດຢູ່ເທິງອຸປະກອນນີ້."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ປັກໝຸດໜ້າຈໍແລ້ວ"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ທ່ານຈະສູນເສຍການປ່ຽນແປງ ແລະ ເດໂມຈະເລີ່ມອີກຄັ້ງໃນອີກ <xliff:g id="TIMEOUT">%1$s</xliff:g> ວິນາທີ…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ຍົກເລີກ"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ຣີເຊັດດຽວນີ້"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ຣີເຊັດໃຫ້ເປັນຄ່າໂຮງງານເພື່ອໃຊ້ອຸປະກອນນີ້ໂດຍບໍ່ມີຂໍ້ຈຳກັດ"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ປິດການນຳໃຊ້ <xliff:g id="LABEL">%1$s</xliff:g> ແລ້ວ"</string>
<string name="conference_call" msgid="3751093130790472426">"ການປະຊຸມສາຍ"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d60a010..f9293c4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1618,6 +1618,10 @@
<string name="select_year" msgid="7952052866994196170">"Pasirinkite metus"</string>
<string name="deleted_key" msgid="7659477886625566590">"Ištrinta: <xliff:g id="KEY">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Kad atsegtumėte šį ekraną, palieskite ir palaikykite „Atgal“."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Programa prisegta: šiame įrenginyje negalima atsegti."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrano prisegtas"</string>
@@ -1753,8 +1757,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Prarasite visus pakeitimus, o demonstracinė versija bus paleista iš naujo po <xliff:g id="TIMEOUT">%1$s</xliff:g> sek…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Atšaukti"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nustatyti iš naujo dabar"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Atkurkite gamyklinius nustatymus, kad galėtumėte naudoti šį įrenginį be apribojimų"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Palieskite, kad sužinotumėte daugiau."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferencinis skambutis"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7afb2ce..04ea14e 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1591,6 +1591,10 @@
<string name="select_year" msgid="7952052866994196170">"Atlasiet gadu."</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> tika dzēsts."</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Lai atspraustu šo ekrānu, pieskarieties pogai “Atpakaļ” un turiet to."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Lietotne ir piesprausta. Atspraušana šajā ierīcē nav atļauta."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrāns ir piesprausts"</string>
@@ -1717,8 +1721,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Pēc <xliff:g id="TIMEOUT">%1$s</xliff:g> sekundēm zaudēsiet visas izmaiņas un tiks atkārtoti palaista demonstrācija..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Atcelt"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Atiestatīt tūlīt"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Rūpnīcas datu atiestatīšana ierīces neierobežotai izmantošanai"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pieskarieties, lai uzzinātu vairāk."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferences zvans"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 139e02a..aeb0c41 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi мрежи се достапни</item>
<item quantity="other">Wi-Fi мрежи се достапни</item>
@@ -1566,6 +1562,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"За откачување на екранов, допрете и задржете Назад."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Апликацијата е закачена: откачување не е дозволено на уредов."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екранот е закачен"</string>
@@ -1683,8 +1683,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ќе ги изгубите измените и демонстрацијата ќе започне повторно по <xliff:g id="TIMEOUT">%1$s</xliff:g> секунди…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Откажи"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ресетирај сега"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетирајте до фабричките поставки за уредов да го користите без ограничувања"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Допрете за да дознаете повеќе."</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="8101791425834697618">"Појавен прозорец на совет за алатка"</string>
</resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index fc3eb40..4193079 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ഈ സ്ക്രീൻ അൺപിൻ ചെയ്യാൻ, ബാക്ക് ബട്ടൺ സ്പർശിച്ച് പിടിക്കുക"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"അപ്ലിക്കേഷൻ പിൻ ചെയ്തു: ഈ ഉപകരണത്തിൽ അൺപിൻ ചെയ്യാനാവില്ല."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"സ്ക്രീൻ പിൻ ചെയ്തു"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"മാറ്റങ്ങളെല്ലാം നിങ്ങൾക്ക് നഷ്ടപ്പെടും, <xliff:g id="TIMEOUT">%1$s</xliff:g> സെക്കൻഡിൽ ഡെമോ വീണ്ടും തുടങ്ങും…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"റദ്ദാക്കുക"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ഇപ്പോൾ പുനക്രമീകരിക്കുക"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"നിയന്ത്രണങ്ങൾ ഇല്ലാതെ ഈ ഉപകരണം ഉപയോഗിക്കാൻ ഫാക്ടറി റീസെറ്റ് നടത്തുക"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"കൂടുതലറിയുന്നതിന് സ്പർശിക്കുക."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="conference_call" msgid="3751093130790472426">"കോൺഫറൻസ് കോൾ"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 2faf163..74006da 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Энэ дэлгэцийг эхэнд нээхийг болиулахын тулд Буцах товчлуурыг дараад, хүлээнэ үү."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App-ыг тусгайлан тэмдэглэсэн байна: Энэ төхөөрөмж дээр тусгайлан тэмдэглэсэн сонголтыг устгах боломжгүй."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Дэлгэцийг тогтоосон"</string>
@@ -1679,8 +1683,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Таны хийсэн өөрчлөлтийг хадгалахгүй бөгөөд жишээ <xliff:g id="TIMEOUT">%1$s</xliff:g> секундын дотор дахин эхлэх болно..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Цуцлах"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Одоо шинэчлэх"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Энэ төхөөрөмжийг хязгаарлалтгүй ашиглахын тулд үйлдвэрийн тохиргоонд дахин тохируулна уу"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Дэлгэрэнгүй үзэх бол дарна уу."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>-г цуцалсан"</string>
<string name="conference_call" msgid="3751093130790472426">"Хурлын дуудлага"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 99465cc..dd99f15 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ही स्क्रीन अनपिन करण्यासाठी, परत ला स्पर्श करा आणि धरून ठेवा."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अॅप पिन केलेला आहे: या डिव्हाइसवर अनपिन करण्यास अनुमती नाही."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"आपण कोणतेही बदल गमवाल आणि डेमो पुन्हा <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकंदांमध्ये प्रारंभ होईल..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"रद्द करा"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"आता रीसेट करा"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"हे डिव्हाइस निर्बंधांशिवाय वापरण्यासाठी फॅक्टरी रीसेट करा"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जाणून घेण्यासाठी स्पर्श करा."</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="8101791425834697618">"टूलटिप पॉपअप"</string>
</resources>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1e7e281..57edab8 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dipadamkan"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Untuk menyahsematkan skrin ni, ketik & tahan Kembali."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Apl disemat: Nyahsemat tidak dibenarkan pada peranti ini."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skrin disemat"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Anda akan kehilangan sebarang perubahan yang dibuat dan tunjuk cara akan dimulakan sekali lagi dalam masa <xliff:g id="TIMEOUT">%1$s</xliff:g> saat…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Batal"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Tetapkan semula sekarang"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Lakukan tetapan semula kilang untuk menggunakan peranti ini tanpa sekatan"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ketik untuk mengetahui lebih lanjut."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
<string name="conference_call" msgid="3751093130790472426">"Panggilan Sidang"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 99d6423..834a665 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1059,16 +1059,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်</item>
<item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်</item>
@@ -1564,6 +1560,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ဤမျက်နှာပြင်ကို ပင်ဖြုတ်ရန် \"နောက်သို့\" ကိုထိပြီးဖိထားပါ။"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"အက်ပ်ကို ပင်ထိုးထားသည်။ ပင်ဖျက်ခြင်းကို ဒီစက်မှာ မရနိုင်ပါ။"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"မျက်နှာပြင်ကို ပင်ထိုးထား"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ပြောင်းလဲမှုများကို ဆုံးရှုံးသွားမည်ဖြစ်ပြီး သရုပ်ပြချက်သည် <xliff:g id="TIMEOUT">%1$s</xliff:g> စက္ကန့်အတွင်း ပြန်လည်စတင်ပါမည်…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"မလုပ်တော့"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ယခုပြန်လည်သတ်မှတ်ပါ"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ဤစက်ပစ္စည်းကို ကန့်သတ်ချက်များမပါဘဲ အသုံးပြုရန် စက်ရုံထုတ်ဆက်တင်အတိုင်း ပြန်လည်သတ်မှတ်ပါ"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ပိုမိုလေ့လာရန် တို့ပါ။"</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="8101791425834697618">"အကြံပြုချက်ပြ ပေါ့အပ်ဝင်းဒိုး"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 324f0d7..61e74a2 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Medievolum"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Varslingsvolum"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Standard ringetone"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringelyder"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyder"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Varsellyder"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Ukjent"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi-nettverk er tilgjengelig</item>
<item quantity="one">Wi-Fi-nettverk er tilgjengelig</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Velg året"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"For å løsne denne skjermen, trykk og hold inne Tilbake."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen er festet – du kan ikke løsne apper på denne enheten."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skjermen er festet"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Du mister eventuelle endringer, og demoen starter på nytt om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Avbryt"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Tilbakestill nå"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Tilbakestill til fabrikkstandard for å bruke denne enheten uten begrensninger"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Trykk for å finne ut mer."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferansesamtale"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Verktøytips i forgrunnen"</string>
</resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index caf3688..d6c8612 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -1065,16 +1065,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
<item quantity="one">Wi-Fi सञ्जाल उपलब्ध छ</item>
@@ -1570,6 +1566,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"यस स्क्रिनलाई अनपिन गर्न पछाडि बटनलाई छोइराख्नुहोस्।"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अनुप्रयोग पिन गरियो: यस यन्त्रमा अनपिन गर्ने अनुमति छैन।"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रिन पिन गरियो"</string>
@@ -1687,8 +1687,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"तपाईँ सबै परिवर्तनहरू गुमाउनु हुनेछ र <xliff:g id="TIMEOUT">%1$s</xliff:g> सेकेन्डमा डेमो फेरि सुरु हुनेछ…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"रद्द गर्नुहोस्"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"अहिले रिसेट गर्नुहोस्"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"यस यन्त्रलाई सीमितताहरू बिना प्रयोग गर्नका लागि फ्याक्ट्री रिसेट गर्नुहोस्"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"थप जान्नका लागि छुनुहोस्।"</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="8101791425834697618">"उपकरणको वर्णन गर्ने पपअप"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 0848304..f7c76cd 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolume"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Meldingsvolume"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Standaardbeltoon"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standaard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Geen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Beltonen"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmgeluiden"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meldingsgeluiden"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wifi-netwerken beschikbaar</item>
<item quantity="one">Wifi-netwerk beschikbaar</item>
@@ -1530,8 +1526,8 @@
<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">"Onbekend portret"</string>
- <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend landschap"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend staand"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend liggend"</string>
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
<string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van content"</string>
<string name="reason_unknown" msgid="6048913880184628119">"onbekend"</string>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Jaar selecteren"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> verwijderd"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Tik op Terug en houd vast om dit scherm los te maken."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"App is vastgezet: losmaken is niet toegestaan op dit apparaat."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Scherm vastgezet"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Je wijzigingen gaan verloren. De demo wordt opnieuw gestart over <xliff:g id="TIMEOUT">%1$s</xliff:g> seconden…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Annuleren"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Nu resetten"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Zet dit apparaat terug op de fabrieksinstellingen om het zonder beperkingen te gebruiken"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tik voor meer informatie."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonische vergadering"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up met knopinfo"</string>
</resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 3e886bc..39c5dfa 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ਇਸ ਸਕ੍ਰੀਨ ਨੂੰ ਅਨਪਿੰਨ ਕਰਨ ਲਈ, ਸਪਰਸ਼ ਕਰੋ & ਦਬਾਈ ਰੱਖੋ।"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ਐਪ ਪਿੰਨਡ ਹੈ: ਇਸ ਡੀਵਾਈਸ ਤੇ ਅਨਪਿਨ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਹੈ।"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ਤੁਸੀਂ ਕਿਸੇ ਵੀ ਤਬਦੀਲੀਆਂ ਨੂੰ ਗੁਆ ਬੈਠੋਂਗੇ ਅਤੇ ਡੈਮੋ <xliff:g id="TIMEOUT">%1$s</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਚਾਲੂ ਕੀਤਾ ਜਾਵੇਗਾ…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ਰੱਦ ਕਰੋ"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ਹੁਣੇ ਮੁੜ-ਸੈੱਟ ਕਰੋ"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬਿਨਾਂ ਪਾਬੰਦੀਆਂ ਦੇ ਵਰਤਣ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ਹੋਰ ਜਾਣਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"ਕਾਨਫਰੰਸ ਕਾਲ"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 92a2e2a..4ffd963 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1105,16 +1105,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Głośność multimediów"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Głośność powiadomień"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Dzwonek domyślny"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Domyślny (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Brak"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Dzwonki"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Dźwięki alarmu"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Dźwięki powiadomień"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Nieznany"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="few">Dostępne są sieci Wi-Fi</item>
<item quantity="many">Dostępne są sieci Wi-Fi</item>
@@ -1618,6 +1614,10 @@
<string name="select_year" msgid="7952052866994196170">"Wybierz rok"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> usunięte"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Aby odpiąć ten ekran, naciśnij i przytrzymaj Wstecz."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacja jest przypięta. Nie możesz jej odpiąć na tym urządzeniu."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran przypięty"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Stracisz wszystkie wprowadzone zmiany, a tryb demo uruchomi się ponownie za <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anuluj"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetuj teraz"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Aby używać tego urządzenia bez ograniczeń, przywróć ustawienia fabryczne"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Kliknij, by dowiedzieć się więcej."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Połączenie konferencyjne"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Wyskakujące okno z etykietką"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index bf9e15d..482c1e9 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Redes Wi-Fi disponíveis</item>
<item quantity="other">Redes Wi-Fi disponíveis</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Para liberar esta tela, toque no botão \"Voltar\" e mantenha-o pressionado."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"O app está fixado. A liberação não é permitida neste dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Você perderá todas as alterações. A demonstração será iniciada novamente em <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de dica"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e09daa5..3f9417e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume de multimédia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume de notificações"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Toque predefinido"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predefinição (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Nada"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarme"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Redes Wi-Fi disponíveis</item>
<item quantity="one">Rede Wi-Fi disponível</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Selecionar ano"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Para soltar este ecrã, toque sem soltar em Anterior."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"A aplicação está fixa: não é permitido soltá-la neste dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ecrã fixo"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Perderá todas as alterações e a demonstração começará novamente dentro de <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Repor agora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Repor os dados de fábrica para utilizar o dispositivo sem restrições"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferência"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de sugestão"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index bf9e15d..482c1e9 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Volume da mídia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Volume da notificação"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Toque padrão"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Padrão (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Nenhum"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Toques"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Redes Wi-Fi disponíveis</item>
<item quantity="other">Redes Wi-Fi disponíveis</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Para liberar esta tela, toque no botão \"Voltar\" e mantenha-o pressionado."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"O app está fixado. A liberação não é permitida neste dispositivo."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Tela fixada"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Você perderá todas as alterações. A demonstração será iniciada novamente em <xliff:g id="TIMEOUT">%1$s</xliff:g> segundos…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Cancelar"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Reiniciar agora"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
<string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Pop-up de dica"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7f96d2e..5735f7c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1591,6 +1591,10 @@
<string name="select_year" msgid="7952052866994196170">"Selectați anul"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> a fost șters"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Pentru a anula fixarea acestui ecran, atingeți lung opțiunea Înapoi."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplicația este fixată: Anularea fixării nu este permisă pe acest dispozitiv."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ecran fixat"</string>
@@ -1717,8 +1721,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Veți pierde toate modificările, iar demonstrația va începe din nou peste <xliff:g id="TIMEOUT">%1$s</xliff:g> secunde…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anulați"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetați acum"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Reveniți la setările din fabrică pentru a folosi acest dispozitiv fără restricții"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Atingeți pentru a afla mai multe."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
<string name="conference_call" msgid="3751093130790472426">"Conferință telefonică"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9e25bb7..0d6ca06 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1105,16 +1105,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Есть доступные сети Wi-Fi</item>
<item quantity="few">Есть доступные сети Wi-Fi</item>
@@ -1618,6 +1614,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Чтобы открепить экран, нажмите и удерживайте кнопку \"Назад\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Включена блокировка в приложении. Ее отключение запрещено правилами организации."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Блокировка включена"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Все изменения будут утеряны. Деморежим будет перезапущен через <xliff:g id="TIMEOUT">%1$s</xliff:g> сек."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Отмена"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Сбросить"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Сброс до заводских настроек для работы без ограничений"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Нажмите, чтобы узнать больше."</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="8101791425834697618">"Подсказка"</string>
</resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index b106464..7526c1e 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -108,7 +108,7 @@
<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="roamingText0" msgid="7170335472198694945">"රෝමිං දර්ශකය ක්රියාත්මකයි"</string>
<string name="roamingText1" msgid="5314861519752538922">"රෝමිං දර්ශකය අක්රියයි"</string>
<string name="roamingText2" msgid="8969929049081268115">"රෝමිං දර්ශකය සැණෙලි වෙයි"</string>
<string name="roamingText3" msgid="5148255027043943317">"වටපිටාවෙන් ඉවත්ව"</string>
@@ -189,7 +189,7 @@
<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="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>
@@ -213,7 +213,7 @@
<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_power_off" msgid="4471879440839879722">"බල රහිත කරන්න"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
<string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
@@ -228,7 +228,7 @@
</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_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>
@@ -975,7 +975,7 @@
<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="whichEditApplicationLabel" msgid="7183524181625290300">"සංස්කරණය"</string>
<string name="whichSendApplication" msgid="6902512414057341668">"සමඟ බෙදාගන්න"</string>
<string name="whichSendApplicationNamed" msgid="2799370240005424391">"%s සමඟ බෙදාගන්න"</string>
<string name="whichSendApplicationLabel" msgid="4579076294675975354">"බෙදා ගන්න"</string>
@@ -1104,7 +1104,7 @@
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ඍජු Wi-Fi"</string>
<string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ඍජු Wi-Fi ආරම්භ කරන්න. මෙය Wi-Fi සේවාදායක/හොට්ස්පොට් එක අක්රිය කරනු ඇත."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ඍජු Wi-Fi ආරම්භ කළ නොහැක."</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ඍජු සම්බන්ධතාව සක්රියයි"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ක්රියාත්මකයි"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"සැකසීම් සඳහා තට්ටු කරන්න"</string>
<string name="accept" msgid="1645267259272829559">"පිළිගන්න"</string>
<string name="decline" msgid="2112225451706137894">"ප්රතික්ෂේප කරන්න"</string>
@@ -1336,7 +1336,7 @@
<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>
+ <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>
@@ -1382,7 +1382,7 @@
<string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</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="wireless_display_route_description" msgid="9070346425023979651">"නොරැහැන් සංදර්ශකය"</string>
<string name="media_route_button_content_description" msgid="591703006349356016">"Cast"</string>
<string name="media_route_chooser_title" msgid="1751618554539087622">"උපාංගයට සම්බන්ධ වන්න"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"තිරය උපාංගයට යොමු කරන්න"</string>
@@ -1566,6 +1566,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"මෙම තිරය ඇමුණුම් ඉවත් කිරීමට, ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"යෙදුම අමුණා ඇත: ගැලවීමට මෙම උපාංගය මත ඉඩ දිය නොහැකිය."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"තිරය අගුළු දමා ඇත"</string>
@@ -1614,7 +1618,7 @@
</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>
- <string name="zen_mode_forever" msgid="7420011936770086993">"ඔබ මෙය අක්රිය කරන තුරු"</string>
+ <string name="zen_mode_forever" msgid="7420011936770086993">"ඔබ මෙය ක්රියාවිරහිත කරන තුරු"</string>
<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>
@@ -1683,8 +1687,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"ඔබට යම් වෙනස් කිරීම් අහිමි වනු ඇති අතර ආදර්ශනය තත්පර <xliff:g id="TIMEOUT">%1$s</xliff:g>කින් නැවත ආරම්භ වනු ඇත…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"අවලංගු කරන්න"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"දැන් යළි සකසන්න"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"සීමා කිරීම්වලින් තොරව මෙම උපාංගය භාවිත කිරීමට කර්මාන්ත ශාලා යළි සැකසීම"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"තව දැන ගැනීමට ස්පර්ශ කරන්න."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"අබල කළ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"සම්මන්ත්රණ ඇමතුම"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 50af3cc..7ff3ce2 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1105,16 +1105,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Hlasitosť médií"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Hlasitosť upozornení"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Predvolený tón zvonenia"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Predvolený (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Žiadny"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Tóny zvonenia"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíka"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornení"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Neznáme"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="few">K dispozícii sú siete Wi-Fi</item>
<item quantity="many">K dispozícii sú siete Wi-Fi</item>
@@ -1618,6 +1614,10 @@
<string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
<string name="deleted_key" msgid="7659477886625566590">"Číslo <xliff:g id="KEY">%1$s</xliff:g> bolo odstránené"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Ak chcete uvoľniť túto obrazovku, klepnite na tlačidlo Späť a podržte ho."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikácia je pripnutá. Uvoľnenie nie je na tomto zariadení povolené."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Obrazovka bola pripnutá"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Prídete o všetky zmeny a ukážka sa znova spustí o <xliff:g id="TIMEOUT">%1$s</xliff:g> s…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Zrušiť"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Resetovať"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Ak chcete toto zariadenie používať bez obmedzení, obnovte na ňom továrenské nastavenia"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím získate ďalšie informácie."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenčný hovor"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Kontextové okno s popisom"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5bc756b..f7b8096 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -656,7 +656,7 @@
<string name="relationTypeMother" msgid="4578571352962758304">"Mati"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"Starši"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
- <string name="relationTypeReferredBy" msgid="101573059844135524">"Predlagatelj:"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"Predlagatelj"</string>
<string name="relationTypeRelative" msgid="1799819930085610271">"Sorodnik"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Zakonski partner"</string>
@@ -1618,6 +1618,10 @@
<string name="select_year" msgid="7952052866994196170">"Izberite leto"</string>
<string name="deleted_key" msgid="7659477886625566590">"Številka <xliff:g id="KEY">%1$s</xliff:g> je izbrisana"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Če želite odpeti ta zaslon, se dotaknite tipke za nazaj in jo pridržite."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je pripeta: v tej napravi odpenjanje ni dovoljeno."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Zaslon je pripet"</string>
@@ -1753,8 +1757,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Morebitne spremembe bodo izgubljene in predstavitev se bo začela znova čez <xliff:g id="TIMEOUT">%1$s</xliff:g> s …"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Prekliči"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ponastavi"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Ponastavitev naprave na tovarniške nastavitve za uporabo brez omejitev"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dotaknite se, če želite izvedeti več."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenčni klic"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 1095088..c3ccaca 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Përzgjidh vitin"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> u fshi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Puna <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Për të hequr gozhdimin e ekranit, prek dhe mbaj të shtypur \"Prapa\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ekrani është i gozhduar. Anulimi i mbërthimit nuk lejohet nga organizata jote."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekrani u gozhdua"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Do të humbasësh çdo ndryshim dhe demonstrimi do të niset përsëri për <xliff:g id="TIMEOUT">%1$s</xliff:g> sekonda…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Anulo"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Rivendos tani"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Rivendos cilësimet e fabrikës për ta përdorur këtë pajisje pa kufizime"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Prek për të mësuar më shumë."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
<string name="conference_call" msgid="3751093130790472426">"Telefonatë konferencë"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 27d7cad..da44a65 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1082,16 +1082,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Wi-Fi мреже су доступне</item>
<item quantity="few">Wi-Fi мреже су доступне</item>
@@ -1591,6 +1587,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Да бисте откачили овај екран, додирните и задржите Назад."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Апликација је закачена: откачињање није дозвољено на овом уређају."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екран је закачен"</string>
@@ -1717,8 +1717,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Изгубићете све промене и демонстрација ће поново почети за <xliff:g id="TIMEOUT">%1$s</xliff:g> сек…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Откажи"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Ресетуј"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетујте уређај на фабричка подешавања да бисте га користили без ограничења"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Додирните да бисте сазнали више."</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="8101791425834697618">"Искачуће објашњење"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b048762..1bf5196 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Mediavolym"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Meddelandevolym"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Standardringsignal"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standard (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ingen"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringsignaler"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ljud för alarm"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Aviseringsljud"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Okänt"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi-nätverk är tillgängliga</item>
<item quantity="one">Wi-Fi-nätverk är tillgängligt</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Välj år"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> har tagits bort"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Om du vill lossa skärmen trycker du länge på Tillbaka."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Appen är fäst. Att lossa den är inte tillåtet på den här enheten."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skärmen är fäst"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ändringar som du har gjort sparas inte och demon börjar om om <xliff:g id="TIMEOUT">%1$s</xliff:g> sekunder …"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Avbryt"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Återställ nu"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Återställ enheten till standardinställningarna om du vill använda den utan begränsningar"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryck här om du vill läsa mer."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferenssamtal"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Popup-fönster med beskrivning"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6cfd253..1d3c7ac 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1057,16 +1057,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Sauti ya midia"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Sauti ya arifa"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Mlio chaguo-msingi"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Chaguo-msingi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Hamna"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Toni za mlio"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sauti za kengele"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sauti za arifa"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Haijulikani"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Mitandao ya Wi-Fi inapatikana</item>
<item quantity="one">Mtandao wa Wi-Fi unapatikana</item>
@@ -1562,6 +1558,10 @@
<string name="select_year" msgid="7952052866994196170">"Chagua mwaka"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> kimefutwa"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Ili kubandua skrini hii, gusa na ushikilie Nyuma."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Programu imebanwa: Kubanuliwa hakuruhusiwi kwenye kifaa hiki."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Skrini imebandikwa"</string>
@@ -1679,8 +1679,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Mabadiliko yoyote hayatahifadhiwa. Onyesho litaanza tena baada ya sekunde <xliff:g id="TIMEOUT">%1$s</xliff:g>..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Ghairi"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Weka upya sasa"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Rejesha mipangilio iliyotoka nayo kiwandani ili utumie kifaa hiki bila vikwazo"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Gusa ili kupata maelezo zaidi."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
<string name="conference_call" msgid="3751093130790472426">"Simu ya Kongamano"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Kidirisha Ibukizi cha vidokezo"</string>
</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index b391912..46a4589 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"இந்தத் திரையை விலக்க, \"முந்தையது\" பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"பயன்பாடு பொருத்தப்பட்டது: பொருத்தியதை நீக்குவதற்கு இந்தச் சாதனத்தில் அனுமதியில்லை."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"திரை பின் செய்யப்பட்டது"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"மாற்றங்கள் சேமிக்கப்படாது, <xliff:g id="TIMEOUT">%1$s</xliff:g> வினாடிகளில் டெமோ மீண்டும் தொடங்கும்…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ரத்துசெய்"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"இப்போதே மீட்டமை"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"இந்தச் சாதனத்தைக் கட்டுப்பாடுகளின்றிப் பயன்படுத்த, ஆரம்ப நிலைக்கு மீட்டமைக்கவும்"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"மேலும் அறிய தொடவும்."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"முடக்கப்பட்டது: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"குழு அழைப்பு"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 5ec586f..c6722ee 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"ఈ స్క్రీన్ని అన్పిన్ చేయడానికి, వెనుకకు తాకి & అలాగే పట్టుకోండి."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"అనువర్తనం పిన్ చేయబడింది: ఈ పరికరంలో అన్పిన్ చేయడానికి అనుమతి లేదు."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"స్క్రీన్ పిన్ చేయబడింది"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"మీరు చేసిన ఏవైనా మార్పులను కోల్పోతారు మరియు డెమో <xliff:g id="TIMEOUT">%1$s</xliff:g> సెకన్లలో మళ్లీ ప్రారంభమవుతుంది…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"రద్దు చేయి"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ఇప్పుడే రీసెట్ చేయి"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"ఈ పరికరాన్ని ఎటువంటి పరిమితులు లేకుండా ఉపయోగించడానికి ఫ్యాక్టరీ రీసెట్ చేయండి"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"మరింత తెలుసుకోవడానికి తాకండి."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> నిలిపివేయబడింది"</string>
<string name="conference_call" msgid="3751093130790472426">"కాన్ఫరెన్స్ కాల్"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 15cbd94..ab04bec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" ค้างไว้"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"มีการตรึงแอป: ไม่อนุญาตให้เลิกตรึงบนอุปกรณ์นี้"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"ตรึงหน้าจอแล้ว"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"การเปลี่ยนแปลงของคุณจะหายไปและการสาธิตจะเริ่มต้นอีกครั้งใน <xliff:g id="TIMEOUT">%1$s</xliff:g> วินาที…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"ยกเลิก"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"รีเซ็ตทันที"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อใช้อุปกรณ์นี้โดยไร้ข้อจำกัด"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"แตะเพื่อเรียนรู้เพิ่มเติม"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"ปิดใช้ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"การประชุมสาย"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 31666ee..e7cec56 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Pumili ng taon"</string>
<string name="deleted_key" msgid="7659477886625566590">"Tinanggal ang <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> sa Trabaho"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Naka-pin ang app: Hindi pinapayagan ang pag-a-unpin sa device na ito."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Naka-pin ang screen"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Mawawala mo ang anumang mga pagbabago at magsisimulang muli ang demo pagkalipas ng <xliff:g id="TIMEOUT">%1$s</xliff:g> (na) segundo…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Kanselahin"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"I-reset ngayon"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"I-factory reset upang magamit ang device na ito nang walang mga paghihigpit"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pindutin upang matuto nang higit pa."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0126068..59dc68e 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Yılı seçin"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Bu ekranın sabitlemesini kaldırmak için Geri\'ye dokunup basılı tutun."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Uygulama sabitlendi. Bu cihazda sabitlemenin kaldırılmasına izin verilmiyor."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran sabitlendi"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Değişiklikleri kaybedeceksiniz ve demo <xliff:g id="TIMEOUT">%1$s</xliff:g> saniye içinde tekrar başlayacak…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"İptal"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Şimdi sıfırla"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı kısıtlama olmadan kullanmak için fabrika ayarlarına sıfırlayın"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha fazla bilgi edinmek için dokunun."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferans Çağrısı"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 104badd..0ac3b80 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1105,16 +1105,12 @@
<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>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <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>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <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">Мережі Wi-Fi доступні</item>
<item quantity="few">Мережі Wi-Fi доступні</item>
@@ -1618,6 +1614,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Щоб відкріпити цей екран, натисніть і утримуйте кнопку \"Назад\"."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Додаток закріплено. Його не можна відкріпити на цьому пристрої."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Екран закріплено"</string>
@@ -1753,8 +1753,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Ви втратите всі зміни, а демонстрація знову почнеться через <xliff:g id="TIMEOUT">%1$s</xliff:g> с…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Скасувати"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Скинути"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Відновіть заводські параметри, щоб використовувати пристрій без обмежень"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Торкніться, щоб дізнатися більше."</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="8101791425834697618">"Спливаюча підказка"</string>
</resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index f8224f2..715dbed 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"اس اسکرین سے پن ہٹانے کیلئے، پیچھے کو تھپتھپائیں اور دبا کر رکھیں۔"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"ایپ کو پن کر دیا گیا ہے: اس آلہ پر پن ہٹانے کی اجازت نہیں ہے۔"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"اسکرین کو پن کر دیا گیا"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"آپ کی تمام تبدیلیاں ضائع ہو جائیں گی اور ڈیمو <xliff:g id="TIMEOUT">%1$s</xliff:g> سیکنڈز میں دوبارہ شروع ہوگا…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"منسوخ کریں"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"ابھی ری سیٹ کریں"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"بغیر کسی حدود کے استعمال کرنے کیلئے اس آلے کو فیکٹری ری سیٹ کریں"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"مزید جاننے کیلئے ٹچ کریں۔"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"غیر فعال کردہ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"کانفرنس کال"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 78b5400..255982c 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Multimedia ovozi"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Eslatma tovushi"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Standart rington"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Standart (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Yo‘q"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Ringtonlar"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Signal ovozlari"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirishnoma ovozlari"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Noma’lum"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="other">Wi-Fi tarmoqlari aniqlandi</item>
<item quantity="one">Wi-Fi tarmog‘i aniqlandi</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Yilni tanlash"</string>
<string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> raqami o‘chirib tashlandi"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Bu ekrandan chiqish uchun “Orqaga” tugmasini bosib turing."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ilova qadab qo‘yilgan. Uni ekrandan yechish ushbu qurilmada ta’qiqlangan."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Ekran qadab qo‘yildi"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Har qanday o‘zgarishlar o‘chib ketadi va demo <xliff:g id="TIMEOUT">%1$s</xliff:g> soniyadan so‘ng yana qayta ishga tushadi…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Bekor qilish"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Asl holatga qaytarish"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu qurilmadan cheklovlarsiz foydalanish uchun zavod sozlamalarini tiklang"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ko‘proq o‘rganish uchun bosing."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
<string name="conference_call" msgid="3751093130790472426">"Konferens-aloqa"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Qalqib chiquvchi maslahat oynasi"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ca5e3bc..1f6a1cd 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1564,6 +1564,10 @@
<string name="select_year" msgid="7952052866994196170">"Chọn năm"</string>
<string name="deleted_key" msgid="7659477886625566590">"Đã xóa <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> làm việc"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Để bỏ ghim màn hình này, nhấn và giữ Quay lại."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Ứng dụng được ghim: Không được phép bỏ ghim trên thiết bị này."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Đã ghim màn hình"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Bạn sẽ bị mất mọi thay đổi và bản trình diễn sẽ bắt đầu lại sau <xliff:g id="TIMEOUT">%1$s</xliff:g> giây…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Hủy"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Đặt lại ngay bây giờ"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Khôi phục cài đặt gốc để sử dụng thiết bị này mà không bị hạn chế"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Chạm để tìm hiểu thêm."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"Cuộc gọi nhiều bên"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 2126d12..5991f54 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"要取消固定此屏幕,请触摸并按住“返回”按钮。"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"应用处于固定状态:在此设备上不允许退出该模式。"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"已固定屏幕"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"您将丢失所有更改,而且演示模式将在 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒后重新启动…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重置"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"恢复出厂设置即可正常使用此设备,不受任何限制"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"触摸即可了解详情。"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"电话会议"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index bdd9fe3..7191a3d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1240,7 +1240,7 @@
<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">"虛擬現實接聽器"</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">"VPN 已啟用。"</string>
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"如要取消固定這個畫面,請按住 [返回]。"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"應用程式已固定:不允許在此裝置上取消固定。"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"螢幕已固定"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"系統將不會儲存變更,示範將於 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後重新開始…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重設"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"將此裝置回復至原廠設定後,使用將不受限制"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸以瞭解詳情。"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"「<xliff:g id="LABEL">%1$s</xliff:g>」已停用"</string>
<string name="conference_call" msgid="3751093130790472426">"會議通話"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 3c2146b..9e37672 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1564,6 +1564,10 @@
<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>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"如要取消固定這個畫面,請按住「返回」按鈕。"</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"應用程式已固定:無法在這部裝置取消固定。"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"已固定螢幕"</string>
@@ -1681,8 +1685,8 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"系統不會儲存您所做的變更,示範模式將於 <xliff:g id="TIMEOUT">%1$s</xliff:g> 秒後重新開始…"</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"取消"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"立即重設"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"恢復原廠設定即可正常使用這個裝置"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸即可瞭解詳情。"</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="conference_call" msgid="3751093130790472426">"電話會議"</string>
+ <!-- no translation found for tooltip_popup_title (8101791425834697618) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 011e4f7..66d1010 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1059,16 +1059,12 @@
<string name="volume_icon_description_media" msgid="4217311719665194215">"Ivolumu yemidiya"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Ivolumu yesaziso"</string>
<string name="ringtone_default" msgid="3789758980357696936">"Iringithoni emisiwe"</string>
- <!-- no translation found for ringtone_default_with_actual (1767304850491060581) -->
- <skip />
+ <string name="ringtone_default_with_actual" msgid="1767304850491060581">"Okuzenzakalelayo (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Akunalutho"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Amaringithoni"</string>
- <!-- no translation found for ringtone_picker_title_alarm (6473325356070549702) -->
- <skip />
- <!-- no translation found for ringtone_picker_title_notification (4837740874822788802) -->
- <skip />
- <!-- no translation found for ringtone_unknown (3914515995813061520) -->
- <skip />
+ <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Imisindo ye-alamu"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Imisindo yezaziso"</string>
+ <string name="ringtone_unknown" msgid="3914515995813061520">"Akwaziwa"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">Amanethiwekhi we-Wi-Fi ayatholakala</item>
<item quantity="other">Amanethiwekhi we-Wi-Fi ayatholakala</item>
@@ -1564,6 +1560,10 @@
<string name="select_year" msgid="7952052866994196170">"Khetha unyaka"</string>
<string name="deleted_key" msgid="7659477886625566590">"I-<xliff:g id="KEY">%1$s</xliff:g> isusiwe"</string>
<string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+ <!-- no translation found for managed_profile_label_badge_2 (5048136430082124036) -->
+ <skip />
+ <!-- no translation found for managed_profile_label_badge_3 (2808305070321719040) -->
+ <skip />
<string name="lock_to_app_toast" msgid="1420543809500606964">"Ukuze ususe ukuphina lesi sikrini, thinta futhi ubambe okuthi Emuva."</string>
<string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Uhlelo lokusebenza luphiniwe: Ukususa ukuphina akuvunyelwe kule divayisi."</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"Isikrini siphiniwe"</string>
@@ -1681,8 +1681,7 @@
<string name="demo_user_inactivity_timeout_countdown" msgid="5675588824402569506">"Uzolahlekelwa inoma iluphi ushintsho futhi idemo izoqala futhi kumasekhondi angu-<xliff:g id="TIMEOUT">%1$s</xliff:g>..."</string>
<string name="demo_user_inactivity_timeout_left_button" msgid="5314271347014802475">"Khansela"</string>
<string name="demo_user_inactivity_timeout_right_button" msgid="5019306703066964808">"Setha kabusha manje"</string>
- <string name="audit_safemode_notification" msgid="6416076898350685856">"Setha kabusha ukuze usebenzise idivayisi ngaphandle kwemikhawulo"</string>
- <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Thinta ukuze ufunde kabanzi."</string>
<string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
<string name="conference_call" msgid="3751093130790472426">"Ikholi yengqungquthela"</string>
+ <string name="tooltip_popup_title" msgid="8101791425834697618">"Okuzivelelayo kwe-tooltip"</string>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 95f372c..7045eaf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2239,13 +2239,23 @@
(black). -->
<attr name="background" format="reference|color" />
- <!-- Sets the padding, in pixels, of all four edges. Padding is defined as
- space between the edges of the view and the view's content. A views size
- will include it's padding. If a {@link android.R.attr#background}
+ <!-- Sets the padding, in pixels, of all four edges. Padding is defined as
+ space between the edges of the view and the view's content. This value will take
+ precedence over any of the edge-specific values, including
+ paddingHorizontal and paddingVertical, if set. A view's size
+ will include its padding. If a {@link android.R.attr#background}
is provided, the padding will initially be set to that (0 if the
- drawable does not have padding). Explicitly setting a padding value
+ drawable does not have padding). Explicitly setting a padding value
will override the corresponding padding found in the background. -->
<attr name="padding" format="dimension" />
+ <!-- Sets the padding, in pixels, of the left and right edges; see
+ {@link android.R.attr#padding}. This value will take precedence over
+ paddingLeft, paddingRight, paddingStart, and paddingEnd, if set. -->
+ <attr name="paddingHorizontal" format="dimension" />
+ <!-- Sets the padding, in pixels, of the top and bottom edges; see
+ {@link android.R.attr#padding}. This value will take precedence over
+ paddingTop and paddingBottom, if set. -->
+ <attr name="paddingVertical" format="dimension" />
<!-- Sets the padding, in pixels, of the left edge; see {@link android.R.attr#padding}. -->
<attr name="paddingLeft" format="dimension" />
<!-- Sets the padding, in pixels, of the top edge; see {@link android.R.attr#padding}. -->
@@ -3059,7 +3069,11 @@
<attr name="layout_width" />
<attr name="layout_height" />
<!-- Specifies extra space on the left, top, right and bottom
- sides of this view. This space is outside this view's bounds.
+ sides of this view. If both layout_margin and any of layout_marginLeft,
+ layout_marginRight, layout_marginStart, layout_marginEnd,
+ layout_marginTop, and layout_marginBottom are
+ also specified, the layout_margin value will take precedence over the
+ edge-specific values. This space is outside this view's bounds.
Margin values should be positive. -->
<attr name="layout_margin" format="dimension" />
<!-- Specifies extra space on the left side of this view.
@@ -3086,6 +3100,29 @@
This space is outside this view's bounds.
Margin values should be positive.-->
<attr name="layout_marginEnd" format="dimension" />
+ <!-- Specifies extra space on the left and right sides of this view.
+ Specifying layout_marginHorizontal is equivalent to specifying
+ either layout_marginLeft and layout_marginRight or
+ layout_marginStart and layout_marginEnd with that same value.
+ If both layout_marginHorizontal and any of layout_marginLeft,
+ layout_marginRight, layout_marginStart, and layout_marginEnd are
+ also specified, the layout_marginHorizontal value will take precedence over the
+ edge-specific values. Also, layout_margin will always take precendent over
+ any of these values, including layout_marginHorizontal.
+ This space is outside this view's bounds.
+ Margin values should be positive.-->
+ <attr name="layout_marginHorizontal" format="dimension" />
+ <!-- Specifies extra space on the tyop and bottom sides of this view.
+ Specifying layout_marginVertical is equivalent to specifying
+ layout_marginTop and layout_marginBottom with that same value.
+ If both layout_marginVertical and either/both layout_marginTop and
+ layout_marginBottom are also specified, the layout_marginVertical value
+ will take precedence over the edge-specific values.
+ Also, layout_margin will always take precendent over
+ any of these values, including layout_marginHorizontal.
+ This space is outside this view's bounds.
+ Margin values should be positive.-->
+ <attr name="layout_marginVertical" format="dimension" />
</declare-styleable>
<!-- Use <code>input-method</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 0995bc3..fa9cac2 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -165,6 +165,11 @@
<color name="user_icon_default_gray">#ff9e9e9e</color><!-- gray 500 -->
<color name="user_icon_default_white">#ffffffff</color><!-- white -->
+ <!-- Default profile badge colors -->
+ <color name="profile_badge_1">#ffff5722</color><!-- Orange -->
+ <color name="profile_badge_2">#ff000000</color><!-- Black -->
+ <color name="profile_badge_3">#ff22f033</color><!-- Green -->
+
<!-- Multi-sim sim colors -->
<color name="Teal_700">#ff00796b</color>
<color name="Teal_800">#ff00695c</color>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 200961f..deeaf35 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2752,6 +2752,11 @@
<public name="exampleAttr1" />
<public name="exampleAttr2" />
</public-group>
+
+ To add a new public-group block, choose an id value that is 1 greater
+ than the last of that item above. For example, the last "attr" id
+ value above is 0x01010530, so the public-group of attrs below has
+ the id value of 0x01010531.
=============================================================== -->
<eat-comment />
@@ -2764,6 +2769,12 @@
<public name="autoSizeStepGranularity" />
<public name="autoSizeStepSizeSet" />
<public name="autoSizeMinTextSize" />
+ <public name="min" />
+ <public name="rotationAnimation" />
+ <public name="layout_marginHorizontal" />
+ <public name="layout_marginVertical" />
+ <public name="paddingHorizontal" />
+ <public name="paddingVertical" />
</public-group>
<public-group type="style" first-id="0x010302e0">
@@ -2772,6 +2783,12 @@
<public-group type="id" first-id="0x01020041">
</public-group>
- <public type="attr" name="min" />
- <public type="attr" name="rotationAnimation" />
+ <!-- ===============================================================
+ DO NOT ADD UN-GROUPED ITEMS HERE
+
+ Any new items (attrs, styles, ids, etc.) *must* be added in a
+ public-group block, as the preceding comment explains.
+ Items added outside of a group may have their value recalculated
+ every time something new is added to this file.
+ =============================================================== -->
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4070d48..af77b1f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1059,6 +1059,11 @@
connected by a call.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_readPhoneNumber">read phone number</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_readPhoneNumber">Allows the app to access the phone number of the device.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_wakeLock" product="tv">prevent TV from sleeping</string>
@@ -4161,6 +4166,8 @@
[CHAR LIMIT=20]
-->
<string name="managed_profile_label_badge">Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
+ <string name="managed_profile_label_badge_2">2nd Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
+ <string name="managed_profile_label_badge_3">3rd Work <xliff:g id="label" example="Email">%1$s</xliff:g></string>
<!-- DO NOT TRANSLATE -->
<string name="time_placeholder">--</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a28a6fd..f6fd64b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1017,6 +1017,8 @@
<java-symbol type="string" name="action_bar_home_subtitle_description_format" />
<java-symbol type="string" name="wireless_display_route_description" />
<java-symbol type="string" name="managed_profile_label_badge" />
+ <java-symbol type="string" name="managed_profile_label_badge_2" />
+ <java-symbol type="string" name="managed_profile_label_badge_3" />
<java-symbol type="string" name="mediasize_unknown_portrait" />
<java-symbol type="string" name="mediasize_unknown_landscape" />
<java-symbol type="string" name="mediasize_iso_a0" />
@@ -1269,12 +1271,15 @@
<java-symbol type="drawable" name="cling_button" />
<java-symbol type="drawable" name="cling_arrow_up" />
<java-symbol type="drawable" name="cling_bg" />
- <java-symbol type="drawable" name="ic_corp_badge" />
+ <java-symbol type="drawable" name="ic_corp_badge_color" />
+ <java-symbol type="drawable" name="ic_corp_badge_case" />
+ <java-symbol type="drawable" name="ic_corp_icon" />
<java-symbol type="drawable" name="ic_corp_badge_off" />
- <java-symbol type="drawable" name="ic_corp_icon_badge" />
+ <java-symbol type="drawable" name="ic_corp_icon_badge_shadow" />
+ <java-symbol type="drawable" name="ic_corp_icon_badge_color" />
+ <java-symbol type="drawable" name="ic_corp_icon_badge_case" />
<java-symbol type="drawable" name="ic_corp_user_badge" />
<java-symbol type="drawable" name="ic_corp_badge_no_background" />
- <java-symbol type="drawable" name="ic_corp_icon" />
<java-symbol type="drawable" name="ic_corp_statusbar_icon" />
<java-symbol type="drawable" name="emulator_circular_window_overlay" />
@@ -1301,6 +1306,9 @@
<java-symbol type="color" name="user_icon_8" />
<java-symbol type="color" name="user_icon_default_gray" />
<java-symbol type="color" name="user_icon_default_white" />
+ <java-symbol type="color" name="profile_badge_1" />
+ <java-symbol type="color" name="profile_badge_2" />
+ <java-symbol type="color" name="profile_badge_3" />
<java-symbol type="layout" name="action_bar_home" />
<java-symbol type="layout" name="action_bar_title_item" />
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a15cba0..33a0493 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -620,7 +620,7 @@
try {
pkgInfo = pm.getPackageInfo(pkg,
PackageManager.GET_PERMISSIONS
- | PackageManager.GET_UNINSTALLED_PACKAGES);
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
pkgInfo = null;
}
@@ -712,7 +712,7 @@
// Make sure the package doesn't exist
try {
ApplicationInfo appInfo = pm.getApplicationInfo(pkg.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
GenericReceiver receiver = new DeleteReceiver(pkg.packageName);
invokeDeletePackage(pkg.packageName, 0, receiver);
} catch (NameNotFoundException e) {
@@ -974,7 +974,7 @@
public boolean invokeDeletePackage(final String pkgName, int flags, GenericReceiver receiver)
throws Exception {
ApplicationInfo info = getPm().getApplicationInfo(pkgName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
mContext.registerReceiver(receiver, receiver.filter);
try {
@@ -1019,7 +1019,7 @@
Log.i(TAG, "okay4");
try {
info = getPm().getApplicationInfo(ip.pkg.packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
info = null;
}
@@ -1323,7 +1323,7 @@
ApplicationInfo info = null;
try {
- info = getPm().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+ info = getPm().getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException ignored) {
}
@@ -1350,7 +1350,7 @@
Log.i(TAG, "Deleting package : " + pkgName);
try {
ApplicationInfo info = getPm().getApplicationInfo(pkgName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
if (info != null) {
DeleteObserver observer = new DeleteObserver(pkgName);
@@ -3756,7 +3756,7 @@
public void testGetUnInstalledPackages() throws Exception {
List<PackageInfo> packages = getPm().getInstalledPackages(
- PackageManager.GET_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
assertNotNull("installed packages cannot be null", packages);
assertTrue("installed packages cannot be empty", packages.size() > 0);
}
@@ -3769,7 +3769,7 @@
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
| PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
- | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+ | PackageManager.GET_SIGNATURES | PackageManager.MATCH_UNINSTALLED_PACKAGES;
final InstallParams ip =
installFromRawResource("install.apk", R.raw.install_complete_package_info,
@@ -3809,12 +3809,12 @@
* flags when the GET_UNINSTALLED_PACKAGES flag is set.
*/
public void testGetUnInstalledPackagesAll() throws Exception {
- final int flags = PackageManager.GET_UNINSTALLED_PACKAGES
+ final int flags = PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
| PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
| PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
| PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
- | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+ | PackageManager.GET_SIGNATURES;
// first, install the package
final InstallParams ip =
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
index e7aca78..02c2517 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
@@ -42,6 +42,8 @@
@Mock private Context mMockContext;
@Mock private PackageManager mMockPm;
+ private NetworkScorerAppManager mNetworkScorerAppManager;
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -54,6 +56,7 @@
MockitoAnnotations.initMocks(this);
Mockito.when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+ mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
}
public void testGetAllValidScorers() throws Exception {
@@ -81,7 +84,7 @@
setScorers(scorers);
Iterator<NetworkScorerAppData> result =
- NetworkScorerAppManager.getAllValidScorers(mMockContext).iterator();
+ mNetworkScorerAppManager.getAllValidScorers().iterator();
assertTrue(result.hasNext());
NetworkScorerAppData next = result.next();
diff --git a/core/tests/coretests/src/android/net/RoughtimeClientTest.java b/core/tests/coretests/src/android/net/RoughtimeClientTest.java
deleted file mode 100644
index cd26804..0000000
--- a/core/tests/coretests/src/android/net/RoughtimeClientTest.java
+++ /dev/null
@@ -1,170 +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 android.net;
-
-import android.net.RoughtimeClient;
-import android.util.Log;
-import libcore.util.HexEncoding;
-
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.security.MessageDigest;
-import java.util.Arrays;
-import junit.framework.TestCase;
-
-
-public class RoughtimeClientTest extends TestCase {
- private static final String TAG = "RoughtimeClientTest";
-
- private static final long TEST_TIME = 8675309;
- private static final int TEST_RADIUS = 42;
-
- private final RoughtimeTestServer mServer = new RoughtimeTestServer();
- private final RoughtimeClient mClient = new RoughtimeClient();
-
- public void testBasicWorkingRoughtimeClientQuery() throws Exception {
- mServer.shouldRespond(true);
- assertTrue(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500));
- assertEquals(1, mServer.numRequestsReceived());
- assertEquals(1, mServer.numRepliesSent());
- }
-
- public void testDnsResolutionFailure() throws Exception {
- mServer.shouldRespond(true);
- assertFalse(mClient.requestTime("roughtime.server.doesnotexist.example", 5000));
- }
-
- public void testTimeoutFailure() throws Exception {
- mServer.shouldRespond(false);
- assertFalse(mClient.requestTime(mServer.getAddress(), mServer.getPort(), 500));
- assertEquals(1, mServer.numRequestsReceived());
- assertEquals(0, mServer.numRepliesSent());
- }
-
- private static MessageDigest md = null;
-
- private static byte[] signedResponse(byte[] nonce) {
- RoughtimeClient.Message signed = new RoughtimeClient.Message();
-
- try {
- if (md == null) {
- md = MessageDigest.getInstance("SHA-512");
- }
- } catch(Exception e) {
- return null;
- }
-
- md.update(new byte[]{0});
- byte[] hash = md.digest(nonce);
- signed.put(RoughtimeClient.Tag.ROOT, hash);
- signed.putLong(RoughtimeClient.Tag.MIDP, TEST_TIME);
- signed.putInt(RoughtimeClient.Tag.RADI, TEST_RADIUS);
-
- return signed.serialize();
- }
-
- private static byte[] response(byte[] nonce) {
- RoughtimeClient.Message msg = new RoughtimeClient.Message();
-
- msg.put(RoughtimeClient.Tag.SREP, signedResponse(nonce));
- msg.putInt(RoughtimeClient.Tag.INDX, 0);
- msg.put(RoughtimeClient.Tag.PATH, new byte[0]);
-
- return msg.serialize();
- }
-
- private static class RoughtimeTestServer {
- private final Object mLock = new Object();
- private final DatagramSocket mSocket;
- private final InetAddress mAddress;
- private final int mPort;
- private int mRcvd;
- private int mSent;
- private Thread mListeningThread;
- private boolean mShouldRespond = true;
-
- public RoughtimeTestServer() {
- mSocket = makeSocket();
- mAddress = mSocket.getLocalAddress();
- mPort = mSocket.getLocalPort();
- Log.d(TAG, "testing server listening on (" + mAddress + ", " + mPort + ")");
-
- mListeningThread = new Thread() {
- public void run() {
- while (true) {
- byte[] buffer = new byte[2048];
- DatagramPacket request = new DatagramPacket(buffer, buffer.length);
- try {
- mSocket.receive(request);
- } catch (IOException e) {
- Log.e(TAG, "datagram receive error: " + e);
- break;
- }
- synchronized (mLock) {
- mRcvd++;
-
- if (! mShouldRespond) {
- continue;
- }
-
- RoughtimeClient.Message msg =
- RoughtimeClient.Message.deserialize(
- Arrays.copyOf(buffer, request.getLength()));
-
- byte[] nonce = msg.get(RoughtimeClient.Tag.NONC);
- if (nonce.length != 64) {
- Log.e(TAG, "Nonce is wrong length.");
- }
-
- try {
- request.setData(response(nonce));
- mSocket.send(request);
- } catch (IOException e) {
- Log.e(TAG, "datagram send error: " + e);
- break;
- }
- mSent++;
- }
- }
- mSocket.close();
- }
- };
- mListeningThread.start();
- }
-
- private DatagramSocket makeSocket() {
- DatagramSocket socket;
- try {
- socket = new DatagramSocket(0, InetAddress.getLoopbackAddress());
- } catch (SocketException e) {
- Log.e(TAG, "Failed to create test server socket: " + e);
- return null;
- }
- return socket;
- }
-
- public void shouldRespond(boolean value) { mShouldRespond = value; }
-
- public InetAddress getAddress() { return mAddress; }
- public int getPort() { return mPort; }
- public int numRequestsReceived() { synchronized (mLock) { return mRcvd; } }
- public int numRepliesSent() { synchronized (mLock) { return mSent; } }
- }
-}
diff --git a/docs/html/reference/images/graphics/colorspace_aces.png b/docs/html/reference/images/graphics/colorspace_aces.png
new file mode 100644
index 0000000..efafe5c
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_aces.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_acescg.png b/docs/html/reference/images/graphics/colorspace_acescg.png
new file mode 100644
index 0000000..55f6ab5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_acescg.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_adobe_rgb.png b/docs/html/reference/images/graphics/colorspace_adobe_rgb.png
new file mode 100644
index 0000000..cb7d602
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_adobe_rgb.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_bt2020.png b/docs/html/reference/images/graphics/colorspace_bt2020.png
new file mode 100644
index 0000000..34a3853
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_bt2020.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_bt709.png b/docs/html/reference/images/graphics/colorspace_bt709.png
new file mode 100644
index 0000000..ba637f5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_bt709.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_clipped.png b/docs/html/reference/images/graphics/colorspace_clipped.png
new file mode 100644
index 0000000..28204e6
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_clipped.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_comparison.png b/docs/html/reference/images/graphics/colorspace_comparison.png
new file mode 100644
index 0000000..b1b015c
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_comparison.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_comparison2.png b/docs/html/reference/images/graphics/colorspace_comparison2.png
new file mode 100644
index 0000000..b263aa1f
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_comparison2.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_dci_p3.png b/docs/html/reference/images/graphics/colorspace_dci_p3.png
new file mode 100644
index 0000000..19144e7
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_dci_p3.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_display_p3.png b/docs/html/reference/images/graphics/colorspace_display_p3.png
new file mode 100644
index 0000000..a86c60a
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_display_p3.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_ntsc_1953.png b/docs/html/reference/images/graphics/colorspace_ntsc_1953.png
new file mode 100644
index 0000000..bce93da
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_ntsc_1953.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_points.png b/docs/html/reference/images/graphics/colorspace_points.png
new file mode 100644
index 0000000..84d1e77
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_points.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_pro_photo_rgb.png b/docs/html/reference/images/graphics/colorspace_pro_photo_rgb.png
new file mode 100644
index 0000000..74c95be
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_pro_photo_rgb.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_renderer.png b/docs/html/reference/images/graphics/colorspace_renderer.png
new file mode 100644
index 0000000..acf30c3
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_renderer.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_scrgb.png b/docs/html/reference/images/graphics/colorspace_scrgb.png
new file mode 100644
index 0000000..2351b8e
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_scrgb.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_smpte_c.png b/docs/html/reference/images/graphics/colorspace_smpte_c.png
new file mode 100644
index 0000000..360bb73
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_smpte_c.png
Binary files differ
diff --git a/docs/html/reference/images/graphics/colorspace_srgb.png b/docs/html/reference/images/graphics/colorspace_srgb.png
new file mode 100644
index 0000000..ba637f5
--- /dev/null
+++ b/docs/html/reference/images/graphics/colorspace_srgb.png
Binary files differ
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index d114deb..7dc5de3 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -16,11 +16,16 @@
package android.graphics;
+import android.annotation.ColorInt;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Size;
+import android.annotation.Nullable;
+import android.util.Pair;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.function.DoubleUnaryOperator;
/**
@@ -117,11 +122,38 @@
* and {@link #connect(ColorSpace, ColorSpace)}, are also guaranteed to be
* thread-safe.</p>
*
+ * <h3>Visualization and debugging</h3>
+ *
+ * <p>To visualize and debug color spaces, you can call {@link #createRenderer()}.
+ * The {@link Renderer} created by calling this method can be used to compare
+ * color spaces and locate specific colors on a CIE 1931 chromaticity diagram.</p>
+ *
+ * <p>The following code snippet shows how to render a bitmap that compares
+ * the color gamuts and white points of {@link Named#DCI_P3} and
+ * {@link Named#PRO_PHOTO_RGB}:</p>
+ *
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .size(768)
+ * .clip(true)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .add(ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), 0xff097ae9)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_renderer.png" />
+ * <figcaption style="text-align: center;">DCI-P3 vs ProPhoto RGB</figcaption>
+ * </p>
+ *
+ * <p>Please refer to the documentation of the {@link Renderer} class for more
+ * information about its options and capabilities.</p>
+ *
* @see #get(Named)
* @see Named
* @see Model
* @see Connector
* @see Adaptation
+ * @see Renderer
*/
@SuppressWarnings("StaticInitializerReferencesSubClass")
public abstract class ColorSpace {
@@ -207,6 +239,11 @@
* ColorSpace cs = ColorSpace.get(ColorSpace.Named.DCI_P3);
* </pre>
*
+ * <p>The properties of each color space are described below (see {@link #SRGB sRGB}
+ * for instance). When applicable, the color gamut of each color space is compared
+ * to the color gamut of sRGB using a CIE 1931 xy chromaticity diagram. This diagram
+ * shows the location of the color space's primaries and white point.</p>
+ *
* @see ColorSpace#get(Named)
*/
public enum Named {
@@ -240,6 +277,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+ * <figcaption style="text-align: center;">sRGB</figcaption>
+ * </p>
*/
SRGB,
/**
@@ -263,6 +304,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+ * <figcaption style="text-align: center;">sRGB</figcaption>
+ * </p>
*/
LINEAR_SRGB,
/**
@@ -298,6 +343,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+ * <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
EXTENDED_SRGB,
/**
@@ -321,6 +370,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+ * <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
LINEAR_EXTENDED_SRGB,
/**
@@ -352,6 +405,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_bt709.png" />
+ * <figcaption style="text-align: center;">BT.709</figcaption>
+ * </p>
*/
BT709,
/**
@@ -383,6 +440,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_bt2020.png" />
+ * <figcaption style="text-align: center;">BT.2020 (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
BT2020,
/**
@@ -406,6 +467,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_dci_p3.png" />
+ * <figcaption style="text-align: center;">DCI-P3 (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
DCI_P3,
/**
@@ -437,6 +502,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_display_p3.png" />
+ * <figcaption style="text-align: center;">Display P3 (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
DISPLAY_P3,
/**
@@ -468,6 +537,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_ntsc_1953.png" />
+ * <figcaption style="text-align: center;">NTSC 1953 (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
NTSC_1953,
/**
@@ -499,6 +572,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_smpte_c.png" />
+ * <figcaption style="text-align: center;">SMPTE-C (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
SMPTE_C,
/**
@@ -522,6 +599,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_adobe_rgb.png" />
+ * <figcaption style="text-align: center;">Adobe RGB (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
ADOBE_RGB,
/**
@@ -553,6 +634,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([0..1]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_pro_photo_rgb.png" />
+ * <figcaption style="text-align: center;">ProPhoto RGB (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
PRO_PHOTO_RGB,
/**
@@ -576,6 +661,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_aces.png" />
+ * <figcaption style="text-align: center;">ACES (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
ACES,
/**
@@ -599,6 +688,10 @@
* </tr>
* <tr><td>Range</td><td colspan="4">\([-65504.0, 65504.0]\)</td></tr>
* </table>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_acescg.png" />
+ * <figcaption style="text-align: center;">ACEScg (orange) vs sRGB (white)</figcaption>
+ * </p>
*/
ACESCG,
/**
@@ -1110,7 +1203,7 @@
if (source.equals(destination)) return Connector.identity(source);
if (source.getModel() == Model.RGB && destination.getModel() == Model.RGB) {
- return new Connector.RGB((Rgb) source, (Rgb) destination, intent);
+ return new Connector.Rgb((Rgb) source, (Rgb) destination, intent);
}
return new Connector(source, destination, intent);
@@ -1162,7 +1255,7 @@
if (source.isSrgb()) return Connector.identity(source);
if (source.getModel() == Model.RGB) {
- return new Connector.RGB((Rgb) source, (Rgb) get(Named.SRGB), intent);
+ return new Connector.Rgb((Rgb) source, (Rgb) get(Named.SRGB), intent);
}
return new Connector(source, get(Named.SRGB), intent);
@@ -1271,6 +1364,20 @@
return sNamedColorSpaces[name.ordinal()];
}
+ /**
+ * <p>Creates a new {@link Renderer} that can be used to visualize and
+ * debug color spaces. See the documentation of {@link Renderer} for
+ * more information.</p>
+ *
+ * @return A new non-null {@link Renderer} instance
+ *
+ * @see Renderer
+ */
+ @NonNull
+ public static Renderer createRenderer() {
+ return new Renderer();
+ }
+
static {
sNamedColorSpaces[Named.SRGB.ordinal()] = new ColorSpace.Rgb(
"sRGB IEC61966-2.1",
@@ -1740,6 +1847,11 @@
* primaries and white point in the CIE XYZ space. The tristimulus XYZ values
* are internally converted to xyY.</p>
*
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_srgb.png" />
+ * <figcaption style="text-align: center;">sRGB primaries and white point</figcaption>
+ * </p>
+ *
* <h3>Transfer functions</h3>
* <p>A transfer function is a color component conversion function, defined as
* a single variable, monotonic mathematical function. It is applied to each
@@ -1788,6 +1900,11 @@
* range \([-0.5..7.5]\) while {@link Named#ACES ACES} can be used throughout
* the range \([-65504, 65504]\).</p>
*
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
+ * <figcaption style="text-align: center;">Extended sRGB and its large range</figcaption>
+ * </p>
+ *
* <h3>Converting between RGB color spaces</h3>
* <p>Conversion between two color spaces is achieved by using an intermediate
* color space called the profile connection space (PCS). The PCS used by
@@ -1854,7 +1971,7 @@
@NonNull @Size(9) float[] toXYZ,
@NonNull DoubleUnaryOperator oetf,
@NonNull DoubleUnaryOperator eotf) {
- this(name,computePrimaries(toXYZ, eotf), computeWhitePoint(toXYZ, eotf),
+ this(name, computePrimaries(toXYZ, eotf), computeWhitePoint(toXYZ, eotf),
oetf, eotf, 0.0f, 1.0f, MIN_ID);
}
@@ -1996,8 +2113,8 @@
// A color space is wide-gamut if its area is >90% of NTSC 1953 and
// if it entirely contains the Color space definition in xyY
- mIsWideGamut = isWideGamut(primaries, min, max);
- mIsSrgb = isSrgb(primaries, whitePoint, oetf, eotf, min, max, id);
+ mIsWideGamut = isWideGamut(mPrimaries, min, max);
+ mIsSrgb = isSrgb(mPrimaries, mWhitePoint, oetf, eotf, min, max, id);
}
/**
@@ -2450,7 +2567,7 @@
* If the conditions above are not met, the color space is considered as having
* a wide color gamut if its range is larger than [0..1].
*
- * @param primaries RGB primaries in CIE xyY or XYZ as an array of 6 or 9 floats
+ * @param primaries RGB primaries in CIE xyY as an array of 6 floats
* @param min The minimum value of the color space's range
* @param max The minimum value of the color space's range
* @return True if the color space has a wide gamut, false otherwise
@@ -2458,7 +2575,7 @@
* @see #isWideGamut()
* @see #area(float[])
*/
- private static boolean isWideGamut(@NonNull @Size(min = 6, max = 9) float[] primaries,
+ private static boolean isWideGamut(@NonNull @Size(6) float[] primaries,
float min, float max) {
return (area(primaries) / area(NTSC_1953_PRIMARIES) > 0.9f &&
contains(primaries, SRGB_PRIMARIES)) || (min < 0.0f && max > 1.0f);
@@ -2643,7 +2760,7 @@
* @return A new array of 6 floats containing the primaries in xyY
*/
@NonNull
- @Size(2)
+ @Size(6)
private static float[] xyPrimaries(@NonNull @Size(min = 6, max = 9) float[] primaries) {
float[] xyPrimaries = new float[6];
@@ -2818,7 +2935,7 @@
private Connector(
@NonNull ColorSpace source, @NonNull ColorSpace destination,
@NonNull ColorSpace transformSource, @NonNull ColorSpace transformDestination,
- @NonNull RenderIntent intent, @NonNull @Size(3) float[] transform) {
+ @NonNull RenderIntent intent, @Nullable @Size(3) float[] transform) {
mSource = source;
mDestination = destination;
mTransformSource = transformSource;
@@ -2938,13 +3055,12 @@
/**
* Optimized connector for RGB->RGB conversions.
*/
- private static class RGB extends Connector {
+ private static class Rgb extends Connector {
@NonNull private final ColorSpace.Rgb mSource;
@NonNull private final ColorSpace.Rgb mDestination;
@NonNull private final float[] mTransform;
- RGB(@NonNull ColorSpace.Rgb source,
- @NonNull ColorSpace.Rgb destination,
+ Rgb(@NonNull ColorSpace.Rgb source, @NonNull ColorSpace.Rgb destination,
@NonNull RenderIntent intent) {
super(source, destination, source, destination, intent, null);
mSource = source;
@@ -3042,4 +3158,688 @@
};
}
}
+
+ /**
+ * <p>A color space renderer can be used to visualize and compare the gamut and
+ * white point of one or more color spaces. The output is an sRGB {@link Bitmap}
+ * showing a CIE 1931 xyY chromaticity diagram.</p>
+ *
+ * <p>The following code snippet shows how to compare the {@link Named#SRGB}
+ * and {@link Named#DCI_P3} color spaces:</p>
+ *
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .size(768)
+ * .clip(true)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_clipped.png" />
+ * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+ * </p>
+ *
+ * <p>A renderer can also be used to show the location of specific colors,
+ * associated with a color space, in the CIE 1931 xyY chromaticity diagram.
+ * See {@link #add(ColorSpace, float, float, float, int)} for more information.</p>
+ *
+ * @see ColorSpace#createRenderer()
+ */
+ public static class Renderer {
+ private static final int NATIVE_SIZE = 1440;
+
+ @IntRange(from = 128, to = Integer.MAX_VALUE)
+ private int mSize = 1024;
+
+ private boolean mShowWhitePoint = true;
+ private boolean mClip = false;
+
+ private final List<Pair<ColorSpace, Integer>> mColorSpaces = new ArrayList<>(2);
+ private final List<Point> mPoints = new ArrayList<>(0);
+
+ private Renderer() {
+ }
+
+ /**
+ * <p>Defines whether the chromaticity diagram should be clipped by the first
+ * registered color space. The default value is false.</p>
+ *
+ * <p>The following code snippet and image show the default behavior:</p>
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison.png" />
+ * <figcaption style="text-align: center;">Clipping disabled</figcaption>
+ * </p>
+ *
+ * <p>Here is the same example with clipping enabled:</p>
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .clip(true)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_clipped.png" />
+ * <figcaption style="text-align: center;">Clipping enabled</figcaption>
+ * </p>
+ *
+ * @param clip True to clip the chromaticity diagram to the first registered color space,
+ * false otherwise
+ * @return This instance of {@link Renderer}
+ */
+ @NonNull
+ public Renderer clip(boolean clip) {
+ mClip = clip;
+ return this;
+ }
+
+ /**
+ * Sets the dimensions (width and height) in pixels of the output bitmap.
+ * The size must be at least 128px and defaults to 1024px.
+ *
+ * @param size The size in pixels of the output bitmap
+ * @return This instance of {@link Renderer}
+ */
+ @NonNull
+ public Renderer size(@IntRange(from = 128, to = Integer.MAX_VALUE) int size) {
+ mSize = Math.max(128, size);
+ return this;
+ }
+
+ /**
+ * Shows or hides the white point of each color space in the output bitmap.
+ * The default is true.
+ *
+ * @param show True to show the white point of each color space, false
+ * otherwise
+ * @return This instance of {@link Renderer}
+ */
+ @NonNull
+ public Renderer showWhitePoint(boolean show) {
+ mShowWhitePoint = show;
+ return this;
+ }
+
+ /**
+ * <p>Adds a color space to represent on the output CIE 1931 chromaticity
+ * diagram. The color space is represented as a triangle showing the
+ * footprint of its color gamut and, optionally, the location of its
+ * white point.</p>
+ *
+ * <p class="note">Color spaces with a color model that is not RGB are
+ * accepted but ignored.</p>
+ *
+ * <p>The following code snippet and image show an example of calling this
+ * method to compare {@link Named#SRGB sRGB} and {@link Named#DCI_P3 DCI-P3}:</p>
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison.png" />
+ * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+ * </p>
+ *
+ * <p>Adding a color space extending beyond the boundaries of the
+ * spectral locus will alter the size of the diagram within the output
+ * bitmap as shown in this example:</p>
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.DCI_P3), 0xffffc845)
+ * .add(ColorSpace.get(ColorSpace.Named.ACES), 0xff097ae9)
+ * .add(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB), 0xff000000)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_comparison2.png" />
+ * <figcaption style="text-align: center;">sRGB vs DCI-P3</figcaption>
+ * </p>
+ *
+ * @param colorSpace The color space whose gamut to render on the diagram
+ * @param color The sRGB color to use to render the color space's gamut and white point
+ * @return This instance of {@link Renderer}
+ *
+ * @see #clip(boolean)
+ * @see #showWhitePoint(boolean)
+ */
+ @NonNull
+ public Renderer add(@NonNull ColorSpace colorSpace, @ColorInt int color) {
+ mColorSpaces.add(new Pair<>(colorSpace, color));
+ return this;
+ }
+
+ /**
+ * <p>Adds a color to represent as a point on the chromaticity diagram.
+ * The color is associated with a color space which will be used to
+ * perform the conversion to CIE XYZ and compute the location of the point
+ * on the diagram. The point is rendered as a colored circle.</p>
+ *
+ * <p>The following code snippet and image show an example of calling this
+ * method to render the location of several sRGB colors as white circles:</p>
+ * <pre class="prettyprint">
+ * Bitmap bitmap = ColorSpace.createRenderer()
+ * .clip(true)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.0f, 0.1f, 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.1f, 0.1f, 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.2f, 0.1f, 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.3f, 0.1f, 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.4f, 0.1f, 0xffffffff)
+ * .add(ColorSpace.get(ColorSpace.Named.SRGB), 0.1f, 0.5f, 0.1f, 0xffffffff)
+ * .render();
+ * </pre>
+ * <p>
+ * <img src="{@docRoot}reference/android/images/graphics/colorspace_points.png" />
+ * <figcaption style="text-align: center;">
+ * Locating colors on the chromaticity diagram
+ * </figcaption>
+ * </p>
+ *
+ * @param colorSpace The color space of the color to locate on the diagram
+ * @param r The first component of the color to locate on the diagram
+ * @param g The second component of the color to locate on the diagram
+ * @param b The third component of the color to locate on the diagram
+ * @param pointColor The sRGB color to use to render the point on the diagram
+ * @return This instance of {@link Renderer}
+ */
+ @NonNull
+ public Renderer add(@NonNull ColorSpace colorSpace, float r, float g, float b,
+ @ColorInt int pointColor) {
+ mPoints.add(new Point(colorSpace, new float[] { r, g, b }, pointColor));
+ return this;
+ }
+
+ /**
+ * <p>Renders the {@link #add(ColorSpace, int) color spaces} and
+ * {@link #add(ColorSpace, float, float, float, int) points} registered
+ * with this renderer. The output bitmap is an sRGB image with the
+ * dimensions specified by calling {@link #size(int)} (1204x1024px by
+ * default).</p>
+ *
+ * @return A new non-null {@link Bitmap} with the dimensions specified
+ * by {@link #size(int)} (1024x1024 by default)
+ */
+ @NonNull
+ public Bitmap render() {
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ Bitmap bitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+
+ float[] primaries = new float[6];
+ float[] whitePoint = new float[2];
+
+ int width = NATIVE_SIZE;
+ int height = NATIVE_SIZE;
+
+ Path path = new Path();
+
+ setTransform(canvas, width, height, primaries);
+ drawBox(canvas, width, height, paint, path);
+ drawLocus(canvas, width, height, paint, path, primaries);
+ drawGamuts(canvas, width, height, paint, path, primaries, whitePoint);
+ drawPoints(canvas, width, height, paint);
+
+ return bitmap;
+ }
+
+ /**
+ * Draws registered points at their correct position in the xyY coordinates.
+ * Each point is positioned according to its associated color space.
+ *
+ * @param canvas The canvas to transform
+ * @param width Width in pixel of the final image
+ * @param height Height in pixel of the final image
+ * @param paint A pre-allocated paint used to avoid temporary allocations
+ */
+ private void drawPoints(@NonNull Canvas canvas, int width, int height,
+ @NonNull Paint paint) {
+
+ paint.setStyle(Paint.Style.FILL);
+
+ float[] v = new float[3];
+ for (final Point point : mPoints) {
+ v[0] = point.mRgb[0];
+ v[1] = point.mRgb[1];
+ v[2] = point.mRgb[2];
+ point.mColorSpace.toXyz(v);
+
+ paint.setColor(point.mColor);
+
+ // XYZ to xyY, assuming Y=1.0
+ float sum = v[0] + v[1] + v[2];
+ canvas.drawCircle(width * v[0] / sum, height - height * v[1] / sum,
+ 4.0f, paint);
+ }
+ }
+
+ /**
+ * Draws the color gamuts and white points of all the registered color
+ * spaces. Only color spaces with an RGB color model are rendered, the
+ * others are ignored.
+ *
+ * @param canvas The canvas to transform
+ * @param width Width in pixel of the final image
+ * @param height Height in pixel of the final image
+ * @param paint A pre-allocated paint used to avoid temporary allocations
+ * @param path A pre-allocated path used to avoid temporary allocations
+ * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations
+ * @param whitePoint A pre-allocated array of 2 floats to avoid temporary allocations
+ */
+ private void drawGamuts(
+ @NonNull Canvas canvas, int width, int height,
+ @NonNull Paint paint, @NonNull Path path,
+ @NonNull @Size(6) float[] primaries, @NonNull @Size(2) float[] whitePoint) {
+
+ for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+ ColorSpace colorSpace = item.first;
+ int color = item.second;
+
+ if (colorSpace.getModel() != Model.RGB) continue;
+
+ Rgb rgb = (Rgb) colorSpace;
+ getPrimaries(rgb, primaries);
+
+ path.rewind();
+ path.moveTo(width * primaries[0], height - height * primaries[1]);
+ path.lineTo(width * primaries[2], height - height * primaries[3]);
+ path.lineTo(width * primaries[4], height - height * primaries[5]);
+ path.close();
+
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(color);
+ canvas.drawPath(path, paint);
+
+ // Draw the white point
+ if (mShowWhitePoint) {
+ rgb.getWhitePoint(whitePoint);
+
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(color);
+ canvas.drawCircle(width * whitePoint[0], height - height * whitePoint[1],
+ 4.0f, paint);
+ }
+ }
+ }
+
+ /**
+ * Returns the primaries of the specified RGB color space. This method handles
+ * the special case of the {@link Named#EXTENDED_SRGB} family of color spaces.
+ *
+ * @param rgb The color space whose primaries to extract
+ * @param primaries A pre-allocated array of 6 floats that will hold the result
+ */
+ @NonNull
+ @Size(6)
+ private static float[] getPrimaries(@NonNull Rgb rgb, @NonNull @Size(6) float[] primaries) {
+ // TODO: We should find a better way to handle these cases
+ if (rgb.equals(ColorSpace.get(Named.EXTENDED_SRGB)) ||
+ rgb.equals(ColorSpace.get(Named.LINEAR_EXTENDED_SRGB))) {
+ primaries[0] = 1.41f;
+ primaries[1] = 0.33f;
+ primaries[2] = 0.27f;
+ primaries[3] = 1.24f;
+ primaries[4] = -0.23f;
+ primaries[5] = -0.57f;
+ return primaries;
+ }
+ return rgb.getPrimaries(primaries);
+ }
+
+ /**
+ * Draws the CIE 1931 chromaticity diagram: the spectral locus and its inside.
+ * This method respect the clip parameter.
+ *
+ * @param canvas The canvas to transform
+ * @param width Width in pixel of the final image
+ * @param height Height in pixel of the final image
+ * @param paint A pre-allocated paint used to avoid temporary allocations
+ * @param path A pre-allocated path used to avoid temporary allocations
+ * @param primaries A pre-allocated array of 6 floats to avoid temporary allocations
+ */
+ private void drawLocus(
+ @NonNull Canvas canvas, int width, int height, @NonNull Paint paint,
+ @NonNull Path path, @NonNull @Size(6) float[] primaries) {
+
+ int vertexCount = SPECTRUM_LOCUS_X.length * CHROMATICITY_RESOLUTION * 6;
+ float[] vertices = new float[vertexCount * 2];
+ int[] colors = new int[vertices.length];
+ computeChromaticityMesh(NATIVE_SIZE, NATIVE_SIZE, vertices, colors);
+
+ // Draw the spectral locus
+ if (mClip && mColorSpaces.size() > 0) {
+ for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+ ColorSpace colorSpace = item.first;
+ if (colorSpace.getModel() != Model.RGB) continue;
+
+ Rgb rgb = (Rgb) colorSpace;
+ getPrimaries(rgb, primaries);
+ break;
+ }
+
+ path.rewind();
+ path.moveTo(width * primaries[0], height - height * primaries[1]);
+ path.lineTo(width * primaries[2], height - height * primaries[3]);
+ path.lineTo(width * primaries[4], height - height * primaries[5]);
+ path.close();
+
+ int[] solid = new int[colors.length];
+ Arrays.fill(solid, 0xff6c6c6c);
+ canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+ null, 0, solid, 0, null, 0, 0, paint);
+
+ canvas.save();
+ canvas.clipPath(path);
+
+ canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+ null, 0, colors, 0, null, 0, 0, paint);
+
+ canvas.restore();
+ } else {
+ canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertices.length, vertices, 0,
+ null, 0, colors, 0, null, 0, 0, paint);
+ }
+
+ // Draw the non-spectral locus
+ int index = (CHROMATICITY_RESOLUTION - 1) * 12;
+ path.reset();
+ path.moveTo(vertices[index], vertices[index + 1]);
+ for (int x = 2; x < SPECTRUM_LOCUS_X.length; x++) {
+ index += CHROMATICITY_RESOLUTION * 12;
+ path.lineTo(vertices[index], vertices[index + 1]);
+ }
+ path.close();
+
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(0xff000000);
+ canvas.drawPath(path, paint);
+ }
+
+ /**
+ * Draws the diagram box, including borders, tick marks, grid lines
+ * and axis labels.
+ *
+ * @param canvas The canvas to transform
+ * @param width Width in pixel of the final image
+ * @param height Height in pixel of the final image
+ * @param paint A pre-allocated paint used to avoid temporary allocations
+ * @param path A pre-allocated path used to avoid temporary allocations
+ */
+ private void drawBox(@NonNull Canvas canvas, int width, int height, @NonNull Paint paint,
+ @NonNull Path path) {
+ // Draw the unit grid
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(2.0f);
+ paint.setColor(0xffc0c0c0);
+ for (int i = 1; i <= 9; i++) {
+ canvas.drawLine(0.0f, height - (height * i / 10.0f),
+ 0.9f * width, height - (height * i / 10.0f), paint);
+ canvas.drawLine(width * i / 10.0f, height,
+ width * i / 10.0f, 0.1f * height, paint);
+ }
+
+ // Draw tick marks
+ paint.setStrokeWidth(4.0f);
+ paint.setColor(0xff000000);
+ for (int i = 1; i <= 9; i++) {
+ canvas.drawLine(0.0f, height - (height * i / 10.0f),
+ width / 100.0f, height - (height * i / 10.0f), paint);
+ canvas.drawLine(width * i / 10.0f, height,
+ width * i / 10.0f, height - (height / 100.0f), paint);
+ }
+
+ // Draw the axis labels
+ paint.setStyle(Paint.Style.FILL);
+ paint.setTextSize(36.0f);
+ paint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
+
+ Rect bounds = new Rect();
+ for (int i = 1; i < 9; i++) {
+ String text = "0." + i;
+ paint.getTextBounds(text, 0, text.length(), bounds);
+
+ float y = height - (height * i / 10.0f);
+ canvas.drawText(text, -0.05f * width + 10, y + bounds.height() / 2.0f, paint);
+
+ float x = width * i / 10.0f;
+ canvas.drawText(text, x - bounds.width() / 2.0f,
+ height + bounds.height() + 16, paint);
+ }
+ paint.setStyle(Paint.Style.STROKE);
+
+ // Draw the diagram box
+ path.moveTo(0.0f, height);
+ path.lineTo(0.9f * width, height);
+ path.lineTo(0.9f * width, 0.1f * height);
+ path.lineTo(0.0f, 0.1f * height);
+ path.close();
+ canvas.drawPath(path, paint);
+ }
+
+ /**
+ * Computes and applies the Canvas transforms required to make the color
+ * gamut of each color space visible in the final image.
+ *
+ * @param canvas The canvas to transform
+ * @param width Width in pixel of the final image
+ * @param height Height in pixel of the final image
+ * @param primaries Array of 6 floats used to avoid temporary allocations
+ */
+ private void setTransform(@NonNull Canvas canvas, int width, int height,
+ @NonNull @Size(6) float[] primaries) {
+
+ RectF primariesBounds = new RectF();
+ for (final Pair<ColorSpace, Integer> item : mColorSpaces) {
+ ColorSpace colorSpace = item.first;
+ if (colorSpace.getModel() != Model.RGB) continue;
+
+ Rgb rgb = (Rgb) colorSpace;
+ getPrimaries(rgb, primaries);
+
+ primariesBounds.left = Math.min(primariesBounds.left, primaries[4]);
+ primariesBounds.top = Math.min(primariesBounds.top, primaries[5]);
+ primariesBounds.right = Math.max(primariesBounds.right, primaries[0]);
+ primariesBounds.bottom = Math.max(primariesBounds.bottom, primaries[3]);
+ }
+
+ primariesBounds.left = Math.min(0.0f, primariesBounds.left);
+ primariesBounds.top = Math.min(0.0f, primariesBounds.top);
+ primariesBounds.right = Math.max(0.9f, primariesBounds.right);
+ primariesBounds.bottom = Math.max(0.9f, primariesBounds.bottom);
+
+ float scaleX = 0.9f / primariesBounds.width();
+ float scaleY = 0.9f / primariesBounds.height();
+ float scale = Math.min(scaleX, scaleY);
+
+ canvas.scale(mSize / (float) NATIVE_SIZE, mSize / (float) NATIVE_SIZE);
+ canvas.scale(scale, scale);
+ canvas.translate(
+ (primariesBounds.width() - 0.9f) * width / 2.0f,
+ (primariesBounds.height() - 0.9f) * height / 2.0f);
+
+ // The spectrum extends ~0.85 vertically and ~0.65 horizontally
+ // We shift the canvas a little bit to get nicer margins
+ canvas.translate(0.05f * width, -0.05f * height);
+ }
+
+ // X coordinates of the spectral locus in CIE 1931
+ private static final float[] SPECTRUM_LOCUS_X = {
+ 0.175596f, 0.172787f, 0.170806f, 0.170085f, 0.160343f,
+ 0.146958f, 0.139149f, 0.133536f, 0.126688f, 0.115830f,
+ 0.109616f, 0.099146f, 0.091310f, 0.078130f, 0.068717f,
+ 0.054675f, 0.040763f, 0.027497f, 0.016270f, 0.008169f,
+ 0.004876f, 0.003983f, 0.003859f, 0.004646f, 0.007988f,
+ 0.013870f, 0.022244f, 0.027273f, 0.032820f, 0.038851f,
+ 0.045327f, 0.052175f, 0.059323f, 0.066713f, 0.074299f,
+ 0.089937f, 0.114155f, 0.138695f, 0.154714f, 0.192865f,
+ 0.229607f, 0.265760f, 0.301588f, 0.337346f, 0.373083f,
+ 0.408717f, 0.444043f, 0.478755f, 0.512467f, 0.544767f,
+ 0.575132f, 0.602914f, 0.627018f, 0.648215f, 0.665746f,
+ 0.680061f, 0.691487f, 0.700589f, 0.707901f, 0.714015f,
+ 0.719017f, 0.723016f, 0.734674f, 0.717203f, 0.699732f,
+ 0.682260f, 0.664789f, 0.647318f, 0.629847f, 0.612376f,
+ 0.594905f, 0.577433f, 0.559962f, 0.542491f, 0.525020f,
+ 0.507549f, 0.490077f, 0.472606f, 0.455135f, 0.437664f,
+ 0.420193f, 0.402721f, 0.385250f, 0.367779f, 0.350308f,
+ 0.332837f, 0.315366f, 0.297894f, 0.280423f, 0.262952f,
+ 0.245481f, 0.228010f, 0.210538f, 0.193067f, 0.175596f
+ };
+ // Y coordinates of the spectral locus in CIE 1931
+ private static final float[] SPECTRUM_LOCUS_Y = {
+ 0.005295f, 0.004800f, 0.005472f, 0.005976f, 0.014496f,
+ 0.026643f, 0.035211f, 0.042704f, 0.053441f, 0.073601f,
+ 0.086866f, 0.112037f, 0.132737f, 0.170464f, 0.200773f,
+ 0.254155f, 0.317049f, 0.387997f, 0.463035f, 0.538504f,
+ 0.587196f, 0.610526f, 0.654897f, 0.675970f, 0.715407f,
+ 0.750246f, 0.779682f, 0.792153f, 0.802971f, 0.812059f,
+ 0.819430f, 0.825200f, 0.829460f, 0.832306f, 0.833833f,
+ 0.833316f, 0.826231f, 0.814796f, 0.805884f, 0.781648f,
+ 0.754347f, 0.724342f, 0.692326f, 0.658867f, 0.624470f,
+ 0.589626f, 0.554734f, 0.520222f, 0.486611f, 0.454454f,
+ 0.424252f, 0.396516f, 0.372510f, 0.351413f, 0.334028f,
+ 0.319765f, 0.308359f, 0.299317f, 0.292044f, 0.285945f,
+ 0.280951f, 0.276964f, 0.265326f, 0.257200f, 0.249074f,
+ 0.240948f, 0.232822f, 0.224696f, 0.216570f, 0.208444f,
+ 0.200318f, 0.192192f, 0.184066f, 0.175940f, 0.167814f,
+ 0.159688f, 0.151562f, 0.143436f, 0.135311f, 0.127185f,
+ 0.119059f, 0.110933f, 0.102807f, 0.094681f, 0.086555f,
+ 0.078429f, 0.070303f, 0.062177f, 0.054051f, 0.045925f,
+ 0.037799f, 0.029673f, 0.021547f, 0.013421f, 0.005295f
+ };
+
+ // Number of subdivision of the inside of the spectral locus
+ private static final int CHROMATICITY_RESOLUTION = 32;
+ private static final double ONE_THIRD = 1.0 / 3.0;
+
+ /**
+ * Computes a 2D mesh representation of the CIE 1931 chromaticity
+ * diagram.
+ *
+ * @param width Width in pixels of the mesh
+ * @param height Height in pixels of the mesh
+ * @param vertices Array of floats that will hold the mesh vertices
+ * @param colors Array of floats that will hold the mesh colors
+ */
+ private static void computeChromaticityMesh(int width, int height,
+ @NonNull float[] vertices, @NonNull int[] colors) {
+
+ ColorSpace colorSpace = get(Named.SRGB);
+
+ float[] color = new float[3];
+
+ int vertexIndex = 0;
+ int colorIndex = 0;
+
+ for (int x = 0; x < SPECTRUM_LOCUS_X.length; x++) {
+ int nextX = (x % (SPECTRUM_LOCUS_X.length - 1)) + 1;
+
+ float a1 = (float) Math.atan2(
+ SPECTRUM_LOCUS_Y[x] - ONE_THIRD,
+ SPECTRUM_LOCUS_X[x] - ONE_THIRD);
+ float a2 = (float) Math.atan2(
+ SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD,
+ SPECTRUM_LOCUS_X[nextX] - ONE_THIRD);
+
+ float radius1 = (float) Math.pow(
+ sqr(SPECTRUM_LOCUS_X[x] - ONE_THIRD) +
+ sqr(SPECTRUM_LOCUS_Y[x] - ONE_THIRD),
+ 0.5);
+ float radius2 = (float) Math.pow(
+ sqr(SPECTRUM_LOCUS_X[nextX] - ONE_THIRD) +
+ sqr(SPECTRUM_LOCUS_Y[nextX] - ONE_THIRD),
+ 0.5);
+
+ // Compute patches; each patch is a quad with a different
+ // color associated with each vertex
+ for (int c = 1; c <= CHROMATICITY_RESOLUTION; c++) {
+ float f1 = c / (float) CHROMATICITY_RESOLUTION;
+ float f2 = (c - 1) / (float) CHROMATICITY_RESOLUTION;
+
+ double cr1 = radius1 * Math.cos(a1);
+ double sr1 = radius1 * Math.sin(a1);
+ double cr2 = radius2 * Math.cos(a2);
+ double sr2 = radius2 * Math.sin(a2);
+
+ // Compute the XYZ coordinates of the 4 vertices of the patch
+ float v1x = (float) (ONE_THIRD + cr1 * f1);
+ float v1y = (float) (ONE_THIRD + sr1 * f1);
+ float v1z = 1 - v1x - v1y;
+
+ float v2x = (float) (ONE_THIRD + cr1 * f2);
+ float v2y = (float) (ONE_THIRD + sr1 * f2);
+ float v2z = 1 - v2x - v2y;
+
+ float v3x = (float) (ONE_THIRD + cr2 * f2);
+ float v3y = (float) (ONE_THIRD + sr2 * f2);
+ float v3z = 1 - v3x - v3y;
+
+ float v4x = (float) (ONE_THIRD + cr2 * f1);
+ float v4y = (float) (ONE_THIRD + sr2 * f1);
+ float v4z = 1 - v4x - v4y;
+
+ // Compute the sRGB representation of each XYZ coordinate of the patch
+ colors[colorIndex ] = computeColor(color, v1x, v1y, v1z, colorSpace);
+ colors[colorIndex + 1] = computeColor(color, v2x, v2y, v2z, colorSpace);
+ colors[colorIndex + 2] = computeColor(color, v3x, v3y, v3z, colorSpace);
+ colors[colorIndex + 3] = colors[colorIndex];
+ colors[colorIndex + 4] = colors[colorIndex + 2];
+ colors[colorIndex + 5] = computeColor(color, v4x, v4y, v4z, colorSpace);
+ colorIndex += 6;
+
+ // Flip the mesh upside down to match Canvas' coordinates system
+ vertices[vertexIndex++] = v1x * width;
+ vertices[vertexIndex++] = height - v1y * height;
+ vertices[vertexIndex++] = v2x * width;
+ vertices[vertexIndex++] = height - v2y * height;
+ vertices[vertexIndex++] = v3x * width;
+ vertices[vertexIndex++] = height - v3y * height;
+ vertices[vertexIndex++] = v1x * width;
+ vertices[vertexIndex++] = height - v1y * height;
+ vertices[vertexIndex++] = v3x * width;
+ vertices[vertexIndex++] = height - v3y * height;
+ vertices[vertexIndex++] = v4x * width;
+ vertices[vertexIndex++] = height - v4y * height;
+ }
+ }
+ }
+
+ @ColorInt
+ private static int computeColor(@NonNull @Size(3) float[] color,
+ float x, float y, float z, @NonNull ColorSpace cs) {
+ color[0] = x;
+ color[1] = y;
+ color[2] = z;
+ cs.fromXyz(color);
+ return 0xff000000 |
+ (((int) (color[0] * 255.0f) & 0xff) << 16) |
+ (((int) (color[1] * 255.0f) & 0xff) << 8) |
+ (((int) (color[2] * 255.0f) & 0xff) );
+ }
+
+ private static double sqr(double v) {
+ return v * v;
+ }
+
+ private static class Point {
+ @NonNull final ColorSpace mColorSpace;
+ @NonNull final float[] mRgb;
+ final int mColor;
+
+ Point(@NonNull ColorSpace colorSpace,
+ @NonNull @Size(3) float[] rgb, @ColorInt int color) {
+ mColorSpace = colorSpace;
+ mRgb = rgb;
+ mColor = color;
+ }
+ }
+ }
}
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 7871aa8..069f81b 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -21,6 +21,8 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -99,6 +101,67 @@
}
}
+ // Note that a well-formed variation contains a four-character tag and a float as styleValue,
+ // with spacers in between. The tag is enclosd either by double quotes or single quotes.
+ @VisibleForTesting
+ public static Axis[] parseFontVariationSettings(String settings) {
+ String[] settingList = settings.split(",");
+ ArrayList<Axis> axisList = new ArrayList<>();
+ settingLoop:
+ for (String setting : settingList) {
+ int pos = 0;
+ while (pos < setting.length()) {
+ char c = setting.charAt(pos);
+ if (c == '\'' || c == '"') {
+ break;
+ } else if (!isSpacer(c)) {
+ continue settingLoop; // Only spacers are allowed before tag appeared.
+ }
+ pos++;
+ }
+ if (pos + 7 > setting.length()) {
+ continue; // 7 is the minimum length of tag-style value pair text.
+ }
+ if (setting.charAt(pos) != setting.charAt(pos + 5)) {
+ continue; // Tag should be wrapped with double or single quote.
+ }
+ String tagString = setting.substring(pos + 1, pos + 5);
+ if (!TAG_PATTERN.matcher(tagString).matches()) {
+ continue; // Skip incorrect format tag.
+ }
+ pos += 6;
+ while (pos < setting.length()) {
+ if (!isSpacer(setting.charAt(pos++))) {
+ break; // Skip spacers between the tag and the styleValue.
+ }
+ }
+ // Skip invalid styleValue
+ float styleValue;
+ String valueString = setting.substring(pos - 1);
+ if (!STYLE_VALUE_PATTERN.matcher(valueString).matches()) {
+ continue; // Skip incorrect format styleValue.
+ }
+ try {
+ styleValue = Float.parseFloat(valueString);
+ } catch (NumberFormatException e) {
+ continue; // ignoreing invalid number format
+ }
+ int tag = makeTag(tagString.charAt(0), tagString.charAt(1), tagString.charAt(2),
+ tagString.charAt(3));
+ axisList.add(new Axis(tag, styleValue));
+ }
+ return axisList.toArray(new Axis[axisList.size()]);
+ }
+
+ @VisibleForTesting
+ public static int makeTag(char c1, char c2, char c3, char c4) {
+ return (c1 << 24) + (c2 << 16) + (c3 << 8) + c4;
+ }
+
+ private static boolean isSpacer(char c) {
+ return c == ' ' || c == '\r' || c == '\t' || c == '\n';
+ }
+
private static Config readFamilies(XmlPullParser parser)
throws XmlPullParserException, IOException {
Config config = new Config();
@@ -179,10 +242,7 @@
int tag = 0;
String tagStr = parser.getAttributeValue(null, "tag");
if (tagStr != null && TAG_PATTERN.matcher(tagStr).matches()) {
- tag = (tagStr.charAt(0) << 24) +
- (tagStr.charAt(1) << 16) +
- (tagStr.charAt(2) << 8) +
- (tagStr.charAt(3) );
+ tag = makeTag(tagStr.charAt(0), tagStr.charAt(1), tagStr.charAt(2), tagStr.charAt(3));
} else {
throw new XmlPullParserException("Invalid tag attribute value.", parser, null);
}
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index abdc2b9..d88aee9 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -1128,8 +1128,6 @@
createAllFutures();
- mCheckedOpacity = true;
-
final int N = mNumChildren;
final Drawable[] drawables = mDrawables;
int op = (N > 0) ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT;
@@ -1138,6 +1136,7 @@
}
mOpacity = op;
+ mCheckedOpacity = true;
return op;
}
@@ -1148,19 +1147,19 @@
createAllFutures();
- mCheckedStateful = true;
-
final int N = mNumChildren;
final Drawable[] drawables = mDrawables;
+ boolean isStateful = false;
for (int i = 0; i < N; i++) {
if (drawables[i].isStateful()) {
- mStateful = true;
- return true;
+ isStateful = true;
+ break;
}
}
- mStateful = false;
- return false;
+ mStateful = isStateful;
+ mCheckedStateful = true;
+ return isStateful;
}
public void growArray(int oldSize, int newSize) {
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 2b950d3..9772009 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -299,7 +299,7 @@
final PackageManager pm = context.getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(
- resPackage, PackageManager.GET_UNINSTALLED_PACKAGES);
+ resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES);
if (ai != null) {
mObj1 = pm.getResourcesForApplication(ai);
} else {
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index e09fea5..355e45e 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -137,7 +137,7 @@
layers[i].setCallback(this);
mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
}
- mLayerState.mNum = length;
+ mLayerState.mNumChildren = length;
mLayerState.mChildren = r;
ensurePadding();
@@ -154,7 +154,7 @@
*/
LayerDrawable(@Nullable LayerState state, @Nullable Resources res) {
mLayerState = createConstantState(state, res);
- if (mLayerState.mNum > 0) {
+ if (mLayerState.mNumChildren > 0) {
ensurePadding();
refreshPadding();
}
@@ -185,7 +185,7 @@
a.recycle();
final ChildDrawable[] array = state.mChildren;
- final int N = state.mNum;
+ final int N = state.mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable layer = array[i];
layer.setDensity(density);
@@ -217,7 +217,7 @@
}
final ChildDrawable[] array = state.mChildren;
- final int N = state.mNum;
+ final int N = state.mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable layer = array[i];
layer.setDensity(density);
@@ -416,7 +416,7 @@
}
final ChildDrawable[] layers = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
if (layers[i].mDrawable.isProjected()) {
return true;
@@ -435,7 +435,7 @@
int addLayer(@NonNull ChildDrawable layer) {
final LayerState st = mLayerState;
final int N = st.mChildren != null ? st.mChildren.length : 0;
- final int i = st.mNum;
+ final int i = st.mNumChildren;
if (i >= N) {
final ChildDrawable[] nu = new ChildDrawable[N + 10];
if (i > 0) {
@@ -446,7 +446,7 @@
}
st.mChildren[i] = layer;
- st.mNum++;
+ st.mNumChildren++;
st.invalidateCache();
return i;
}
@@ -514,7 +514,7 @@
*/
public Drawable findDrawableByLayerId(int id) {
final ChildDrawable[] layers = mLayerState.mChildren;
- for (int i = mLayerState.mNum - 1; i >= 0; i--) {
+ for (int i = mLayerState.mNumChildren - 1; i >= 0; i--) {
if (layers[i].mId == id) {
return layers[i].mDrawable;
}
@@ -549,7 +549,7 @@
* @attr ref android.R.styleable#LayerDrawableItem_id
*/
public int getId(int index) {
- if (index >= mLayerState.mNum) {
+ if (index >= mLayerState.mNumChildren) {
throw new IndexOutOfBoundsException();
}
return mLayerState.mChildren[index].mId;
@@ -561,7 +561,7 @@
* @return The number of layers.
*/
public int getNumberOfLayers() {
- return mLayerState.mNum;
+ return mLayerState.mNumChildren;
}
/**
@@ -593,7 +593,7 @@
*/
public int findIndexByLayerId(int id) {
final ChildDrawable[] layers = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable childDrawable = layers[i];
if (childDrawable.mId == id) {
@@ -615,7 +615,7 @@
* @attr ref android.R.styleable#LayerDrawableItem_drawable
*/
public void setDrawable(int index, Drawable drawable) {
- if (index >= mLayerState.mNum) {
+ if (index >= mLayerState.mNumChildren) {
throw new IndexOutOfBoundsException();
}
@@ -651,7 +651,7 @@
* @attr ref android.R.styleable#LayerDrawableItem_drawable
*/
public Drawable getDrawable(int index) {
- if (index >= mLayerState.mNum) {
+ if (index >= mLayerState.mNumChildren) {
throw new IndexOutOfBoundsException();
}
return mLayerState.mChildren[index].mDrawable;
@@ -1003,7 +1003,7 @@
@Override
public void draw(Canvas canvas) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1230,7 +1230,7 @@
// Add all the padding.
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
refreshChildPadding(i, array[i]);
@@ -1249,7 +1249,7 @@
// Take the max padding.
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
refreshChildPadding(i, array[i]);
@@ -1268,7 +1268,7 @@
@Override
public void getOutline(@NonNull Outline outline) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1283,7 +1283,7 @@
@Override
public void setHotspot(float x, float y) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1295,7 +1295,7 @@
@Override
public void setHotspotBounds(int left, int top, int right, int bottom) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1323,7 +1323,7 @@
public boolean setVisible(boolean visible, boolean restart) {
final boolean changed = super.setVisible(visible, restart);
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1337,7 +1337,7 @@
@Override
public void setDither(boolean dither) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1349,7 +1349,7 @@
@Override
public void setAlpha(int alpha) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1371,7 +1371,7 @@
@Override
public void setColorFilter(ColorFilter colorFilter) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1383,7 +1383,7 @@
@Override
public void setTintList(ColorStateList tint) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1395,7 +1395,7 @@
@Override
public void setTintMode(Mode tintMode) {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1406,7 +1406,7 @@
private Drawable getFirstNonNullDrawable() {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1444,7 +1444,7 @@
mLayerState.mAutoMirrored = mirrored;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1461,7 +1461,7 @@
@Override
public void jumpToCurrentState() {
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1480,7 +1480,7 @@
boolean changed = false;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null && dr.isStateful() && dr.setState(state)) {
@@ -1501,7 +1501,7 @@
boolean changed = false;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null && dr.setLevel(level)) {
@@ -1543,7 +1543,7 @@
final boolean isPaddingNested = mLayerState.mPaddingMode == PADDING_MODE_NEST;
final ChildDrawable[] array = mLayerState.mChildren;
- for (int i = 0, count = mLayerState.mNum; i < count; i++) {
+ for (int i = 0, count = mLayerState.mNumChildren; i < count; i++) {
final ChildDrawable r = array[i];
final Drawable d = r.mDrawable;
if (d == null) {
@@ -1642,7 +1642,7 @@
final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
final boolean isLayoutRtl = getLayoutDirection() == LayoutDirection.RTL;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable r = array[i];
if (r.mDrawable == null) {
@@ -1684,7 +1684,7 @@
final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable r = array[i];
if (r.mDrawable == null) {
@@ -1733,7 +1733,7 @@
* Ensures the child padding caches are large enough.
*/
void ensurePadding() {
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
if (mPaddingL != null && mPaddingL.length >= N) {
return;
}
@@ -1745,7 +1745,7 @@
}
void refreshPadding() {
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
final ChildDrawable[] array = mLayerState.mChildren;
for (int i = 0; i < N; i++) {
refreshChildPadding(i, array[i]);
@@ -1766,7 +1766,7 @@
if (!mMutated && super.mutate() == this) {
mLayerState = createConstantState(mLayerState, null);
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1785,7 +1785,7 @@
super.clearMutated();
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1800,7 +1800,7 @@
boolean changed = false;
final ChildDrawable[] array = mLayerState.mChildren;
- final int N = mLayerState.mNum;
+ final int N = mLayerState.mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null) {
@@ -1905,7 +1905,7 @@
static class LayerState extends ConstantState {
private int[] mThemeAttrs;
- int mNum;
+ int mNumChildren;
ChildDrawable[] mChildren;
int mDensity;
@@ -1922,10 +1922,10 @@
@Config int mChangingConfigurations;
@Config int mChildrenChangingConfigurations;
- private boolean mHaveOpacity;
+ private boolean mCheckedOpacity;
private int mOpacity;
- private boolean mHaveIsStateful;
+ private boolean mCheckedStateful;
private boolean mIsStateful;
private boolean mAutoMirrored = false;
@@ -1938,9 +1938,9 @@
if (orig != null) {
final ChildDrawable[] origChildDrawable = orig.mChildren;
- final int N = orig.mNum;
+ final int N = orig.mNumChildren;
- mNum = N;
+ mNumChildren = N;
mChildren = new ChildDrawable[N];
mChangingConfigurations = orig.mChangingConfigurations;
@@ -1951,9 +1951,9 @@
mChildren[i] = new ChildDrawable(or, owner, res);
}
- mHaveOpacity = orig.mHaveOpacity;
+ mCheckedOpacity = orig.mCheckedOpacity;
mOpacity = orig.mOpacity;
- mHaveIsStateful = orig.mHaveIsStateful;
+ mCheckedStateful = orig.mCheckedStateful;
mIsStateful = orig.mIsStateful;
mAutoMirrored = orig.mAutoMirrored;
mPaddingMode = orig.mPaddingMode;
@@ -1970,7 +1970,7 @@
applyDensityScaling(orig.mDensity, mDensity);
}
} else {
- mNum = 0;
+ mNumChildren = 0;
mChildren = null;
}
}
@@ -2022,7 +2022,7 @@
}
final ChildDrawable[] array = mChildren;
- final int N = mNum;
+ final int N = mNumChildren;
for (int i = 0; i < N; i++) {
final ChildDrawable layer = array[i];
if (layer.canApplyTheme()) {
@@ -2050,12 +2050,12 @@
}
public final int getOpacity() {
- if (mHaveOpacity) {
+ if (mCheckedOpacity) {
return mOpacity;
}
+ final int N = mNumChildren;
final ChildDrawable[] array = mChildren;
- final int N = mNum;
// Seek to the first non-null drawable.
int firstIndex = -1;
@@ -2082,17 +2082,17 @@
}
mOpacity = op;
- mHaveOpacity = true;
+ mCheckedOpacity = true;
return op;
}
public final boolean isStateful() {
- if (mHaveIsStateful) {
+ if (mCheckedStateful) {
return mIsStateful;
}
+ final int N = mNumChildren;
final ChildDrawable[] array = mChildren;
- final int N = mNum;
boolean isStateful = false;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
@@ -2103,13 +2103,13 @@
}
mIsStateful = isStateful;
- mHaveIsStateful = true;
+ mCheckedStateful = true;
return isStateful;
}
public final boolean canConstantState() {
final ChildDrawable[] array = mChildren;
- final int N = mNum;
+ final int N = mNumChildren;
for (int i = 0; i < N; i++) {
final Drawable dr = array[i].mDrawable;
if (dr != null && dr.getConstantState() == null) {
@@ -2122,8 +2122,8 @@
}
public void invalidateCache() {
- mHaveOpacity = false;
- mHaveIsStateful = false;
+ mCheckedOpacity = false;
+ mCheckedStateful = false;
}
}
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index caf2e7a..f83c160 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -667,7 +667,7 @@
public void getOutline(@NonNull Outline outline) {
final LayerState state = mLayerState;
final ChildDrawable[] children = state.mChildren;
- final int N = state.mNum;
+ final int N = state.mNumChildren;
for (int i = 0; i < N; i++) {
if (children[i].mId != R.id.mask) {
children[i].mDrawable.getOutline(outline);
@@ -815,7 +815,7 @@
// Check for non-opaque, non-mask content.
final ChildDrawable[] array = mLayerState.mChildren;
- final int count = mLayerState.mNum;
+ final int count = mLayerState.mNumChildren;
for (int i = 0; i < count; i++) {
if (array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) {
return MASK_CONTENT;
@@ -829,7 +829,7 @@
private void drawContent(Canvas canvas) {
// Draw everything except the mask.
final ChildDrawable[] array = mLayerState.mChildren;
- final int count = mLayerState.mNum;
+ final int count = mLayerState.mNumChildren;
for (int i = 0; i < count; i++) {
if (array[i].mId != R.id.mask) {
array[i].mDrawable.draw(canvas);
@@ -1045,7 +1045,7 @@
mLayerState = mState;
mDensity = Drawable.resolveDensity(res, mState.mDensity);
- if (mState.mNum > 0) {
+ if (mState.mNumChildren > 0) {
ensurePadding();
refreshPadding();
}
diff --git a/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
new file mode 100644
index 0000000..e4d6aa8
--- /dev/null
+++ b/graphics/tests/graphicstests/src/android/graphics/VariationParserTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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 android.graphics;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class VariationParserTest extends TestCase {
+
+ @SmallTest
+ public void testParseFontVariationSetting() {
+ int tag = FontListParser.makeTag('w', 'd', 't', 'h');
+ FontListParser.Axis[] axis = FontListParser.parseFontVariationSettings("'wdth' 1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("\"wdth\" 100");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(100.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings(" 'wdth' 100");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(100.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("\t'wdth' 0.5");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(0.5f, axis[0].styleValue);
+
+ tag = FontListParser.makeTag('A', 'X', ' ', ' ');
+ axis = FontListParser.parseFontVariationSettings("'AX ' 1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("'AX '\t1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("'AX '\n1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("'AX '\r1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ axis = FontListParser.parseFontVariationSettings("'AX '\r\t\n 1");
+ assertEquals(tag, axis[0].tag);
+ assertEquals(1.0f, axis[0].styleValue);
+
+ // Test for invalid input
+ axis = FontListParser.parseFontVariationSettings("");
+ assertEquals(0, axis.length);
+ axis = FontListParser.parseFontVariationSettings("invalid_form");
+ assertEquals(0, axis.length);
+
+ // Test with invalid tag
+ axis = FontListParser.parseFontVariationSettings("'' 1");
+ assertEquals(0, axis.length);
+ axis = FontListParser.parseFontVariationSettings("'invalid' 1");
+ assertEquals(0, axis.length);
+
+ // Test with invalid styleValue
+ axis = FontListParser.parseFontVariationSettings("'wdth' ");
+ assertEquals(0, axis.length);
+ axis = FontListParser.parseFontVariationSettings("'wdth' x");
+ assertEquals(0, axis.length);
+ axis = FontListParser.parseFontVariationSettings("'wdth' \t");
+ assertEquals(0, axis.length);
+ axis = FontListParser.parseFontVariationSettings("'wdth' \n\r");
+ assertEquals(0, axis.length);
+ }
+
+ @SmallTest
+ public void testParseFontVariationStyleSettings() {
+ FontListParser.Axis[] axis =
+ FontListParser.parseFontVariationSettings("'wdth' 10,'AX '\r1");
+ int tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
+ int tag2 = FontListParser.makeTag('A', 'X', ' ', ' ');
+ assertEquals(tag1, axis[0].tag);
+ assertEquals(10.0f, axis[0].styleValue);
+ assertEquals(tag2, axis[1].tag);
+ assertEquals(1.0f, axis[1].styleValue);
+
+ // Test only spacers are allowed before tag
+ axis = FontListParser.parseFontVariationSettings(" 'wdth' 10,ab'wdth' 1");
+ tag1 = FontListParser.makeTag('w', 'd', 't', 'h');
+ assertEquals(tag1, axis[0].tag);
+ assertEquals(10.0f, axis[0].styleValue);
+ assertEquals(1, axis.length);
+ }
+
+ @SmallTest
+ public void testMakeTag() {
+ assertEquals(0x77647468, FontListParser.makeTag('w', 'd', 't', 'h'));
+ assertEquals(0x41582020, FontListParser.makeTag('A', 'X', ' ', ' '));
+ assertEquals(0x20202020, FontListParser.makeTag(' ', ' ', ' ', ' '));
+ }
+}
\ No newline at end of file
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
new file mode 100644
index 0000000..fe5d8ca
--- /dev/null
+++ b/legacy-test/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+# Build the legacy-test library
+# =============================
+# This contains the junit.framework classes that were in Android API level 25.
+include $(CLEAR_VARS)
+
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_STATIC_JAVA_LIBRARIES := core-junit-static
+
+LOCAL_MODULE := legacy-test
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index ad1ead8..7689256 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -65,8 +65,9 @@
LOCAL_SRC_FILES:= $(deviceSources)
LOCAL_C_INCLUDES := \
system/core/include
-LOCAL_STATIC_LIBRARIES := libziparchive libbase
LOCAL_SHARED_LIBRARIES := \
+ libziparchive \
+ libbase \
libbinder \
liblog \
libcutils \
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 6837f25..d18cb8f 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -28,6 +28,7 @@
Config_test.cpp \
ConfigLocale_test.cpp \
Idmap_test.cpp \
+ Main.cpp \
ResTable_test.cpp \
Split_test.cpp \
TestHelpers.cpp \
@@ -59,7 +60,8 @@
libutils \
libcutils \
liblog \
- libz \
+ libz
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
include $(BUILD_HOST_NATIVE_TEST)
@@ -80,7 +82,8 @@
libbase \
libcutils \
libutils \
- libui \
+ libui
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
include $(BUILD_NATIVE_TEST)
endif # Not SDK_ONLY
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 7fbe6d3..d6d7890 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -15,24 +15,27 @@
*/
#include "androidfw/AttributeResolution.h"
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
#include "TestHelpers.h"
#include "data/styles/R.h"
-#include <android-base/file.h>
-#include <android-base/macros.h>
-
-using namespace android;
-using android::base::ReadFileToString;
using com::android::app::R;
+namespace android {
+
class AttributeResolutionTest : public ::testing::Test {
public:
virtual void SetUp() override {
- std::string test_source_dir = TestSourceDir();
+ std::string test_source_dir = GetTestDataPath();
std::string contents;
- LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/resources.arsc", &contents));
- LOG_ALWAYS_FATAL_IF(
- table_.add(contents.data(), contents.size(), 1 /*cookie*/, true /*copyData*/) != NO_ERROR);
+ CHECK(base::ReadFileToString(test_source_dir + "/styles/resources.arsc",
+ &contents));
+ CHECK(table_.add(contents.data(), contents.size(), 1 /*cookie*/,
+ true /*copyData*/) == NO_ERROR);
}
protected:
@@ -43,11 +46,12 @@
public:
virtual void SetUp() override {
AttributeResolutionTest::SetUp();
- std::string test_source_dir = TestSourceDir();
+ std::string test_source_dir = GetTestDataPath();
std::string contents;
- LOG_ALWAYS_FATAL_IF(!ReadFileToString(test_source_dir + "/styles/layout.xml", &contents));
- LOG_ALWAYS_FATAL_IF(xml_parser_.setTo(contents.data(), contents.size(), true /*copyData*/) !=
- NO_ERROR);
+ CHECK(base::ReadFileToString(test_source_dir + "/styles/layout.xml",
+ &contents));
+ CHECK(xml_parser_.setTo(contents.data(), contents.size(),
+ true /*copyData*/) == NO_ERROR);
// Skip to the first tag.
while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -68,8 +72,9 @@
values.resize(arraysize(attrs) * 6);
ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
- nullptr /*src_values*/, 0 /*src_values_length*/, attrs, arraysize(attrs),
- values.data(), nullptr /*out_indices*/));
+ nullptr /*src_values*/, 0 /*src_values_length*/,
+ attrs, arraysize(attrs), values.data(),
+ nullptr /*out_indices*/));
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -111,8 +116,8 @@
std::vector<uint32_t> values;
values.resize(arraysize(attrs) * 6);
- ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs), values.data(),
- nullptr /*out_indices*/));
+ ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs, arraysize(attrs),
+ values.data(), nullptr /*out_indices*/));
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -151,13 +156,14 @@
ResTable::Theme theme(table_);
ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
- uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three, R::attr::attr_four,
- R::attr::attr_five};
+ uint32_t attrs[] = {R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
+ R::attr::attr_four, R::attr::attr_five};
std::vector<uint32_t> values;
values.resize(arraysize(attrs) * 6);
- ASSERT_TRUE(ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs,
- arraysize(attrs), values.data(), nullptr /*out_indices*/));
+ ASSERT_TRUE(ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/,
+ 0 /*def_style_res*/, attrs, arraysize(attrs),
+ values.data(), nullptr /*out_indices*/));
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -199,3 +205,5 @@
EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
}
+
+} // namespace android
diff --git a/libs/androidfw/tests/Main.cpp b/libs/androidfw/tests/Main.cpp
new file mode 100644
index 0000000..6a50691
--- /dev/null
+++ b/libs/androidfw/tests/Main.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#include <libgen.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "android-base/file.h"
+#include "android-base/strings.h"
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+
+// Extract the directory of the current executable path.
+static std::string GetExecutableDir() {
+ const std::string path = android::base::GetExecutablePath();
+ std::unique_ptr<char, decltype(&std::free)> mutable_path = {
+ strdup(path.c_str()), std::free};
+ std::string executable_dir = dirname(mutable_path.get());
+ return executable_dir;
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ // Set the default test data path to be the executable path directory.
+ android::SetTestDataPath(GetExecutableDir());
+
+ const char* command = argv[0];
+ ++argv;
+ --argc;
+
+ while (argc > 0) {
+ const std::string arg = *argv;
+ if (android::base::StartsWith(arg, "--testdata=")) {
+ android::SetTestDataPath(arg.substr(strlen("--testdata=")));
+ } else if (arg == "-h" || arg == "--help") {
+ std::cerr
+ << "\nAdditional options specific to this test:\n"
+ " --testdata=[PATH]\n"
+ " Specify the location of test data used within the tests.\n";
+ return 1;
+ } else {
+ std::cerr << command << ": Unrecognized argument '" << *argv << "'.\n";
+ return 1;
+ }
+
+ --argc;
+ ++argv;
+ }
+
+ std::cerr << "using --testdata=" << android::GetTestDataPath() << "\n";
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 3d1d5f5..702ee5c 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,26 +16,23 @@
#include "TestHelpers.h"
-#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
#include <unistd.h>
-#include <utils/String8.h>
-std::string TestSourceDir() {
- const char* dir = getenv("ANDROID_BUILD_TOP");
- LOG_ALWAYS_FATAL_IF(dir == nullptr, "Environment variable ANDROID_BUILD_TOP must be set");
- std::string testdir = std::string(dir) + "/frameworks/base/libs/androidfw/tests/data";
-
- // Check that the directory exists.
- struct stat filestat;
- LOG_ALWAYS_FATAL_IF(stat(testdir.c_str(), &filestat) != 0, "test data path '%s' does not exist",
- testdir.c_str());
- return testdir;
-}
+#include "android-base/logging.h"
namespace android {
-::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
+static std::string sTestDataPath;
+
+void SetTestDataPath(const std::string& path) { sTestDataPath = path; }
+
+const std::string& GetTestDataPath() {
+ CHECK(!sTestDataPath.empty()) << "no test data path set.";
+ return sTestDataPath;
+}
+
+::testing::AssertionResult IsStringEqual(const ResTable& table,
+ uint32_t resource_id,
const char* expected_str) {
Res_value val;
ssize_t block = table.getResource(resource_id, &val, MAY_NOT_BE_BAG);
@@ -49,7 +46,8 @@
const ResStringPool* pool = table.getTableStringBlock(block);
if (pool == NULL) {
- return ::testing::AssertionFailure() << "table has no string pool for block " << block;
+ return ::testing::AssertionFailure()
+ << "table has no string pool for block " << block;
}
const String8 actual_str = pool->string8ObjectAt(val.data);
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index 5f0c4552..c1e349f 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-#ifndef __TEST_HELPERS_H
-#define __TEST_HELPERS_H
-
-#include <androidfw/ResourceTypes.h>
-#include <gtest/gtest.h>
-#include <utils/String16.h>
-#include <utils/String8.h>
+#ifndef TEST_HELPERS_H_
+#define TEST_HELPERS_H_
#include <ostream>
#include <string>
-std::string TestSourceDir();
+#include "androidfw/ResourceTypes.h"
+#include "gtest/gtest.h"
+#include "utils/String16.h"
+#include "utils/String8.h"
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+ const android::String8& str) {
return out << str.string();
}
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::String16& str) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+ const android::String16& str) {
return out << android::String8(str).string();
}
@@ -39,18 +39,24 @@
enum { MAY_NOT_BE_BAG = false };
-static inline bool operator==(const android::ResTable_config& a,
- const android::ResTable_config& b) {
+void SetTestDataPath(const std::string& path);
+
+const std::string& GetTestDataPath();
+
+static inline bool operator==(const ResTable_config& a,
+ const ResTable_config& b) {
return a.compare(b) == 0;
}
-static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
+static inline ::std::ostream& operator<<(::std::ostream& out,
+ const ResTable_config& c) {
return out << c.toString().string();
}
-::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
+::testing::AssertionResult IsStringEqual(const ResTable& table,
+ uint32_t resource_id,
const char* expected_str);
} // namespace android
-#endif // __TEST_HELPERS_H
+#endif // TEST_HELPERS_H_
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index eff2499..cf571e9 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -278,6 +278,7 @@
tests/unit/BakedOpDispatcherTests.cpp \
tests/unit/BakedOpRendererTests.cpp \
tests/unit/BakedOpStateTests.cpp \
+ tests/unit/BitmapTests.cpp \
tests/unit/CanvasContextTests.cpp \
tests/unit/CanvasStateTests.cpp \
tests/unit/ClipAreaTests.cpp \
@@ -297,6 +298,7 @@
tests/unit/MeshStateTests.cpp \
tests/unit/OffscreenBufferPoolTests.cpp \
tests/unit/OpDumperTests.cpp \
+ tests/unit/PathInterpolatorTests.cpp \
tests/unit/RenderNodeDrawableTests.cpp \
tests/unit/RecordingCanvasTests.cpp \
tests/unit/RenderNodeTests.cpp \
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 1d67579..00238a2 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -37,6 +37,26 @@
Extensions::Extensions() {
+ const char* version = (const char*) glGetString(GL_VERSION);
+
+ // Section 6.1.5 of the OpenGL ES specification indicates the GL version
+ // string strictly follows this format:
+ //
+ // OpenGL<space>ES<space><version number><space><vendor-specific information>
+ //
+ // In addition section 6.1.5 describes the version number thusly:
+ //
+ // "The version number is either of the form major number.minor number or
+ // major number.minor number.release number, where the numbers all have one
+ // or more digits. The release number and vendor specific information are
+ // optional."
+
+ if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
+ // If we cannot parse the version number, assume OpenGL ES 2.0
+ mVersionMajor = 2;
+ mVersionMinor = 0;
+ }
+
auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
mHasNPot = extensions.has("GL_OES_texture_npot");
mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
@@ -58,26 +78,6 @@
mHasSRGB = false;
mHasSRGBWriteControl = false;
#endif
-
- const char* version = (const char*) glGetString(GL_VERSION);
-
- // Section 6.1.5 of the OpenGL ES specification indicates the GL version
- // string strictly follows this format:
- //
- // OpenGL<space>ES<space><version number><space><vendor-specific information>
- //
- // In addition section 6.1.5 describes the version number thusly:
- //
- // "The version number is either of the form major number.minor number or
- // major number.minor number.release number, where the numbers all have one
- // or more digits. The release number and vendor specific information are
- // optional."
-
- if (sscanf(version, "OpenGL ES %d.%d", &mVersionMajor, &mVersionMinor) != 2) {
- // If we cannot parse the version number, assume OpenGL ES 2.0
- mVersionMajor = 2;
- mVersionMinor = 0;
- }
}
}; // namespace uirenderer
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index cc47f00..f94a22d 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -88,6 +88,39 @@
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
+float PathInterpolator::interpolate(float t) {
+ if (t <= 0) {
+ return 0;
+ } else if (t >= 1) {
+ return 1;
+ }
+ // Do a binary search for the correct x to interpolate between.
+ size_t startIndex = 0;
+ size_t endIndex = mX.size() - 1;
+
+ while (endIndex > startIndex + 1) {
+ int midIndex = (startIndex + endIndex) / 2;
+ if (t < mX[midIndex]) {
+ endIndex = midIndex;
+ } else {
+ startIndex = midIndex;
+ }
+ }
+
+ float xRange = mX[endIndex] - mX[startIndex];
+ if (xRange == 0) {
+ return mY[startIndex];
+ }
+
+ float tInRange = t - mX[startIndex];
+ float fraction = tInRange / xRange;
+
+ float startY = mY[startIndex];
+ float endY = mY[endIndex];
+ return startY + (fraction * (endY - startY));
+
+}
+
LUTInterpolator::LUTInterpolator(float* values, size_t size)
: mValues(values)
, mSize(size) {
@@ -97,7 +130,8 @@
}
float LUTInterpolator::interpolate(float input) {
- float lutpos = input * mSize;
+ // lut position should only be at the end of the table when input is 1f.
+ float lutpos = input * (mSize - 1);
if (lutpos >= (mSize - 1)) {
return mValues[mSize - 1];
}
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 6512008..224cee7 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -20,6 +20,7 @@
#include <memory>
#include <cutils/compiler.h>
+#include <vector>
namespace android {
namespace uirenderer {
@@ -100,6 +101,16 @@
const float mTension;
};
+class ANDROID_API PathInterpolator : public Interpolator {
+public:
+ explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y)
+ : mX (x), mY(y) {}
+ virtual float interpolate(float input) override;
+private:
+ std::vector<float> mX;
+ std::vector<float> mY;
+};
+
class ANDROID_API LUTInterpolator : public Interpolator {
public:
LUTInterpolator(float* values, size_t size);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index a03ded6..a5443d9 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -188,8 +188,9 @@
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
- // Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
- bool functorsNeedLayer = Properties::debugOverdraw;
+ // The OpenGL renderer reserves the stencil buffer for overdraw debugging. Functors
+ // will need to be drawn in a layer.
+ bool functorsNeedLayer = Properties::debugOverdraw && !Properties::isSkiaEnabled();
prepareTreeImpl(info, functorsNeedLayer);
}
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 5e21dfc..6786a69 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -52,16 +52,20 @@
SkiaCanvas::SkiaCanvas() {}
SkiaCanvas::SkiaCanvas(SkCanvas* canvas)
- : mCanvas(SkRef(canvas)) {}
+ : mCanvas(canvas) {}
SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
- mCanvas.reset(new SkCanvas(bitmap));
+ mCanvasOwned = std::unique_ptr<SkCanvas>(new SkCanvas(bitmap));
+ mCanvas = mCanvasOwned.get();
}
SkiaCanvas::~SkiaCanvas() {}
void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
- mCanvas.reset(SkRef(skiaCanvas));
+ if (mCanvas != skiaCanvas) {
+ mCanvas = skiaCanvas;
+ mCanvasOwned.reset();
+ }
mSaveStack.reset(nullptr);
mHighContrastText = false;
}
@@ -99,8 +103,9 @@
mCanvas->replayClips(&copier);
}
- // unrefs the existing canvas
- mCanvas.reset(newCanvas);
+ // deletes the previously owned canvas (if any)
+ mCanvasOwned = std::unique_ptr<SkCanvas>(newCanvas);
+ mCanvas = newCanvas;
// clean up the old save stack
mSaveStack.reset(nullptr);
@@ -307,7 +312,7 @@
const SkMatrix saveMatrix = mCanvas->getTotalMatrix();
for (auto clip = begin; clip != end; ++clip) {
- clip->apply(mCanvas.get());
+ clip->apply(mCanvas);
}
mCanvas->setMatrix(saveMatrix);
@@ -562,7 +567,7 @@
void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
SkBitmap bitmap;
hwuiBitmap.getSkBitmap(&bitmap);
- SkAutoCanvasRestore acr(mCanvas.get(), true);
+ SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
mCanvas->drawBitmap(bitmap, 0, 0, paint);
}
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index a0cdfcb..4f1d857 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -35,15 +35,15 @@
* Create a new SkiaCanvas.
*
* @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
- * not be NULL. This constructor will ref() the SkCanvas, and unref()
- * it in its destructor.
+ * not be NULL. This constructor does not take ownership, so the caller
+ * must guarantee that it remains valid while the SkiaCanvas is valid.
*/
explicit SkiaCanvas(SkCanvas* canvas);
virtual ~SkiaCanvas();
virtual SkCanvas* asSkCanvas() override {
- return mCanvas.get();
+ return mCanvas;
}
virtual void resetRecording(int width, int height,
@@ -182,7 +182,9 @@
class Clip;
- sk_sp<SkCanvas> mCanvas;
+ std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
+ SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
+ // unless it is the same as mCanvasOwned.get()
std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
std::vector<Clip> mClipStack; // tracks persistent clips.
};
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d6b6548..d3e765d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -246,7 +246,7 @@
if (!uploadBitmapToGraphicBuffer(caches, bitmap, *buffer, format, type)) {
return nullptr;
}
- return sk_sp<Bitmap>(new Bitmap(std::move(buffer), info));
+ return sk_sp<Bitmap>(new Bitmap(buffer.get(), info));
}
sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(SkBitmap& bitmap) {
@@ -301,6 +301,16 @@
info, pixelRef.rowBytes(), pixelRef.colorTable()));
}
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
+ PixelFormat format = graphicBuffer->getPixelFormat();
+ if (!graphicBuffer.get() || format != PIXEL_FORMAT_RGBA_8888) {
+ return nullptr;
+ }
+ SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
+}
+
void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
if (kIndex_8_SkColorType != newInfo.colorType()) {
ctable = nullptr;
@@ -360,16 +370,14 @@
reconfigure(info, rowBytes, ctable);
}
-Bitmap::Bitmap(sp<GraphicBuffer>&& buffer, const SkImageInfo& info)
+Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
: SkPixelRef(info)
, mPixelStorageType(PixelStorageType::Hardware) {
- auto rawBuffer = buffer.get();
- mPixelStorage.hardware.buffer = rawBuffer;
- if (rawBuffer) {
- rawBuffer->incStrong(rawBuffer);
- }
+ mPixelStorage.hardware.buffer = buffer;
+ buffer->incStrong(buffer);
mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
}
+
Bitmap::~Bitmap() {
switch (mPixelStorageType) {
case PixelStorageType::External:
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 663238c..518be03 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -52,6 +52,8 @@
static sk_sp<Bitmap> allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info,
size_t rowBytes, SkColorTable* ctable);
+ static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
+
static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
static sk_sp<Bitmap> allocateHardwareBitmap(uirenderer::renderthread::RenderThread&,
@@ -63,7 +65,6 @@
const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
size_t rowBytes, SkColorTable* ctable);
- Bitmap(sp<GraphicBuffer>&& buffer, const SkImageInfo& info);
int width() const { return info().width(); }
int height() const { return info().height(); }
@@ -113,6 +114,7 @@
virtual void onUnlockPixels() override { };
virtual size_t getAllocatedSizeInBytes() const override;
private:
+ Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
virtual ~Bitmap();
void* getStorage() const;
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index da9002d..4b34c7c 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -174,13 +174,22 @@
}
renderNode->getLayerSurface()->draw(canvas, 0, 0, paint);
- if (CC_UNLIKELY(Properties::debugLayersUpdates
- && !renderNode->getSkiaLayer()->hasRenderedSinceRepaint)) {
+ if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) {
renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true;
- SkPaint layerPaint;
- layerPaint.setColor(0x7f00ff00);
- canvas->drawRect(bounds, layerPaint);
+ if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
+ SkPaint layerPaint;
+ layerPaint.setColor(0x7f00ff00);
+ canvas->drawRect(bounds, layerPaint);
+ } else if (CC_UNLIKELY(Properties::debugOverdraw)) {
+ // Render transparent rect to increment overdraw for repaint area.
+ // This can be "else if" because flashing green on layer updates
+ // will also increment the overdraw if it happens to be turned on.
+ SkPaint transparentPaint;
+ transparentPaint.setColor(SK_ColorTRANSPARENT);
+ canvas->drawRect(bounds, transparentPaint);
+ }
}
+
// composing a software layer with alpha
} else if (properties.effectiveLayerType() == LayerType::Software) {
SkPaint paint;
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 6973209..d05e7f6 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -40,7 +40,7 @@
//mChildren is allocated and initialized only the first time onDraw is called and cached for
//subsequent calls
mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
- for (unsigned int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
+ for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
}
}
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 298a732..9f00d23 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -47,8 +47,8 @@
virtual void onDraw(SkCanvas* canvas) override;
private:
- size_t mEndChildIndex;
- size_t mBeginChildIndex;
+ int mEndChildIndex;
+ int mBeginChildIndex;
FatVector<RenderNodeDrawable*, 16> mChildren;
SkiaDisplayList* mDisplayList;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index c5a40d4..0f2d09d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -18,6 +18,8 @@
#include "utils/TraceUtils.h"
#include <SkOSFile.h>
+#include <SkOverdrawCanvas.h>
+#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
#include <SkPixelSerializer.h>
@@ -192,6 +194,34 @@
}
}
+ renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas);
+
+ if (skpCaptureEnabled() && recordingPicture) {
+ sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
+ if (picture->approximateOpCount() > 0) {
+ SkFILEWStream stream(prop);
+ if (stream.isValid()) {
+ PngPixelSerializer serializer;
+ picture->serialize(&stream, &serializer);
+ stream.flush();
+ SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
+ }
+ }
+ surface->getCanvas()->drawPicture(picture);
+ }
+
+ if (CC_UNLIKELY(Properties::debugOverdraw)) {
+ renderOverdraw(layers, clip, nodes, contentDrawBounds, surface);
+ }
+
+ ATRACE_NAME("flush commands");
+ canvas->flush();
+}
+
+void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, const Rect &contentDrawBounds,
+ SkCanvas* canvas) {
+
canvas->clipRect(clip, SkRegion::kReplace_Op);
if (!opaque) {
@@ -250,23 +280,6 @@
canvas->restoreToCount(count);
layer++;
}
-
- if (skpCaptureEnabled() && recordingPicture) {
- sk_sp<SkPicture> picture = recorder->finishRecordingAsPicture();
- if (picture->approximateOpCount() > 0) {
- SkFILEWStream stream(prop);
- if (stream.isValid()) {
- PngPixelSerializer serializer;
- picture->serialize(&stream, &serializer);
- stream.flush();
- SkDebugf("Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(), prop);
- }
- }
- surface->getCanvas()->drawPicture(picture);
- }
-
- ATRACE_NAME("flush commands");
- canvas->flush();
}
void SkiaPipeline::dumpResourceCacheUsage() const {
@@ -283,6 +296,40 @@
ALOGD("%s", log.c_str());
}
+// Overdraw debugging
+
+// These colors should be kept in sync with Caches::getOverdrawColor() with a few differences.
+// This implementation:
+// (1) Requires transparent entries for "no overdraw" and "single draws".
+// (2) Requires premul colors (instead of unpremul).
+// (3) Requires RGBA colors (instead of BGRA).
+static const uint32_t kOverdrawColors[2][6] = {
+ { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
+ { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
+};
+
+void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+ const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
+ sk_sp<SkSurface> surface) {
+ // Set up the overdraw canvas.
+ SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
+ sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
+ SkOverdrawCanvas overdrawCanvas(offscreen->getCanvas());
+
+ // Fake a redraw to replay the draw commands. This will increment the alpha channel
+ // each time a pixel would have been drawn.
+ // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
+ // initialized.
+ renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas);
+ sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
+
+ // Draw overdraw colors to the canvas. The color filter will convert counts to colors.
+ SkPaint paint;
+ const SkPMColor* colors = kOverdrawColors[static_cast<int>(Properties::overdrawColorSet)];
+ paint.setColorFilter(SkOverdrawColorFilter::Make(colors));
+ surface->getCanvas()->drawImage(counts.get(), 0.0f, 0.0f, &paint);
+}
+
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index c1c8cbe..c58fedf 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -107,6 +107,18 @@
renderthread::RenderThread& mRenderThread;
private:
+ void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+ const std::vector< sp<RenderNode> >& nodes, bool opaque, const Rect &contentDrawBounds,
+ SkCanvas* canvas);
+
+ /**
+ * Debugging feature. Draws a semi-transparent overlay on each pixel, indicating
+ * how many times it has been drawn.
+ */
+ void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+ const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
+ sk_sp<SkSurface>);
+
TaskManager mTaskManager;
std::vector<sk_sp<SkImage>> mPinnedImages;
static float mLightRadius;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6df544f..95db258 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -32,7 +32,6 @@
void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
int height) {
- mBarrierPending = false;
mCurrentBarrier = nullptr;
SkASSERT(mDisplayList.get() == nullptr);
@@ -76,8 +75,6 @@
}
void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
- mBarrierPending = enableReorder;
-
if (nullptr != mCurrentBarrier) {
// finish off the existing chunk
SkDrawable* drawable =
@@ -86,6 +83,12 @@
mCurrentBarrier = nullptr;
drawDrawable(drawable);
}
+ if (enableReorder) {
+ mCurrentBarrier = (StartReorderBarrierDrawable*)
+ mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
+ mDisplayList.get());
+ drawDrawable(mCurrentBarrier);
+ }
}
void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
@@ -97,15 +100,6 @@
}
void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
- // lazily create the chunk if needed
- if (mBarrierPending) {
- mCurrentBarrier = (StartReorderBarrierDrawable*)
- mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
- mDisplayList.get());
- drawDrawable(mCurrentBarrier);
- mBarrierPending = false;
- }
-
// record the child node
mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 8aef97f..10829f8 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -76,7 +76,6 @@
private:
SkLiteRecorder mRecorder;
std::unique_ptr<SkiaDisplayList> mDisplayList;
- bool mBarrierPending;
StartReorderBarrierDrawable* mCurrentBarrier;
/**
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 177a729..9dc2b59 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -88,7 +88,7 @@
caches.tessellationCache.trim();
#if DEBUG_MEMORY_USAGE
- mCaches.dumpMemoryUsage();
+ caches.dumpMemoryUsage();
#else
if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
caches.dumpMemoryUsage();
diff --git a/libs/hwui/tests/unit/BitmapTests.cpp b/libs/hwui/tests/unit/BitmapTests.cpp
new file mode 100644
index 0000000..8c7e081
--- /dev/null
+++ b/libs/hwui/tests/unit/BitmapTests.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "hwui/Bitmap.h"
+
+#include <SkBitmap.h>
+#include <SkColorTable.h>
+#include <SkImageInfo.h>
+
+#include <tests/common/TestUtils.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(Bitmap, colorTableRefCounting) {
+ const SkPMColor c[] = { SkPackARGB32(0x80, 0x80, 0, 0) };
+ SkColorTable* ctable = new SkColorTable(c, SK_ARRAY_COUNT(c));
+
+ SkBitmap* bm = new SkBitmap();
+ bm->allocPixels(SkImageInfo::Make(1, 1, kIndex_8_SkColorType, kPremul_SkAlphaType),
+ nullptr, ctable);
+ sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(bm, ctable);
+ EXPECT_FALSE(ctable->unique());
+ delete bm;
+ bitmap.reset();
+ EXPECT_TRUE(ctable->unique());
+ ctable->unref();
+}
+
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 8c956e5..a1c225f 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1530,6 +1530,8 @@
RENDERTHREAD_TEST(FrameBuilder, zReorder) {
auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
[](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
drawOrderedRect(&canvas, 1);
canvas.insertReorderBarrier(true);
@@ -1542,6 +1544,14 @@
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 8);
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+ drawOrderedRect(&canvas, 11);
+ drawOrderedNode(&canvas, 10, -1.0f);
+ canvas.insertReorderBarrier(false);
+ canvas.insertReorderBarrier(true); //test with two empty reorder sections
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 12);
});
FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
sLightGeometry, Caches::getInstance());
@@ -1549,7 +1559,7 @@
ZReorderTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(10, renderer.getIndex());
+ EXPECT_EQ(13, renderer.getIndex());
};
RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
diff --git a/libs/hwui/tests/unit/PathInterpolatorTests.cpp b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
new file mode 100644
index 0000000..d7cb23a
--- /dev/null
+++ b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Interpolator.h>
+
+namespace android {
+namespace uirenderer {
+
+struct TestData {
+ const std::vector<float> x;
+ const std::vector<float> y;
+ const std::vector<float> inFraction;
+ const std::vector<float> outFraction;
+};
+
+const static TestData sTestDataSet[] = {
+ {
+ // Straight line as a path.
+ {0.0f, 1.0f},
+ {0.0f, 1.0f},
+ {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
+ {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
+ },
+
+ {
+ {
+ 0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f, 0.5748291f,
+ 0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f, 0.6951172f,
+ 0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f, 0.871875f,
+ 0.9000244f, 0.93066406f, 0.96394044f, 1.0f
+ },
+ {
+ 0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
+ 0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
+ 0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
+ 0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f
+ },
+ {
+ 0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
+ 0.336834192276001f, 0.4508626461029053f, 0.564141035079956f,
+ 0.6781694889068604f, 0.7921979427337646f, 0.9054763317108154f, 1.0f
+ },
+ {
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f,
+ 0.5146934390068054f, 0.8607426285743713f, 0.9776809215545654f, 1.0f
+
+ }
+
+ },
+ {
+ {
+ 0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
+ 0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
+ 0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
+ 0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f
+ },
+ {
+ 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
+ 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
+ 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
+ 0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f
+ },
+ {
+ 0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f,
+ 0.43060302734375f, 0.5318756103515625f, 0.6331634521484375f,
+ 0.746429443359375f, 0.84771728515625f, 0.9617462158203125f, 1.0f
+ },
+ {
+ 0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f,
+ 0.9887426495552063f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
+ }
+ },
+
+
+};
+
+static std::vector<float> getX(const TestData& data) {
+ return data.x;
+}
+
+static std::vector<float> getY(const TestData& data) {
+ return data.y;
+}
+
+TEST(Interpolator, pathInterpolation) {
+ for (const TestData& data: sTestDataSet) {
+ PathInterpolator interpolator(getX(data), getY(data));
+ for (size_t i = 0; i < data.inFraction.size(); i++) {
+ EXPECT_FLOAT_EQ(data.outFraction[i], interpolator.interpolate(data.inFraction[i]));
+ }
+ }
+}
+
+}
+}
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index ae4f0f4..f4b686d 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -102,6 +102,8 @@
auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
drawOrderedRect(&canvas, 1);
canvas.insertReorderBarrier(true);
@@ -114,13 +116,21 @@
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 8);
drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+ drawOrderedRect(&canvas, 11);
+ drawOrderedNode(&canvas, 10, -1.0f);
+ canvas.insertReorderBarrier(false);
+ canvas.insertReorderBarrier(true); //test with two empty reorder sections
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 12);
});
//create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ZReorderCanvas canvas(100, 100);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
- EXPECT_EQ(10, canvas.getIndex());
+ EXPECT_EQ(13, canvas.getIndex());
}
TEST(RenderNodeDrawable, composeOnLayer)
@@ -303,40 +313,42 @@
static const int LAYER_HEIGHT = 200;
class ProjectionTestCanvas : public SkCanvas {
public:
- ProjectionTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
+ ProjectionTestCanvas(int* drawCounter)
+ : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
+ , mDrawCounter(drawCounter)
+ {}
void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
const SkPaint&) override {
- EXPECT_EQ(0, mIndex++); //part of painting the layer
+ EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), getBounds(this));
}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- EXPECT_EQ(1, mIndex++);
+ EXPECT_EQ(1, (*mDrawCounter)++);
EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), getBounds(this));
}
void onDrawOval(const SkRect&, const SkPaint&) override {
- EXPECT_EQ(2, mIndex++);
+ EXPECT_EQ(2, (*mDrawCounter)++);
SkMatrix expectedMatrix;
expectedMatrix.setTranslate(100 - SCROLL_X, 100 - SCROLL_Y);
EXPECT_EQ(expectedMatrix, getTotalMatrix());
EXPECT_EQ(SkRect::MakeLTRB(-85, -80, 295, 300), getLocalBounds(this));
}
- int mIndex = 0;
+ int* mDrawCounter;
};
class ProjectionLayer : public SkSurface_Base {
public:
- ProjectionLayer(ProjectionTestCanvas *canvas)
+ ProjectionLayer(int* drawCounter)
: SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
- , mCanvas(canvas) {
+ , mDrawCounter(drawCounter) {
}
void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
- EXPECT_EQ(3, mCanvas->mIndex++);
+ EXPECT_EQ(3, (*mDrawCounter)++);
EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
- 300 - SCROLL_Y), getBounds(mCanvas));
+ 300 - SCROLL_Y), getBounds(this->getCanvas()));
}
SkCanvas* onNewCanvas() override {
- mCanvas->ref();
- return mCanvas;
+ return new ProjectionTestCanvas(mDrawCounter);
}
sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
return sk_sp<SkSurface>();
@@ -345,7 +357,7 @@
return sk_sp<SkImage>();
}
void onCopyOnWrite(ContentChangeMode) override {}
- ProjectionTestCanvas* mCanvas;
+ int* mDrawCounter;
};
auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
@@ -389,10 +401,10 @@
info.observer = nullptr;
parent->prepareTree(info);
- sk_sp<ProjectionTestCanvas> canvas(new ProjectionTestCanvas());
+ int drawCounter = 0;
//set a layer after prepareTree to avoid layer logic there
child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
- sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(canvas.get()));
+ sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
child->setLayerSurface(surfaceLayer1);
Matrix4 windowTransform;
windowTransform.loadTranslate(100, 100, 0);
@@ -402,11 +414,11 @@
layerUpdateQueue.enqueueLayerWithDamage(child.get(),
android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
SkiaPipeline::renderLayersImpl(layerUpdateQueue, true);
- EXPECT_EQ(1, canvas->mIndex); //assert index 0 is drawn on the layer
+ EXPECT_EQ(1, drawCounter); //assert index 0 is drawn on the layer
- RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
- canvas->drawDrawable(&drawable);
- EXPECT_EQ(4, canvas->mIndex);
+ RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
+ surfaceLayer1->getCanvas()->drawDrawable(&drawable);
+ EXPECT_EQ(4, drawCounter);
// clean up layer pointer, so we can safely destruct RenderNode
child->setLayerSurface(nullptr);
@@ -479,7 +491,7 @@
info.observer = nullptr;
parent->prepareTree(info);
- sk_sp<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
+ std::unique_ptr<ProjectionChildScrollTestCanvas> canvas(new ProjectionChildScrollTestCanvas());
RenderNodeDrawable drawable(parent.get(), canvas.get(), true);
canvas->drawDrawable(&drawable);
EXPECT_EQ(2, canvas->mIndex);
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7a2fa57..17801af 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -179,3 +179,53 @@
redNode->setLayerSurface(sk_sp<SkSurface>());
blueNode->setLayerSurface(sk_sp<SkSurface>());
}
+
+RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
+ ScopedProperty<bool> prop(Properties::debugOverdraw, true);
+
+ auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
+ LayerUpdateQueue layerUpdateQueue;
+ SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
+ std::vector<sp<RenderNode>> renderNodes;
+ renderNodes.push_back(whiteNode);
+ bool opaque = true;
+ android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
+ auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
+ auto surface = SkSurface::MakeRasterN32Premul(1, 1);
+
+ // Initialize the canvas to blue.
+ surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
+
+ // Single draw, should be white.
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
+
+ // 1 Overdraw, should be blue blended onto white.
+ renderNodes.push_back(whiteNode);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
+
+ // 2 Overdraw, should be green blended onto white
+ renderNodes.push_back(whiteNode);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
+
+ // 3 Overdraw, should be pink blended onto white.
+ renderNodes.push_back(whiteNode);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
+
+ // 4 Overdraw, should be red blended onto white.
+ renderNodes.push_back(whiteNode);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+
+ // 5 Overdraw, should be red blended onto white.
+ renderNodes.push_back(whiteNode);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 435e6ba..65eadb6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -801,8 +801,8 @@
* management of audio settings or the main telephony application.
*
* @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
- * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or
- * {@link #STREAM_ALARM}
+ * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
+ * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
@@ -3195,7 +3195,8 @@
* {@link #STREAM_MUSIC},
* {@link #STREAM_ALARM},
* {@link #STREAM_NOTIFICATION},
- * {@link #STREAM_DTMF}.
+ * {@link #STREAM_DTMF},
+ * {@link #STREAM_ACCESSIBILITY}.
*
* @return The bit-mask "or" of audio output device codes for all enabled devices on this
* stream. Zero or more of
@@ -3238,6 +3239,7 @@
case STREAM_ALARM:
case STREAM_NOTIFICATION:
case STREAM_DTMF:
+ case STREAM_ACCESSIBILITY:
return AudioSystem.getDevicesForStream(streamType);
default:
return 0;
diff --git a/media/java/android/media/IVolumeController.aidl b/media/java/android/media/IVolumeController.aidl
index 90ac416..7f37265 100644
--- a/media/java/android/media/IVolumeController.aidl
+++ b/media/java/android/media/IVolumeController.aidl
@@ -32,4 +32,11 @@
void setLayoutDirection(int layoutDirection);
void dismiss();
+
+ /**
+ * Change the a11y mode.
+ * @param a11yMode one of {@link VolumePolicy#A11Y_MODE_MEDIA_A11Y_VOLUME},
+ * {@link VolumePolicy#A11Y_MODE_INDEPENDENT_A11Y_VOLUME}
+ */
+ void setA11yMode(int mode);
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 36ad90b..eff5aac 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -127,7 +127,7 @@
* {@link #getVideoWidth()}, {@link #setAudioStreamType(int)},
* {@link #setLooping(boolean)},
* {@link #setVolume(float, float)}, {@link #pause()}, {@link #start()},
- * {@link #stop()}, {@link #seekTo(int)}, {@link #prepare()} or
+ * {@link #stop()}, {@link #seekTo(int, int)}, {@link #prepare()} or
* {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
* methods is called right after a MediaPlayer object is constructed,
* the user supplied callback method OnErrorListener.onError() won't be
@@ -273,19 +273,22 @@
* </ul>
* </li>
* <li>The playback position can be adjusted with a call to
- * {@link #seekTo(int)}.
+ * {@link #seekTo(int, int)}.
* <ul>
- * <li>Although the asynchronuous {@link #seekTo(int)}
- * call returns right way, the actual seek operation may take a while to
+ * <li>Although the asynchronuous {@link #seekTo(int, int)}
+ * call returns right away, the actual seek operation may take a while to
* finish, especially for audio/video being streamed. When the actual
* seek operation completes, the internal player engine calls a user
* supplied OnSeekComplete.onSeekComplete() if an OnSeekCompleteListener
* has been registered beforehand via
* {@link #setOnSeekCompleteListener(OnSeekCompleteListener)}.</li>
* <li>Please
- * note that {@link #seekTo(int)} can also be called in the other states,
+ * note that {@link #seekTo(int, int)} can also be called in the other states,
* such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
- * </em> state.</li>
+ * </em> state. When {@link #seekTo(int, int)} is called in those states,
+ * one video frame will be displayed if the stream has video and the requested
+ * position is valid.
+ * </li>
* <li>Furthermore, the actual current playback position
* can be retrieved with a call to {@link #getCurrentPosition()}, which
* is helpful for applications such as a Music player that need to keep
@@ -1502,13 +1505,107 @@
public native SyncParams getSyncParams();
/**
+ * Seek modes used in method seekTo(int, int) to move media position
+ * to a specified location.
+ *
+ * Do not change these mode values without updating their counterparts
+ * in include/media/IMediaSource.h!
+ */
+ /**
+ * This mode is used with {@link #seekTo(int, int)} to move media position to
+ * a sync (or key) frame associated with a data source that is located
+ * right before or at the given time.
+ *
+ * @see #seekTo(int, int)
+ */
+ public static final int SEEK_PREVIOUS_SYNC = 0x00;
+ /**
+ * This mode is used with {@link #seekTo(int, int)} to move media position to
+ * a sync (or key) frame associated with a data source that is located
+ * right after or at the given time.
+ *
+ * @see #seekTo(int, int)
+ */
+ public static final int SEEK_NEXT_SYNC = 0x01;
+ /**
+ * This mode is used with {@link #seekTo(int, int)} to move media position to
+ * a sync (or key) frame associated with a data source that is located
+ * closest to (in time) or at the given time.
+ *
+ * @see #seekTo(int, int)
+ */
+ public static final int SEEK_CLOSEST_SYNC = 0x02;
+ /**
+ * This mode is used with {@link #seekTo(int, int)} to move media position to
+ * a frame (not necessarily a key frame) associated with a data source that
+ * is located closest to or at the given time.
+ *
+ * @see #seekTo(int, int)
+ */
+ public static final int SEEK_CLOSEST = 0x03;
+
+ /** @hide */
+ @IntDef(
+ value = {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SeekMode {}
+
+ private native final void _seekTo(int msec, int mode);
+
+ /**
+ * Moves the media to specified time position by considering the given mode.
+ * <p>
+ * When seekTo is finished, the user will be notified via OnSeekComplete supplied by the user.
+ * There is at most one active seekTo processed at any time. If there is a to-be-completed
+ * seekTo, new seekTo requests will be queued in such a way that only the last request
+ * is kept. When current seekTo is completed, the queued request will be processed if
+ * that request is different from just-finished seekTo operation, i.e., the requested
+ * position or mode is different.
+ *
+ * @param msec the offset in milliseconds from the start to seek to.
+ * When seeking to the given time position, there is no guarantee that the data source
+ * has a frame located at the position. When this happens, a frame nearby will be rendered.
+ * If msec is negative, time position zero will be used.
+ * If msec is larger than duration, duration will be used.
+ * @param mode the mode indicating where exactly to seek to.
+ * Use {@link #SEEK_PREVIOUS_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp earlier than or the same as msec. Use
+ * {@link #SEEK_NEXT_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp later than or the same as msec. Use
+ * {@link #SEEK_CLOSEST_SYNC} if one wants to seek to a sync frame
+ * that has a timestamp closest to or the same as msec. Use
+ * {@link #SEEK_CLOSEST} if one wants to seek to a frame that may
+ * or may not be a sync frame but is closest to or the same as msec.
+ * {@link #SEEK_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at msec.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized
+ * @throws IllegalArgumentException if the mode is invalid.
+ */
+ public void seekTo(int msec, @SeekMode int mode) throws IllegalStateException {
+ if (mode < SEEK_PREVIOUS_SYNC || mode > SEEK_CLOSEST) {
+ final String msg = "Illegal seek mode: " + mode;
+ throw new IllegalArgumentException(msg);
+ }
+ _seekTo(msec, mode);
+ }
+
+ /**
* Seeks to specified time position.
+ * Same as {@link #seekTo(int, int)} with {@code mode = SEEK_PREVIOUS_SYNC}.
*
* @param msec the offset in milliseconds from the start to seek to
* @throws IllegalStateException if the internal player engine has not been
* initialized
*/
- public native void seekTo(int msec) throws IllegalStateException;
+ public void seekTo(int msec) throws IllegalStateException {
+ seekTo(msec, SEEK_PREVIOUS_SYNC /* mode */);
+ }
/**
* Get current playback position as a {@link MediaTimestamp}.
diff --git a/media/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
index 1d33128..bbcce82 100644
--- a/media/java/android/media/VolumePolicy.java
+++ b/media/java/android/media/VolumePolicy.java
@@ -25,6 +25,17 @@
public final class VolumePolicy implements Parcelable {
public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true, 400);
+ /**
+ * Accessibility volume policy where the STREAM_MUSIC volume (i.e. media volume) affects
+ * the STREAM_ACCESSIBILITY volume, and vice-versa.
+ */
+ public static final int A11Y_MODE_MEDIA_A11Y_VOLUME = 0;
+ /**
+ * Accessibility volume policy where the STREAM_ACCESSIBILITY volume is independent from
+ * any other volume.
+ */
+ public static final int A11Y_MODE_INDEPENDENT_A11Y_VOLUME = 1;
+
/** Allow volume adjustments lower from vibrate to enter ringer mode = silent */
public final boolean volumeDownToEnterSilent;
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 96c12dd..4de1d00 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -607,8 +607,6 @@
gFields.cryptoInfoSetID =
env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
-
- DataSource::RegisterDefaultSniffers();
}
static void android_media_MediaExtractor_native_setup(
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c825702..c52ed94 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -577,15 +577,15 @@
}
static void
-android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec)
+android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec, jint mode)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- ALOGV("seekTo: %d(msec)", msec);
- process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL );
+ ALOGV("seekTo: %d(msec), mode=%d", msec, mode);
+ process_media_player_call( env, thiz, mp->seekTo(msec, (MediaPlayerSeekMode)mode), NULL, NULL );
}
static jint
@@ -1056,7 +1056,7 @@
{"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
{"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams},
{"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams},
- {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
+ {"_seekTo", "(II)V", (void *)android_media_MediaPlayer_seekTo},
{"_pause", "()V", (void *)android_media_MediaPlayer_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
{"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index cf09c58..53ec6c8 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -284,6 +284,7 @@
// C function EGLSurface eglCreatePixmapSurface ( EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list )
+ @Deprecated
public static native EGLSurface eglCreatePixmapSurface(
EGLDisplay dpy,
EGLConfig config,
diff --git a/opengl/java/android/opengl/GLES30.java b/opengl/java/android/opengl/GLES30.java
index 74181c5..3b805d2 100644
--- a/opengl/java/android/opengl/GLES30.java
+++ b/opengl/java/android/opengl/GLES30.java
@@ -590,6 +590,10 @@
// C function void glGetBufferPointerv ( GLenum target, GLenum pname, GLvoid** params )
+ /**
+ * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+ * to be an instance of {@link java.nio.ByteBuffer}.
+ */
public static native java.nio.Buffer glGetBufferPointerv(
int target,
int pname
@@ -761,6 +765,10 @@
// C function GLvoid * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access )
+ /**
+ * The {@link java.nio.Buffer} instance returned by this method is guaranteed
+ * to be an instance of {@link java.nio.ByteBuffer}.
+ */
public static native java.nio.Buffer glMapBufferRange(
int target,
int offset,
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index cf58888..612d59c 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -98,6 +98,7 @@
boolean eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list);
EGLSurface eglCreatePbufferSurface(EGLDisplay display, EGLConfig config, int[] attrib_list);
+ @Deprecated
EGLSurface eglCreatePixmapSurface(EGLDisplay display, EGLConfig config, Object native_pixmap, int[] attrib_list);
EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, Object native_window, int[] attrib_list);
boolean eglDestroyContext(EGLDisplay display, EGLContext context);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 94286ec..5aa673b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -44,6 +44,7 @@
protected View mEcaView;
protected boolean mEnableHaptics;
private boolean mDismissing;
+ private CountDownTimer mCountdownTimer = null;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -215,11 +216,13 @@
protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
setPasswordEntryEnabled(false);
long elapsedRealtime = SystemClock.elapsedRealtime();
- new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+ long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
- int secondsRemaining = (int) (millisUntilFinished / 1000);
+ int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
mSecurityMessageDisplay.formatMessage(
R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
}
@@ -252,6 +255,10 @@
@Override
public void onPause() {
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ mCountdownTimer = null;
+ }
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
mPendingLockCheck = null;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 330632b..c2b57ff 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -325,12 +325,13 @@
mLockPatternView.clearPattern();
mLockPatternView.setEnabled(false);
final long elapsedRealtime = SystemClock.elapsedRealtime();
-
- mCountdownTimer = new CountDownTimer(elapsedRealtimeDeadline - elapsedRealtime, 1000) {
+ final long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
- final int secondsRemaining = (int) (millisUntilFinished / 1000);
+ final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
mSecurityMessageDisplay.formatMessage(
R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index cdcc05c..0a7bdbf 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -26,6 +26,7 @@
import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE;
import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_STATUS;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -191,8 +192,6 @@
// Password attempts
private SparseIntArray mFailedAttempts = new SparseIntArray();
- /** Tracks whether strong authentication hasn't been used since quite some time per user. */
- private ArraySet<Integer> mStrongAuthNotTimedOut = new ArraySet<>();
private final StrongAuthTracker mStrongAuthTracker;
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
@@ -209,6 +208,7 @@
private TrustManager mTrustManager;
private UserManager mUserManager;
private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
+ private LockPatternUtils mLockPatternUtils;
private final Handler mHandler = new Handler() {
@Override
@@ -576,8 +576,7 @@
}
public boolean isUnlockingWithFingerprintAllowed() {
- return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
- && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ return mStrongAuthTracker.isUnlockingWithFingerprintAllowed();
}
public boolean needsSlowUnlockTransition() {
@@ -588,16 +587,7 @@
return mStrongAuthTracker;
}
- /**
- * @return true if the user hasn't use strong authentication (pattern, PIN, password) since a
- * while and thus can't unlock with fingerprint, false otherwise
- */
- public boolean hasFingerprintUnlockTimedOut(int userId) {
- return !mStrongAuthNotTimedOut.contains(userId);
- }
-
public void reportSuccessfulStrongAuthUnlockAttempt() {
- mStrongAuthNotTimedOut.add(sCurrentUser);
scheduleStrongAuthTimeout();
if (mFpm != null) {
byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
@@ -738,7 +728,7 @@
public void onReceive(Context context, Intent intent) {
if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
int userId = intent.getIntExtra(USER_ID, -1);
- mStrongAuthNotTimedOut.remove(userId);
+ mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_TIMEOUT, userId);
notifyStrongAuthStateChanged(userId);
}
}
@@ -1110,7 +1100,8 @@
PERMISSION_SELF, null /* handler */);
mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
mTrustManager.registerTrustListener(this);
- new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker);
+ mLockPatternUtils = new LockPatternUtils(context);
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
@@ -1839,7 +1830,6 @@
pw.println(" disabled(DPM)=" + isFingerprintDisabled(userId));
pw.println(" possible=" + isUnlockWithFingerprintPossible(userId));
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
- pw.println(" timedout=" + hasFingerprintUnlockTimedOut(userId));
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
}
}
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index a67c84b..21716ca 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -97,8 +97,8 @@
<item msgid="79513688117503758">"Korte zijde"</item>
</string-array>
<string-array name="orientation_labels">
- <item msgid="4061931020926489228">"Portret"</item>
- <item msgid="3199660090246166812">"Landschap"</item>
+ <item msgid="4061931020926489228">"Staand"</item>
+ <item msgid="3199660090246166812">"Liggend"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Kan niet naar bestand schrijven"</string>
<string name="print_error_default_message" msgid="8602678405502922346">"Dat werkte niet. Probeer het opnieuw."</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d0abbf9..a281bba 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"ብጁ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"እገዛ እና ግብረመልስ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"ምናሌ"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"ጂኤምቲ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 0eebcd7..9f6c440 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"مخصص (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"المساعدة والتعليقات"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"القائمة"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"غرينيتش"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index cbb2271..cad5980 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Prilagođeni (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoć i povratne informacije"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meni"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index 12f103d..ba5b100 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Карыстальніцкі (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Даведка і водгукі"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 19382ec..c360f87 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalitzat (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda i suggeriments"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 032d73d..f331080 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Προσαρμοσμένη (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Βοήθεια και σχόλια"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Μενού"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 57738e8..e27822f 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Custom (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Help & feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 259e7fb..4353282 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ayuda y sugerencias"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 952fda8..3e08c77 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Pertsonalizatua (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Laguntza eta iritziak"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menua"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index bf96b59..648f7b3 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Muokattu (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ohje ja palaute"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valikko"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 1cded3d..a732ea1 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"કસ્ટમ (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"સહાય અને પ્રતિસાદ"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"મેનુ"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index 44cfe92..1241bee 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -25,7 +25,7 @@
<item msgid="8934131797783724664">"Սկանավորում…"</item>
<item msgid="8513729475867537913">"Միանում է..."</item>
<item msgid="515055375277271756">"Նույնականացում…"</item>
- <item msgid="1943354004029184381">"IP հասցեն գտնվում է...."</item>
+ <item msgid="1943354004029184381">"IP հասցեի ստացում…"</item>
<item msgid="4221763391123233270">"Միացված է"</item>
<item msgid="624838831631122137">"Կասեցված է"</item>
<item msgid="7979680559596111948">"Անջատվում է…"</item>
@@ -43,7 +43,7 @@
<item msgid="8937994881315223448">"Միացված է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ին"</item>
<item msgid="1330262655415760617">"Անջատված"</item>
<item msgid="7698638434317271902">"Անջատվում է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ից…"</item>
- <item msgid="197508606402264311">"Անջատված"</item>
+ <item msgid="197508606402264311">"Անջատած է"</item>
<item msgid="8578370891960825148">"Անհաջող"</item>
<item msgid="5660739516542454527">"Արգելափակված"</item>
<item msgid="1805837518286731242">"Վատ ցանցից ժամանակավոր խուսափում"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 07241b5..9559887 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"(<xliff:g id="DENSITYDPI">%d</xliff:g>) khusus"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Bantuan & masukan"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 8e8307b..8be8444 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Sérsniðið (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Hjálp og ábendingar"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Valmynd"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index d894ccf..74ee5a1 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizzato (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Guida e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 609cb33..8a3b81b 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"მორგებული (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"დახმარება და გამოხმაურება"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"მენიუ"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index cf8f382..20d8ae9 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -155,7 +155,7 @@
<string name="keep_screen_on" msgid="1146389631208760344">"ಎಚ್ಚರವಾಗಿರು"</string>
<string name="keep_screen_on_summary" msgid="2173114350754293009">"ಚಾರ್ಜ್ ಮಾಡುವಾಗ ಪರದೆಯು ಎಂದಿಗೂ ನಿದ್ರಾವಸ್ಥೆಗೆ ಹೋಗುವುದಿಲ್ಲ"</string>
<string name="bt_hci_snoop_log" msgid="3340699311158865670">"ಬ್ಲೂಟೂತ್ HCI ಸ್ನೂಪ್ಲಾಗ್"</string>
- <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ಫೈಲ್ನಲ್ಲಿ ಎಲ್ಲ bluetooth HCI ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
+ <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"ಫೈಲ್ನಲ್ಲಿ ಎಲ್ಲ ಬ್ಲೂಟೂತ್ HCI ಪ್ಯಾಕೆಟ್ಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
<string name="oem_unlock_enable" msgid="6040763321967327691">"OEM ಅನ್ಲಾಕ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="oem_unlock_enable_summary" msgid="4720281828891618376">"ಬೂಟ್ಲೋಡರ್ ಅನ್ಲಾಕ್ ಮಾಡಲು ಅನುಮತಿಸಿ"</string>
<string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM ಅನ್ಲಾಕ್ ಮಾಡುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index a2eb86d..3783cce 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Ыңгайлаштырылган (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Жардам жана жооп пикир"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 711b949..ebe8d00 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Приспособен (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Помош и повратни информации"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 20f64fe..be1fbc6 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index a8a918b..834580b 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"अनुकूलन (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"मद्दत र प्रतिक्रिया"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनु"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 8bb4579..0f2e6d4 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Aangepast (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Help en feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 4db3e6e..738974f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Niestandardowe (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Pomoc i opinie"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 7855beb..ab866c8 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 2c366c6..2e4bbdc8 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e comentários"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 7855beb..ab866c8 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizada (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Ajuda e feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 2cf68a5..5fd58a5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Прилагођени (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Помоћ и повратне информације"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Мени"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 975a4aa..ee93622 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Anpassad (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Hjälp och feedback"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Meny"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index b538545..29557ec 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Спеціальний масштаб (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Довідка й відгуки"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Меню"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 8d1056a..05879a2 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -341,6 +341,5 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Moslashtirilgan (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"Yordam va fikr-mulohaza"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menyu"</string>
- <!-- no translation found for time_zone_gmt (2587097992671450782) -->
- <skip />
+ <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index f0ec107..2b1582d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -135,11 +135,11 @@
mBackgroundHandler = new BackgroundHandler(mThread.getLooper());
// Only the owner can see all apps.
- mAdminRetrieveFlags = PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_DISABLED_COMPONENTS |
- PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS;
- mRetrieveFlags = PackageManager.GET_DISABLED_COMPONENTS |
- PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS;
+ mAdminRetrieveFlags = PackageManager.MATCH_ANY_USER |
+ PackageManager.MATCH_DISABLED_COMPONENTS |
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+ mRetrieveFlags = PackageManager.MATCH_DISABLED_COMPONENTS |
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
/**
* This is a trick to prevent the foreground thread from being delayed.
@@ -855,7 +855,7 @@
// explicitly include both direct boot aware and unaware components here.
List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
launchIntent,
- PackageManager.GET_DISABLED_COMPONENTS
+ PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 5c577f8..e520319 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -409,8 +409,8 @@
// Measure all apps hosted on this volume for all users
if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) {
final List<ApplicationInfo> apps = packageManager.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
+ PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
final List<ApplicationInfo> volumeApps = new ArrayList<>();
for (ApplicationInfo app : apps) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index b16cd08..c7efb07 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -79,6 +79,11 @@
*/
public Bundle metaData;
+ /**
+ * Optional key to use for this tile.
+ */
+ public String key;
+
public Tile() {
// Empty
}
@@ -113,6 +118,7 @@
dest.writeString(category);
dest.writeInt(priority);
dest.writeBundle(metaData);
+ dest.writeString(key);
}
public void readFromParcel(Parcel in) {
@@ -132,6 +138,7 @@
category = in.readString();
priority = in.readInt();
metaData = in.readBundle();
+ key = in.readString();
}
Tile(Parcel in) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 9442458..d12e8c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -102,6 +102,12 @@
/**
* Name of the meta-data item that should be set in the AndroidManifest.xml
+ * to specify the key that should be used for the preference.
+ */
+ public static final String META_DATA_PREFERENCE_KEYHINT = "com.android.settings.keyhint";
+
+ /**
+ * Name of the meta-data item that should be set in the AndroidManifest.xml
* to specify the icon that should be displayed for the preference.
*/
public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon";
@@ -292,6 +298,7 @@
int icon = 0;
CharSequence title = null;
String summary = null;
+ String keyHint = null;
// Get the activity's meta-data
try {
@@ -317,6 +324,13 @@
summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY);
}
}
+ if (metaData.containsKey(META_DATA_PREFERENCE_KEYHINT)) {
+ if (metaData.get(META_DATA_PREFERENCE_KEYHINT) instanceof Integer) {
+ keyHint = res.getString(metaData.getInt(META_DATA_PREFERENCE_KEYHINT));
+ } else {
+ keyHint = metaData.getString(META_DATA_PREFERENCE_KEYHINT);
+ }
+ }
}
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
if (DEBUG) Log.d(LOG_TAG, "Couldn't find info", e);
@@ -338,6 +352,8 @@
// Replace the intent with this specific activity
tile.intent = new Intent().setClassName(activityInfo.packageName,
activityInfo.name);
+ // Suggest a key for this tile
+ tile.key = keyHint;
return true;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index c189e1d..c4aa57d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -112,7 +112,7 @@
// Enable selected apps
try {
ApplicationInfo info = mIPm.getApplicationInfo(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ PackageManager.MATCH_ANY_USER, userId);
if (info == null || !info.enabled
|| (info.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mIPm.installExistingPackageAsUser(packageName, mUser.getIdentifier());
@@ -178,7 +178,7 @@
addSystemApps(mVisibleApps, widgetIntent, excludePackages);
List<ApplicationInfo> installedApps = pm.getInstalledApplications(
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
for (ApplicationInfo app : installedApps) {
// If it's not installed, skip
if ((app.flags & ApplicationInfo.FLAG_INSTALLED) == 0) continue;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 651a7cb..86b210a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -21,7 +21,9 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.ArrayMap;
@@ -43,6 +45,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -54,11 +57,14 @@
private Context mContext;
@Mock
private PackageManager mPackageManager;
+ @Mock
+ private Resources mResources;
@Before
- public void setUp() {
+ public void setUp() throws NameNotFoundException {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getResourcesForApplication(anyString())).thenReturn(mResources);
}
@Test
@@ -82,6 +88,27 @@
}
@Test
+ public void getTilesForIntent_shouldParseKeyHintForSystemApp() {
+ String keyHint = "key";
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, keyHint);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */);
+
+ assertThat(outTiles.size()).isEqualTo(1);
+ assertThat(outTiles.get(0).key).isEqualTo(keyHint);
+ }
+
+ @Test
public void getTilesForIntent_shouldSkipNonSystemApp() {
final String testCategory = "category1";
Intent intent = new Intent();
@@ -100,7 +127,12 @@
assertThat(outTiles.isEmpty()).isTrue();
}
+
private ResolveInfo newInfo(boolean systemApp, String category) {
+ return newInfo(systemApp, category, null);
+ }
+
+ private ResolveInfo newInfo(boolean systemApp, String category, String keyHint) {
ResolveInfo info = new ResolveInfo();
info.system = systemApp;
info.activityInfo = new ActivityInfo();
@@ -108,7 +140,13 @@
info.activityInfo.name = "123";
info.activityInfo.metaData = new Bundle();
info.activityInfo.metaData.putString("com.android.settings.category", category);
+ if (keyHint != null) {
+ info.activityInfo.metaData.putString("com.android.settings.keyhint", keyHint);
+ }
info.activityInfo.applicationInfo = new ApplicationInfo();
+ if (systemApp) {
+ info.activityInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
return info;
}
}
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 444f0f0..078f9d7 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,17 +24,36 @@
android:outlineProvider="none"
android:elevation="5dp" > <!-- Put it above the status bar header -->
- <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_text"
+ <LinearLayout
+ android:id="@+id/keyguard_indication_area"
+ android:forceHasOverlappingRendering="false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
android:layout_gravity="bottom|center_horizontal"
- android:gravity="center_horizontal"
- android:textStyle="italic"
- android:textColor="#ffffff"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:accessibilityLiveRegion="polite" />
+ android:orientation="vertical">
+
+ <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+ android:id="@+id/keyguard_indication_enterprise_disclosure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textStyle="italic"
+ android:textColor="#ffffff"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone" />
+
+ <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+ android:id="@+id/keyguard_indication_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textStyle="italic"
+ android:textColor="#ffffff"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:accessibilityLiveRegion="polite" />
+
+ </LinearLayout>
<FrameLayout
android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/notification_icon_area.xml b/packages/SystemUI/res/layout/notification_icon_area.xml
index c5b4e84..6732e6c 100644
--- a/packages/SystemUI/res/layout/notification_icon_area.xml
+++ b/packages/SystemUI/res/layout/notification_icon_area.xml
@@ -19,13 +19,7 @@
android:id="@+id/notification_icon_area_inner"
android:layout_width="match_parent"
android:layout_height="match_parent" >
- <com.android.systemui.statusbar.StatusBarIconView
- android:id="@+id/moreIcon"
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="match_parent"
- android:src="@drawable/stat_notify_more"
- android:visibility="gone" />
- <com.android.systemui.statusbar.phone.IconMerger
+ <com.android.systemui.statusbar.phone.NotificationIconContainer
android:id="@+id/notificationIcons"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 63af3e0..6784254 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -42,7 +42,7 @@
<LinearLayout android:id="@+id/status_bar_contents"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingStart="6dp"
+ android:paddingStart="@dimen/status_bar_padding_start"
android:paddingEnd="8dp"
android:orientation="horizontal"
>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
deleted file mode 100644
index 7df6bc6..0000000
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ /dev/null
@@ -1,74 +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
- -->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.statusbar.NotificationOverflowContainer
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/notification_summary_height"
- android:focusable="true"
- android:clickable="true"
- >
-
- <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundDimmed"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
-
- <com.android.keyguard.AlphaOptimizedLinearLayout
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <TextView
- android:id="@+id/more_text"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="12dp"
- android:layout_gravity="center_vertical"
- android:background="@drawable/keyguard_overflow_number_background"
- android:gravity="center"
- android:textColor="#ff686868"
- android:textStyle="bold"
- android:textSize="14dp"
- />
- <com.android.systemui.statusbar.StatusBarIconView
- android:id="@+id/more_icon_overflow"
- android:layout_width="@dimen/status_bar_icon_size"
- android:layout_height="match_parent"
- android:src="@drawable/stat_notify_more"
- android:tint="@color/keyguard_overflow_content_color"
- android:visibility="gone"
- />
- <com.android.systemui.statusbar.NotificationOverflowIconsView
- android:id="@+id/overflow_icons_view"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="8dp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- </com.android.keyguard.AlphaOptimizedLinearLayout>
-
- <com.android.systemui.statusbar.notification.FakeShadowView
- android:id="@+id/fake_shadow"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-</com.android.systemui.statusbar.NotificationOverflowContainer>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_shelf.xml b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
new file mode 100644
index 0000000..7bfbd3c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_shelf.xml
@@ -0,0 +1,47 @@
+<!--
+ ~ 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
+ -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.NotificationShelf
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_shelf_height"
+ android:focusable="true"
+ android:clickable="true"
+ >
+
+ <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+ <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundDimmed"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+ <com.android.systemui.statusbar.phone.NotificationIconContainer
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/shelf_icon_container_padding"
+ android:paddingEnd="@dimen/shelf_icon_container_padding"
+ android:gravity="center_vertical" />
+
+ <com.android.systemui.statusbar.notification.FakeShadowView
+ android:id="@+id/fake_shadow"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</com.android.systemui.statusbar.NotificationShelf>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5294c9c..40308dc 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Toeganklikheid"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om te ontdemp."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om op vibreer te stel. Toeganklikheidsdienste kan dalk gedemp wees."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 601930a..f807ba9 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"ተደራሽነት"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s። ድምጸ-ከል ለማድረግ መታ ያድርጉ"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s። ወደ ንዝረት ለማቀናበር መታ ያድርጉ። የተደራሽነት አገልግሎቶች ድምጸ-ከል ሊደረግባቸው ይችላል።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index a1a8f8d..33110ce 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -459,6 +459,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"إمكانية الوصول"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. انقر لإلغاء التجاهل."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. انقر للتعيين على الاهتزاز. قد يتم تجاهل خدمات إمكانية الوصول."</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 1bc9e59..49f27b2 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Münasiblik"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Səsli etmək üçün tıklayın."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Vibrasiyanı ayarlamaq üçün tıklayın. Əlçatımlılıq xidmətləri səssiz edilmiş ola bilər."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8105d9e..dc21bde 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Pristupačnost"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 83c67d4..ac93da7 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -457,6 +457,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Спецыяльныя магчымасці"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дакраніцеся, каб уключыць гук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index bf3a614..7814efb 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Достъпност"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Докоснете, за да включите отново звука."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Докоснете, за да зададете вибриране. Възможно е звукът на услугите за достъпност да бъде заглушен."</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index bd599bc..c80efa4 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> হল ভলিউম ডায়লগ"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"আসলটি পুনঃস্থাপন করতে আলতো চাপ দিন৷"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"আপনি আপনার কাজের প্রোফাইল ব্যবহার করছেন"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"কল করুন"</item>
- <item msgid="5997713001067658559">"সিস্টেম"</item>
- <item msgid="7858983209929864160">"রিং"</item>
- <item msgid="1850038478268896762">"মিডিয়া"</item>
- <item msgid="8265110906352372092">"অ্যালার্ম"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ব্লুটুথ"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। সশব্দ করতে আলতো চাপুন।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। কম্পন এ সেট করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। নিঃশব্দ করতে আলতো চাপুন। অ্যাক্সেসযোগ্যতার পরিষেবাগুলিকে নিঃশব্দ করা হতে পারে।"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index 5ba720c..2d02a4f 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Pristupačnost"</item>
</string-array>
<!-- String.format failed for translation -->
<!-- no translation found for volume_stream_content_description_unmute (4436631538779230857) -->
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 927e75b..b0e6fe5 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accessibilitat"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca per activar el so."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca per activar la vibració. Pot ser que els serveis d\'accessibilitat se silenciïn."</string>
@@ -472,7 +473,7 @@
<string name="status_bar_airplane" msgid="7057575501472249002">"Mode d\'avió"</string>
<string name="add_tile" msgid="2995389510240786221">"Afegeix un mosaic"</string>
<string name="broadcast_tile" msgid="3894036511763289383">"Mosaic d\'emissió"</string>
- <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Si no desactives aquesta opció abans, <xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Si no desactives aquesta opció abans, no sentiràs la pròxima alarma (<xliff:g id="WHEN">%1$s</xliff:g>)"</string>
<string name="zen_alarm_warning" msgid="444533119582244293">"<xliff:g id="WHEN">%1$s</xliff:g> no sentiràs la pròxima alarma"</string>
<string name="alarm_template" msgid="3980063409350522735">"Hora: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="4242179982586714810">"Dia: <xliff:g id="WHEN">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 69629a9..639f8b5 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -457,6 +457,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Přístupnost"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnete zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujete režim vibrací. Služby přístupnosti mohou být ztlumeny."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8e34bd0..8fa27ad 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er dialogboksen for lydstyrke"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Tryk for at gendanne det oprindelige."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du bruger din arbejdsprofil"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Opkald"</item>
- <item msgid="5997713001067658559">"System"</item>
- <item msgid="7858983209929864160">"Ring"</item>
- <item msgid="1850038478268896762">"Medier"</item>
- <item msgid="8265110906352372092">"Alarm"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryk for at slå lyden til."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryk for at konfigurere til at vibrere. Tilgængelighedstjenester kan blive deaktiveret."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Tryk for at slå lyden fra. Lyden i tilgængelighedstjenester kan blive slået fra."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index b3a457d..564625f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Tippe, um das Original wiederherzustellen."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du verwendest dein Arbeitsprofil."</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Anruf"</item>
- <item msgid="5997713001067658559">"System"</item>
- <item msgid="7858983209929864160">"Klingeln lassen"</item>
- <item msgid="1850038478268896762">"Medien"</item>
- <item msgid="8265110906352372092">"Wecker"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Zum Aufheben der Stummschaltung tippen."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tippen, um Vibrieren festzulegen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Zum Stummschalten tippen. Bedienungshilfen werden unter Umständen stummgeschaltet."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 050d7f8..a5c790c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Προσβασιμότητα"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Πατήστε για κατάργηση σίγασης."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Πατήστε για ενεργοποιήσετε τη δόνηση. Οι υπηρεσίες προσβασιμότητας ενδέχεται να τεθούν σε σίγαση."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accessibility"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accessibility"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9aca3cc..5dacfb2 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accessibility"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tap to unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tap to set to vibrate. Accessibility services may be muted."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 90c2ca1..3ba4360 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accesibilidad"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Presiona para dejar de silenciar."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Presiona para establecer el modo vibración. Es posible que los servicios de accesibilidad estén silenciados."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 0a45ac1..969f812 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accesibilidad"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar el sonido."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para poner el dispositivo en vibración. Los servicios de accesibilidad pueden silenciarse."</string>
@@ -491,8 +492,8 @@
<string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
<string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
- <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
- <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar ajustes rápidos"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en ajustes rápidos"</string>
<string name="experimental" msgid="6198182315536726162">"Experimental"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 84fadb2..e1ebfd2 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on helitugevuse dialoog"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Puudutage originaali taastamiseks."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Kasutate oma tööprofiili"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Helistamine"</item>
- <item msgid="5997713001067658559">"Süsteem"</item>
- <item msgid="7858983209929864160">"Helin"</item>
- <item msgid="1850038478268896762">"Meedia"</item>
- <item msgid="8265110906352372092">"Äratus"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Puudutage vaigistuse tühistamiseks."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Puudutage värinarežiimi määramiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Puudutage vaigistamiseks. Juurdepääsetavuse teenused võidakse vaigistada."</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d6578a2..fa0c711 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Erabilerraztasuna"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sakatu audioa aktibatzeko."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index e00c5b5..bd3c4fc 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> کنترلکننده صدا است"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"برای بازیابی نسخه اصلی ضربه بزنید."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"درحال استفاده از نمایه کاریتان هستید"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"تماس"</item>
- <item msgid="5997713001067658559">"سیستم"</item>
- <item msgid="7858983209929864160">"تماس"</item>
- <item msgid="1850038478268896762">"رسانه"</item>
- <item msgid="8265110906352372092">"هشدار"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"بلوتوث"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. برای باصدا کردن ضربه بزنید."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. برای تنظیم روی لرزش ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. برای بیصدا کردن ضربه بزنید. ممکن است سرویسهای دسترسپذیری بیصدا شوند."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 08572fe..446c9f8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Esteettömyys"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Poista mykistys koskettamalla."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Siirry värinätilaan koskettamalla. Myös esteettömyyspalvelut saattavat mykistyä."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 830bfa7..a03e897 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Touchez pour restaurer l\'original."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Appeler"</item>
- <item msgid="5997713001067658559">"Système"</item>
- <item msgid="7858983209929864160">"Sonnerie"</item>
- <item msgid="1850038478268896762">"Multimédia"</item>
- <item msgid="8265110906352372092">"Alarme"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Touchez pour réactiver le son."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Touchez pour activer les vibrations. Il est possible de couper le son des services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Touchez pour couper le son. Il est possible de couper le son des services d\'accessibilité."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3b138c2..1e72795 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Appuyez pour rétablir la version d\'origine."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Vous utilisez votre profil professionnel."</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Appeler"</item>
- <item msgid="5997713001067658559">"Système"</item>
- <item msgid="7858983209929864160">"Sonnerie"</item>
- <item msgid="1850038478268896762">"Multimédia"</item>
- <item msgid="8265110906352372092">"Alarme"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Appuyez pour ne plus ignorer."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Appuyez pour mettre en mode vibreur. Vous pouvez ignorer les services d\'accessibilité."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Appuyez pour ignorer. Vous pouvez ignorer les services d\'accessibilité."</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 579335d..515c729 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accesibilidade"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toca para activar o son."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toca para establecer a vibración. Pódense silenciar os servizos de accesibilidade."</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 48a6d0f..9778b86 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"ઍક્સેસિબિલિટી"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. અનમ્યૂટ કરવા માટે ટૅપ કરો."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. વાઇબ્રેટ પર સેટ કરવા માટે ટૅપ કરો. ઍક્સેસિબિલિટી સેવાઓ મ્યૂટ કરવામાં આવી શકે છે."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 97f3926..1010126 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"मूल को पुन: स्थापित करने के लिए टैप करें."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"आप अपनी कार्य प्रोफ़ाइल का उपयोग कर रहे हैं"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"कॉल करें"</item>
- <item msgid="5997713001067658559">"सिस्टम"</item>
- <item msgid="7858983209929864160">"रिंग करें"</item>
- <item msgid="1850038478268896762">"मीडिया"</item>
- <item msgid="8265110906352372092">"अलार्म"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ब्लूटूथ"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. अनम्यूट करने के लिए टैप करें."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन पर सेट करने के लिए टैप करें. एक्सेस-योग्यता सेवाएं म्यूट हो सकती हैं."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. म्यूट करने के लिए टैप करें. एक्सेस-योग्यता सेवाएं म्यूट हो सकती हैं."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7ff63bd..5d9162e 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Pristupačnost"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste postavili na vibraciju. Usluge pristupačnosti možda neće imati zvuk."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index bd0805b..bb78030 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Kisegítő lehetőségek"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Koppintson a némítás megszüntetéséhez."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Koppintson a rezgés beállításához. Előfordulhat, hogy a kisegítő lehetőségek szolgáltatásai le vannak némítva."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 07966cf..d9ec09e 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ձայնի ուժգնության երկխոսության հավելված է"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Հպեք՝ բնօրինակը վերականգնելու համար:"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Դուք օգտագործում եք ձեր աշխատանքային պրոֆիլը"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Զանգել"</item>
- <item msgid="5997713001067658559">"Համակարգ"</item>
- <item msgid="7858983209929864160">"Զանգ"</item>
- <item msgid="1850038478268896762">"Մեդիա"</item>
- <item msgid="8265110906352372092">"Զարթուցիչ"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s: Հպեք՝ ձայնը միացնելու համար:"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s: Հպեք՝ թրթռումը միացնելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s: Հպեք՝ ձայնն անջատելու համար: Մատչելիության ծառայությունների ձայնը կարող է անջատվել:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6444ae5..49d5221 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Aksesibilitas"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketuk untuk menyuarakan."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketuk untuk menyetel agar bergetar. Layanan aksesibilitas mungkin dibisukan."</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 7e08a01..f95d35f 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Aðgengi"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ýttu til að hætta að þagga."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ýttu til að stilla á titring. Hugsanlega verður slökkt á hljóði aðgengisþjónustu."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8ffb10d..b30516d 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Accessibilità"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tocca per riattivare l\'audio."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tocca per attivare la vibrazione. L\'audio dei servizi di accessibilità può essere disattivato."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a6d7983..c9f907a 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -444,18 +444,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> הוא תיבת הדו-שיח של עוצמת הקול"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"הקש כדי לשחזר את המקור."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"אתה משתמש בפרופיל העבודה שלך"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"שיחה"</item>
- <item msgid="5997713001067658559">"מערכת"</item>
- <item msgid="7858983209929864160">"השמע צלצול"</item>
- <item msgid="1850038478268896762">"מדיה"</item>
- <item msgid="8265110906352372092">"התראה"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. הקש כדי לבטל את ההשתקה."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. הקש כדי להגדיר רטט. ייתכן ששירותי הנגישות מושתקים."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. הקש כדי להשתיק. ייתכן ששירותי הנגישות מושתקים."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6ef9f73..b891b61 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>を音量ダイアログとして使用"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"タップすると元に戻ります。"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"仕事用プロファイルを使用しています"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"通話"</item>
- <item msgid="5997713001067658559">"システム"</item>
- <item msgid="7858983209929864160">"着信音"</item>
- <item msgid="1850038478268896762">"メディア"</item>
- <item msgid="8265110906352372092">"アラーム"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。タップしてミュートを解除します。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。タップしてバイブレーションに設定します。ユーザー補助機能サービスがミュートされる場合があります。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。タップしてミュートします。ユーザー補助機能サービスがミュートされる場合があります。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 695279d..e00d6b3 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"მარტივი წვდომა"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. შეეხეთ დადუმების გასაუქმებლად."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. შეეხეთ ვიბრაციაზე დასაყენებლად. შეიძლება დადუმდეს მარტივი წვდომის სერვისებიც."</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index ba71182..92b94bd 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> — көлем диалогтық терезесі"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Бастапқы қалпына келтіру үшін түртіңіз."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Сіз жұмыс профиліңізді пайдаланып жатырсыз"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Қоңырау шалу"</item>
- <item msgid="5997713001067658559">"Жүйе"</item>
- <item msgid="7858983209929864160">"Шылдырлау"</item>
- <item msgid="1850038478268896762">"Мультимeдиа"</item>
- <item msgid="8265110906352372092">"Дабыл"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дыбысын қосу үшін түртіңіз."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Діріл режимін орнату үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дыбысын өшіру үшін түртіңіз. Арнайы мүмкіндік қызметтерінің дыбысы өшуі мүмкін."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index b222555..9a352fc 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> គឺជាប្រអប់សម្លេង"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"ប៉ះដើម្បីស្តារច្បាប់ដើម"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"អ្នកកំពុងប្រើប្រវត្តិរូបការងាររបស់អ្នក"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"ហៅ"</item>
- <item msgid="5997713001067658559">"ប្រព័ន្ធ"</item>
- <item msgid="7858983209929864160">"រោទ៍"</item>
- <item msgid="1850038478268896762">"មេឌៀ"</item>
- <item msgid="8265110906352372092">"ម៉ោងរោទ៍"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ប៊្លូធូស"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s។ ប៉ះដើម្បីបើកសំឡេង។"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s។ ប៉ះដើម្បីកំណត់ឲ្យញ័រ។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s។ ប៉ះដើម្បីបិទសំឡេង។ សេវាកម្មលទ្ធភាពប្រើប្រាស់អាចនឹងត្រូវបានបិទសំឡេង។"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index b2a6f27..990c721 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಿದೆ"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"ಮೂಲಕ್ಕೆ ಮರುಸ್ಥಾಪಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ನೀವು ಬಳಸುತ್ತಿರುವಿರಿ"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"ಕರೆಮಾಡಿ"</item>
- <item msgid="5997713001067658559">"ಸಿಸ್ಟಂ"</item>
- <item msgid="7858983209929864160">"ಉಂಗುರ"</item>
- <item msgid="1850038478268896762">"ಮಾಧ್ಯಮ"</item>
- <item msgid="8265110906352372092">"ಅಲಾರಮ್"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ಬ್ಲೂಟೂತ್"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ಅನ್ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ಕಂಪನಕ್ಕೆ ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ಮ್ಯೂಟ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಪ್ರವೇಶಿಸುವಿಕೆ ಸೇವೆಗಳನ್ನು ಮ್ಯೂಟ್ ಮಾಡಬಹುದು."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index cefb57a..b06f15e 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"원본을 복원하려면 탭하세요."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"직장 프로필을 사용하고 있습니다."</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"통화"</item>
- <item msgid="5997713001067658559">"시스템"</item>
- <item msgid="7858983209929864160">"벨 울리기"</item>
- <item msgid="1850038478268896762">"미디어"</item>
- <item msgid="8265110906352372092">"알람"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"블루투스"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. 탭하여 음소거를 해제하세요."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. 탭하여 진동으로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. 탭하여 음소거로 설정하세요. 접근성 서비스가 음소거될 수 있습니다."</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index e013c6b..d5af0b3 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Атайын мүмкүнчүлүктөр"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Үнүн чыгаруу үчүн таптап коюңуз."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дирилдөөгө коюу үчүн таптап коюңуз. Атайын мүмкүнчүлүктөр кызматынын үнүн өчүрүп койсо болот."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 94e789a..711a68d 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນໜ້າຕ່າງລະດັບສຽງ"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"ແຕະເພື່ອກູ້ຕົ້ນສະບັບຄືນມາ."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ທ່ານກຳລັງໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານ"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"ໂທ"</item>
- <item msgid="5997713001067658559">"ລະບົບ"</item>
- <item msgid="7858983209929864160">"ເຕືອນດ້ວຍສຽງ"</item>
- <item msgid="1850038478268896762">"ມີເດຍ"</item>
- <item msgid="8265110906352372092">"ໂມງປຸກ"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ແຕະເພື່ອເຊົາປິດສຽງ."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. ແຕະເພື່ອຕັ້ງເປັນສັ່ນ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ແຕະເພື່ອປິດສຽງ. ບໍລິການຊ່ວຍເຂົ້າເຖິງອາດຖືກປິດສຽງໄວ້."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5af5979..aec484d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -444,18 +444,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ yra garsumo valdymo dialogo langas"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Palieskite, kad atkurtumėte originalą."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Naudojate darbo profilį"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Skambinti"</item>
- <item msgid="5997713001067658559">"Sistema"</item>
- <item msgid="7858983209929864160">"Skambinti"</item>
- <item msgid="1850038478268896762">"Medija"</item>
- <item msgid="8265110906352372092">"Signalas"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Palieskite, kad įjungtumėte garsą."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Palieskite, kad nustatytumėte vibravimą. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Palieskite, kad nutildytumėte. Gali būti nutildytos pritaikymo neįgaliesiems paslaugos."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 503c8c8..900a955d 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ir skaļuma dialoglodziņš"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Pieskarieties, lai atjaunotu sākotnējo saturu."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Jūs izmantojat darba profilu."</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Zvans"</item>
- <item msgid="5997713001067658559">"Sistēma"</item>
- <item msgid="7858983209929864160">"Zvanīt"</item>
- <item msgid="1850038478268896762">"Multivide"</item>
- <item msgid="8265110906352372092">"Signāls"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Pieskarieties, lai ieslēgtu skaņu."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Pieskarieties, lai iestatītu uz vibrozvanu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Pieskarieties, lai izslēgtu skaņu. Var tikt izslēgti pieejamības pakalpojumu signāli."</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 62fc350..716f76c 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Пристапност"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Допрете за да вклучите звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Допрете за да поставите на вибрации. Можеби ќе се исклучи звукот на услугите за достапност."</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 9e7d2f2..6c14826 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"ഒറിജിനൽ പുനഃസ്ഥാപിക്കാൻ ടാപ്പുചെയ്യുക."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"നിങ്ങൾ ഉപയോഗിക്കുന്നത് ഔദ്യോഗിക പ്രൊഫൈലാണ്"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"വിളിക്കുക"</item>
- <item msgid="5997713001067658559">"സിസ്റ്റം"</item>
- <item msgid="7858983209929864160">"റിംഗുചെയ്യുക"</item>
- <item msgid="1850038478268896762">"മീഡിയ"</item>
- <item msgid="8265110906352372092">"അലാറം"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ബ്ലൂടൂത്ത്"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. അൺമ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. വൈബ്രേറ്റിലേക്ക് സജ്ജമാക്കുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. മ്യൂട്ടുചെയ്യുന്നതിന് ടാപ്പുചെയ്യുക. പ്രവേശനക്ഷമതാ സേവനങ്ങൾ മ്യൂട്ടുചെയ്യപ്പെട്ടേക്കാം."</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 04fb4c2..8171310 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -410,12 +410,12 @@
<string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Таны төхөөрөмжийн удирдагч <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nТаны админ таны төхөөрөмжтэй холбоотой тохиргоо, байгууллагын хандалт, мэдээлэл болон байршлын мэдээллийг удирдан, хяналт тавих боломжтой.\n\nТа таны имэйл, апп, вэб сайтын үйл ажиллагааг хянах VPN-д холбогдсон байна.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\nАдмин нь таны имэйл,апп болон вэбсайт зэрэг сүлжээний үйл ажиллагааг хянадаг. \n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу. \n\nМөн та VPN-д холбогдсон бөгөөд ингэснээр өөрийн сүлжээний үйл ажиллагааг хянах боломжтой байна."</string>
<string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
- <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
- <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
+ <string name="monitoring_description_app" msgid="6259179342284742878">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой."</string>
+ <string name="monitoring_description_app_personal" msgid="484599052118316268">"Та <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой."</string>
<string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION">%1$s</xliff:g>-д холбогдсон байна."</string>
- <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
- <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вебсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
- <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вебсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
+ <string name="monitoring_description_app_work" msgid="1754325860918060897">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION">%2$s</xliff:g>-тэй холбогдсон бөгөөд таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
+ <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон бөгөөд таны имэйл, апп, вэбсайт зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой.\n\nМөн та <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон бөгөөд энэ нь таны сүлжээний хувийн үйл ажиллагааг хянаж чадна."</string>
+ <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Таны төхөөрөмжийг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг.\n\n Танай админ төхөөрөмж, төхөөрөмжийн байршилтай холбоотой өгөгдлийг холбох, тохиргоог өөрчлөх болон хяналт тавих боломжтой.\n\nТа <xliff:g id="APPLICATION">%2$s</xliff:g>-тай холбогдсон бөгөөд ингэснээр таны имэйл,апп, аюулгүй вэбсайт зэрэг сүлжээний үйл ажиллагаагаа хянах боломжтой.\n\n Дэлгэрэнгүй мэдээлэл авахыг хүсвэл админтайгаа холбогдоно уу."</string>
<string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Таныг гараар онгойлгох хүртэл төхөөрөмж түгжээтэй байх болно"</string>
<string name="hidden_notifications_title" msgid="7139628534207443290">"Мэдэгдлийг хурдан авах"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Түгжээг тайлахын өмнө үзнэ үү"</string>
@@ -438,18 +438,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Эх хувилбарыг сэргээхийн тулд дарна уу."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Та өөрийн ажлын профайлыг ашиглаж байна"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Дуудлага"</item>
- <item msgid="5997713001067658559">"Систем"</item>
- <item msgid="7858983209929864160">"Хонх дуугаргах"</item>
- <item msgid="1850038478268896762">"Медиа"</item>
- <item msgid="8265110906352372092">"Сэрүүлэг"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дууг нь нээхийн тулд товшино уу."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Чичиргээнд тохируулахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дууг нь хаахын тулд товшино уу. Хүртээмжийн үйлчилгээний дууг хаасан."</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index a21019a..ade3921 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"प्रवेशयोग्यता"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. सशब्द करण्यासाठी टॅप करा."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. कंपन सेट करण्यासाठी टॅप करा. प्रवेशयोग्यता सेवा नि:शब्द केल्या जाऊ शकतात."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index ce94295..ebe2cf8 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ialah dialog kelantangan"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Ketik untuk memulihkan yang asal."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Anda sedang menggunakan profil kerja"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Panggil"</item>
- <item msgid="5997713001067658559">"Sistem"</item>
- <item msgid="7858983209929864160">"Dering"</item>
- <item msgid="1850038478268896762">"Media"</item>
- <item msgid="8265110906352372092">"Penggera"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ketik untuk menyahredam."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Ketik untuk menetapkan pada getar. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketik untuk meredam. Perkhidmatan kebolehaksesan mungkin diredamkan."</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 8ab1de0..a1e6d37 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"အများသုံးစွဲနိုင်မှု"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s။ အသံပြန်ဖွင့်ရန် တို့ပါ။"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s။ တုန်ခါမှုကို သတ်မှတ်ရန် တို့ပါ။ အများသုံးစွဲနိုင်မှု ဝန်ဆောင်မှုများကို အသံပိတ်ထားနိုင်ပါသည်။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index c6312e1..4508276 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Tilgjengelighet"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trykk for å slå på lyden."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trykk for å angi vibrasjon. Lyden kan bli slått av for tilgjengelighetstjenestene."</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index f87223c..7afcac1 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"पहुँच"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। अनम्यूट गर्नका लागि ट्याप गर्नुहोस्।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। कम्पनमा सेट गर्नका लागि ट्याप गर्नुहोस्। पहुँच सम्बन्धी सेवाहरू म्यूट हुन सक्छन्।"</string>
diff --git a/packages/SystemUI/res/values-nl-land/strings.xml b/packages/SystemUI/res/values-nl-land/strings.xml
index d762d07..48624eb 100644
--- a/packages/SystemUI/res/values-nl-land/strings.xml
+++ b/packages/SystemUI/res/values-nl-land/strings.xml
@@ -19,5 +19,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="toast_rotation_locked" msgid="7609673011431556092">"Het scherm is nu vergrendeld in liggende (landschap) stand."</string>
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Het scherm is nu vergrendeld in liggende stand."</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 29f8875..a13030d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -274,8 +274,8 @@
<string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Scherm automatisch draaien"</string>
<string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Instellen op <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotatie vergrendeld"</string>
- <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Portret"</string>
- <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Landschap"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Staand"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Liggend"</string>
<string name="quick_settings_ime_label" msgid="7073463064369468429">"Invoermethode"</string>
<string name="quick_settings_location_label" msgid="5011327048748762257">"Locatie"</string>
<string name="quick_settings_location_off_label" msgid="7464544086507331459">"Locatie uit"</string>
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Toegankelijkheid"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tik om dempen op te heffen."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tik om in te stellen op trillen. Toegankelijkheidsservices kunnen zijn gedempt."</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index f25662b..6b5abe4 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੋਲਯੂਮ ਡਾਇਲੌਗ ਹੈ"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"ਅਸਲ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ਤੁਸੀਂ ਆਪਣੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਵਰਤ ਰਹੇ ਹੋ"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"ਕਾਲ ਕਰੋ"</item>
- <item msgid="5997713001067658559">"ਸਿਸਟਮ"</item>
- <item msgid="7858983209929864160">"ਰਿੰਗ ਕਰੋ"</item>
- <item msgid="1850038478268896762">"ਮੀਡੀਆ"</item>
- <item msgid="8265110906352372092">"ਅਲਾਰਮ"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"ਬਲੂਟੁੱਥ"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s। ਅਣਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s। ਥਰਥਰਾਹਟ ਸੈੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s। ਮਿਊਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ। ਪਹੁੰਚਯੋਗਤਾ ਸੇਵਾਵਾਂ ਮਿਊਟ ਹੋ ਸਕਦੀਆਂ ਹਨ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 78c6102..429fdfb 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -399,7 +399,7 @@
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
- <string name="clear_all_notifications_text" msgid="814192889771462828">"Usuń wszystkie"</string>
+ <string name="clear_all_notifications_text" msgid="814192889771462828">"Ukryj wszystkie"</string>
<string name="media_projection_action_text" msgid="8470872969457985954">"Rozpocznij teraz"</string>
<string name="empty_shade_text" msgid="708135716272867002">"Brak powiadomień"</string>
<string name="device_owned_footer" msgid="3802752663326030053">"Urządzenie może być monitorowane"</string>
@@ -455,6 +455,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Ułatwienia dostępu"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Kliknij, by wyłączyć wyciszenie."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Kliknij, by włączyć wibracje. Ułatwienia dostępu mogą być wyciszone."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 0dbdcb9..828d4d9 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Acessibilidade"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index d037cda..60a1cda 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Acessibilidade"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para reativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para ativar a vibração. Os serviços de acessibilidade podem ser silenciados."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0dbdcb9..828d4d9 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Acessibilidade"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Toque para ativar o som."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Toque para configurar para vibrar. É possível que os serviços de acessibilidade sejam silenciados."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e33ebb5..b418d4a 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -444,18 +444,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> afișează caseta de dialog pentru volum"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Atingeți pentru a restabili versiunea originală."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Acum folosiți profilul de serviciu"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Apel"</item>
- <item msgid="5997713001067658559">"Sistem"</item>
- <item msgid="7858983209929864160">"Sonerie"</item>
- <item msgid="1850038478268896762">"Conținut media"</item>
- <item msgid="8265110906352372092">"Alarmă"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Atingeți pentru a activa sunetul."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Atingeți pentru a seta vibrarea. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Atingeți pentru a dezactiva sunetul. Sunetul se poate dezactiva pentru serviciile de accesibilitate."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0fbb0bd..05f0d38 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -457,6 +457,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Специальные возможности"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Нажмите, чтобы включить звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Нажмите, чтобы включить вибрацию. Специальные возможности могут прекратить работу."</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index c4d2378..2db54d0 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -187,7 +187,7 @@
<string name="accessibility_desc_close" msgid="7479755364962766729">"වසන්න"</string>
<string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
<string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi අක්රියයි."</string>
- <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi සක්රියයි."</string>
+ <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi ක්රියාත්මකයි."</string>
<string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"ජංගම <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
<string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"බැටරිය <xliff:g id="STATE">%s</xliff:g>."</string>
<string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"අහස්යානා අකාරය අක්රියයි."</string>
@@ -203,15 +203,15 @@
<string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"බාධා නොකරන්න ක්රියාත්මක කරන ලදි"</string>
<string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"බ්ලූටූත්."</string>
<string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"බ්ලූටූත් අක්රියයි."</string>
- <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"බ්ලූටූත් සක්රියයි."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"බ්ලූටූත් ක්රියාත්මකයි."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"බ්ලූටූත් සම්බන්ධවෙමින්."</string>
<string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"බ්ලූටූත් සම්බන්ධිතයි."</string>
<string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"බ්ලූටූත් අක්රියයි."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"බ්ලූටූත් සක්රියයි."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"බ්ලූටූත් ක්රියාත්මක කෙරිණි."</string>
<string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"ස්ථානය වාර්තාකරණය අක්රියයි."</string>
- <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"ස්ථානය වාර්තාකරණය සක්රියයි."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"ස්ථානය වාර්තාකරණය ක්රියාත්මකයි."</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"ස්ථානය වාර්තාකරණය අක්රියයි."</string>
- <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"ස්ථානය වාර්තාකරණය සක්රියයි."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"ස්ථානය වාර්තාකරණය ක්රියාත්මක කෙරිණි."</string>
<string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"<xliff:g id="TIME">%s</xliff:g> සඳහා සීනුව සකස් කර ඇත."</string>
<string name="accessibility_quick_settings_close" msgid="3115847794692516306">"පැනලය වහන්න."</string>
<string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"වේලාව වැඩියෙන්."</string>
@@ -232,7 +232,7 @@
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"වැඩ ප්රකාරය ක්රියාත්මක කරන ලදී."</string>
<string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"දත්ත සුරැකුම ක්රියාවිරහිත කරන ලදී."</string>
<string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"දත්ත සුරැකුම ක්රියාත්මක කරන ලදී."</string>
- <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
+ <string name="accessibility_brightness" msgid="8003681285547803095">"සංදර්ශක දීප්තිය"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
@@ -263,7 +263,7 @@
<string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string>
<string name="quick_settings_dnd_label" msgid="8735855737575028208">"බාධා නොකරන්න"</string>
<string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ප්රමුඛතාව පමණයි"</string>
- <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ඇඟවීම් පමණි"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"එලාම පමණි"</string>
<string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"සම්පූර්ණ නිහඬතාව"</string>
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -356,7 +356,7 @@
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"සම්පූර්ණ නිහඬතාව. මෙය තිර කියවන්නන්ද නිහඬ කරනු ඇත."</string>
<string name="interruption_level_none" msgid="6000083681244492992">"සම්පූර්ණ නිහඬතාව"</string>
<string name="interruption_level_priority" msgid="6426766465363855505">"ප්රමුඛතාව පමණයි"</string>
- <string name="interruption_level_alarms" msgid="5226306993448328896">"ඇඟවීම් පමණි"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"එලාම පමණි"</string>
<string name="interruption_level_none_twoline" msgid="3957581548190765889">"සම්පූර්ණ\nනිහඬතාව"</string>
<string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්රමුඛතා\nපමණි"</string>
<string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
@@ -370,8 +370,8 @@
<string name="user_add_user" msgid="5110251524486079492">"පරිශීලකයෙක් එක් කරන්න"</string>
<string name="user_new_user_name" msgid="426540612051178753">"නව පරිශීලකයා"</string>
<string name="guest_nickname" msgid="8059989128963789678">"අමුත්තා"</string>
- <string name="guest_new_guest" msgid="600537543078847803">"ආගන්තුකයා එකතු කරන්න"</string>
- <string name="guest_exit_guest" msgid="7187359342030096885">"අමුත්තාන් ඉවත් කරන්න"</string>
+ <string name="guest_new_guest" msgid="600537543078847803">"අමුත්තා එක් කරන්න"</string>
+ <string name="guest_exit_guest" msgid="7187359342030096885">"අමුත්තා ඉවත් කරන්න"</string>
<string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"අමුත්තාන් ඉවත් කරන්නද?"</string>
<string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"ඉවත් කරන්න"</string>
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"මුල් තත්ත්වය නැවත ප්රතිසාධනය කිරීමට තට්ටු කරන්න."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"ඔබ ඔබේ කාර්යාල පැතිකඩ භාවිත කරමින් සිටී"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"ඇමතුම"</item>
- <item msgid="5997713001067658559">"පද්ධතිය"</item>
- <item msgid="7858983209929864160">"නාද කරන්න"</item>
- <item msgid="1850038478268896762">"මාධ්ය"</item>
- <item msgid="8265110906352372092">"එලාමය"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"බ්ලූටූත්"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. නිහඬ කිරීම ඉවත් කිරීමට තට්ටු කරන්න."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. කම්පනය කිරීමට තට්ටු කරන්න. ප්රවේශ්යතා සේවා නිහඬ කළ හැකිය."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. නිහඬ කිරීමට තට්ටු කරන්න. ප්රවේශ්යතා සේවා නිහඬ කළ හැකිය."</string>
@@ -602,7 +591,7 @@
<string name="preview" msgid="9077832302472282938">"පෙරදසුන"</string>
<string name="drag_to_add_tiles" msgid="7058945779098711293">"ටයිල් එක් කිරීමට අදින්න"</string>
<string name="drag_to_remove_tiles" msgid="3361212377437088062">"ඉවත් කිරීමට මෙතැනට අදින්න"</string>
- <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය කරන්න"</string>
+ <string name="qs_edit" msgid="2232596095725105230">"සංස්කරණය"</string>
<string name="tuner_time" msgid="6572217313285536011">"වේලාව"</string>
<string-array name="clock_options">
<item msgid="5965318737560463480">"පැය, මිනිත්තු, සහ තත්පර පෙන්වන්න"</item>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 23daf91..803be7f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -457,6 +457,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Dostupnosť"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Klepnutím zapnite zvuk."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Klepnutím aktivujte režim vibrovania. Služby dostupnosti je možné stlmiť."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 90985e7..0f03de9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -446,18 +446,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pogovorno okno glede prostornine"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Dotaknite se, če želite obnoviti prvotno stanje."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Uporabljate delovni profil"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Klic"</item>
- <item msgid="5997713001067658559">"Sistem"</item>
- <item msgid="7858983209929864160">"Zvonjenje"</item>
- <item msgid="1850038478268896762">"Predstavnost"</item>
- <item msgid="8265110906352372092">"Alarm"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dotaknite se, če želite vklopiti zvok."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dotaknite se, če želite nastaviti vibriranje. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dotaknite se, če želite izklopiti zvok. V storitvah za ljudi s posebnimi potrebami bo morda izklopljen zvok."</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 9616c07..c03c0fe 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> është dialogu i volumit"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Trokit për të restauruar origjinalin."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Po përdor profilin tënd të punës"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Telefono"</item>
- <item msgid="5997713001067658559">"Sistemi"</item>
- <item msgid="7858983209929864160">"Bjeri ziles"</item>
- <item msgid="1850038478268896762">"Media"</item>
- <item msgid="8265110906352372092">"Alarmi"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Trokit për të aktivizuar."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Trokit për ta caktuar te dridhja. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Trokit për të çaktivizuar. Shërbimet e qasshmërisë mund të çaktivizohen."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 667c65d..fd560de 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Приступачност"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Додирните да бисте укључили звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Додирните да бисте подесили на вибрацију. Звук услуга приступачности ће можда бити искључен."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0a95017..e0c8472 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Tillgänglighet"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Tryck här om du vill slå på ljudet."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tryck här om du vill sätta på vibrationen. Tillgänglighetstjänster kanske inaktiveras."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index afc5ee4..7c89410 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Zana za walio na matatizo ya kuona au kusikia"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Gonga ili urejeshe."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Gonga ili uweke mtetemo. Huenda ikakomesha huduma za zana za walio na matatizo ya kuona au kusikia."</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 99b8439..bd23b43 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"ஒலியளவு செய்தி: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"அசலை மீட்டமைக்க, தட்டவும்."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"பணி சுயவிவரத்தைப் பயன்படுத்துகிறீர்கள்"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"அழைப்பு"</item>
- <item msgid="5997713001067658559">"சாதனம்"</item>
- <item msgid="7858983209929864160">"ரிங்"</item>
- <item msgid="1850038478268896762">"மீடியா"</item>
- <item msgid="8265110906352372092">"அலாரம்"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"புளூடூத்"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. ஒலி இயக்க, தட்டவும்."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. அதிர்விற்கு அமைக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. ஒலியடக்க, தட்டவும். அணுகல்தன்மை சேவைகள் ஒலியடக்கப்படக்கூடும்."</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c1aeb09..6ae1e67 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"అసలు దాన్ని పునరుద్ధరించడానికి నొక్కండి."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"మీరు మీ కార్యాలయ ప్రొఫైల్ను ఉపయోగిస్తున్నారు"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"కాల్"</item>
- <item msgid="5997713001067658559">"సిస్టమ్"</item>
- <item msgid="7858983209929864160">"రింగ్"</item>
- <item msgid="1850038478268896762">"మీడియా"</item>
- <item msgid="8265110906352372092">"అలారం"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"బ్లూటూత్"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. అన్మ్యూట్ చేయడానికి నొక్కండి."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. వైబ్రేషన్కు సెట్ చేయడానికి నొక్కండి. ప్రాప్యత సేవలు మ్యూట్ చేయబడవచ్చు."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. మ్యూట్ చేయడానికి నొక్కండి. ప్రాప్యత సేవలు మ్యూట్ చేయబడవచ్చు."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0c461b4..7e2c00f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> เป็นช่องโต้ตอบระดับเสียง"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"แตะเพื่อคืนค่าเป็นค่าเดิม"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"คุณกำลังใช้โปรไฟล์งานของคุณ"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"โทร"</item>
- <item msgid="5997713001067658559">"ระบบ"</item>
- <item msgid="7858983209929864160">"ทำให้ส่งเสียง"</item>
- <item msgid="1850038478268896762">"สื่อ"</item>
- <item msgid="8265110906352372092">"การปลุก"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"บลูทูธ"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s แตะเพื่อเปิดเสียง"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s แตะเพื่อตั้งค่าให้สั่น อาจมีการปิดเสียงบริการการเข้าถึง"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s แตะเพื่อปิดเสียง อาจมีการปิดเสียงบริการการเข้าถึง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index caa9f97..e1e06df 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ang volume dialog"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"I-tap upang i-restore ang orihinal."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Ginagamit mo ang iyong profile sa trabaho"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Tawag"</item>
- <item msgid="5997713001067658559">"System"</item>
- <item msgid="7858983209929864160">"Ipa-ring"</item>
- <item msgid="1850038478268896762">"Media"</item>
- <item msgid="8265110906352372092">"Alarm"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. I-tap upang i-unmute."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. I-tap upang itakda na mag-vibrate. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. I-tap upang i-mute. Maaaring i-mute ang mga serbisyo sa Accessibility."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 030c97f..d416fdf 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Orijinali geri yüklemek için dokunun."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"İş profilinizi kullanıyorsunuz"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Çağrı"</item>
- <item msgid="5997713001067658559">"Sistem"</item>
- <item msgid="7858983209929864160">"Zili Çaldır"</item>
- <item msgid="1850038478268896762">"Medya"</item>
- <item msgid="8265110906352372092">"Alarm"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Sesi açmak için hafifçe dokunun."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Titreşime ayarlamak için hafifçe dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Sesi kapatmak için hafifçe dokunun. Erişilebilirlik hizmetlerinin sesi kapatılabilir."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index c086fff..5db6545 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -457,6 +457,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Спеціальні можливості"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Торкніться, щоб увімкнути звук."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Торкніться, щоб налаштувати вібросигнал. Спеціальні можливості може бути вимкнено."</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index ff46ad3..bc89301 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"اصل بحال کرنے کیلئے تھپتھپائیں۔"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"آپ اپنا دفتری پروفائل استعمال کر رہے ہیں۔"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"کال"</item>
- <item msgid="5997713001067658559">"سسٹم"</item>
- <item msgid="7858983209929864160">"رِنگ"</item>
- <item msgid="1850038478268896762">"میڈیا"</item>
- <item msgid="8265110906352372092">"الارم"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"بلوٹوتھ"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s۔ آواز چالو کرنے کیلئے تھپتھپائیں۔"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s۔ ارتعاش پر سیٹ کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s۔ خاموش کرنے کیلئے تھپتھپائیں۔ Accessibility سروسز شاید خاموش ہوں۔"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index f2d2661..a71b539 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -453,6 +453,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Maxsus imkoniyatlar"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Ovozini yoqish uchun ustiga bosing."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Tebranishni yoqish uchun ustiga bosing. Maxsus imkoniyatlar ishlamasligi mumkin."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 48b1e4f..d0d8216 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> là hộp thoại khối lượng"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"Nhấn để khôi phục ảnh chụp màn hình gốc."</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Bạn đang sử dụng hồ sơ công việc của mình"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"Gọi"</item>
- <item msgid="5997713001067658559">"Hệ thống"</item>
- <item msgid="7858983209929864160">"Chuông"</item>
- <item msgid="1850038478268896762">"Phương tiện"</item>
- <item msgid="8265110906352372092">"Báo thức"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"Bluetooth"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Nhấn để bật tiếng."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Nhấn để đặt chế độ rung. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Nhấn để tắt tiếng. Bạn có thể tắt tiếng dịch vụ trợ năng."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 94c3af1..7928bf9 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"点按即可恢复原始设置。"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您当前正在使用工作资料"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"通话"</item>
- <item msgid="5997713001067658559">"系统"</item>
- <item msgid="7858983209929864160">"铃声"</item>
- <item msgid="1850038478268896762">"媒体"</item>
- <item msgid="8265110906352372092">"闹钟"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"蓝牙"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。点按即可取消静音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。点按即可设为振动,但可能会同时将无障碍服务设为静音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。点按即可设为静音,但可能会同时将无障碍服务设为静音。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5785af9..b4ea6f8 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -442,18 +442,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"輕按即可復原。"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用工作設定檔"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"通話"</item>
- <item msgid="5997713001067658559">"系統"</item>
- <item msgid="7858983209929864160">"鈴聲"</item>
- <item msgid="1850038478268896762">"媒體"</item>
- <item msgid="8265110906352372092">"鬧鐘"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"藍牙"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕按即可取消靜音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕按即可設為震動。無障礙功能服務可能已經設為靜音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕按即可設為靜音。無障礙功能服務可能已經設為靜音。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6562b39..a6a87f6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -440,18 +440,7 @@
<string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
<string name="volumeui_notification_text" msgid="8819536904234337445">"輕觸即可恢復原始設定。"</string>
<string name="managed_profile_foreground_toast" msgid="5421487114739245972">"您正在使用 Work 設定檔"</string>
- <string-array name="volume_stream_titles">
- <item msgid="5841843895402729630">"通話"</item>
- <item msgid="5997713001067658559">"系統"</item>
- <item msgid="7858983209929864160">"鈴聲"</item>
- <item msgid="1850038478268896762">"媒體"</item>
- <item msgid="8265110906352372092">"鬧鐘"</item>
- <item msgid="5339394737636839168"></item>
- <item msgid="2951313578278086204">"藍牙"</item>
- <item msgid="2919807739709798970"></item>
- <item msgid="150349973435223405"></item>
- <item msgid="6761963760295549099"></item>
- </string-array>
+ <!-- no translation found for volume_stream_titles:10 (8119402510273906841) -->
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s。輕觸即可取消靜音。"</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s。輕觸即可設為震動,但系統可能會將無障礙服務一併設為靜音。"</string>
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s。輕觸即可設為靜音,但系統可能會將無障礙服務一併設為靜音。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e3c419b..324d306 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -451,6 +451,7 @@
<item msgid="2919807739709798970"></item>
<item msgid="150349973435223405"></item>
<item msgid="6761963760295549099"></item>
+ <item msgid="8119402510273906841">"Ukufinyeleleka"</item>
</string-array>
<string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Thepha ukuze ususe ukuthula."</string>
<string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Thepha ukuze usethe ukudlidliza. Amasevisi okufinyelela angathuliswa."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2f7174a..a6604cb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -81,8 +81,18 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height">148dp</dimen>
- <!-- Height of a the summary ("more card") notification on keyguard. -->
- <dimen name="notification_summary_height">44dp</dimen>
+ <!-- Height of a the shelf with the notification icons -->
+ <dimen name="notification_shelf_height">32dp</dimen>
+
+ <!-- the padding of the shelf icon container -->
+ <dimen name="shelf_icon_container_padding">13dp</dimen>
+
+ <!-- The padding of a notification icon on top to the start of the notification. Used for custom
+ views where the distance can't be measured -->
+ <dimen name="notification_icon_appear_padding">15dp</dimen>
+
+ <!-- The amount the content shifts upwards when transforming into the icon -->
+ <dimen name="notification_icon_transform_content_shift">32dp</dimen>
<!-- Minimum layouted height of a notification in the statusbar-->
<dimen name="min_notification_layout_height">48dp</dimen>
@@ -94,7 +104,7 @@
<dimen name="notification_gear_padding">20dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
- <dimen name="status_bar_icon_drawing_size">17dip</dimen>
+ <dimen name="status_bar_icon_drawing_size">17dp</dimen>
<!-- opacity at which Notification icons will be drawn in the status bar -->
<item type="dimen" name="status_bar_icon_drawing_alpha">90%</item>
@@ -102,6 +112,15 @@
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">0dp</dimen>
+ <!-- the padding on the start of the statusbar -->
+ <dimen name="status_bar_padding_start">6dp</dimen>
+
+ <!-- the radius of the overflow dot in the status bar -->
+ <dimen name="overflow_dot_radius">1dp</dimen>
+
+ <!-- the padding between dots in the icon overflow -->
+ <dimen name="overflow_icon_dot_padding">3dp</dimen>
+
<!-- The padding on the global screenshot background image -->
<dimen name="global_screenshot_bg_padding">20dp</dimen>
@@ -257,16 +276,10 @@
<!-- Default distance from each snap target that GlowPadView considers a "hit" -->
<dimen name="glowpadview_inner_radius">15dip</dimen>
- <!-- Space reserved for the cards behind the top card in the bottom stack -->
- <dimen name="bottom_stack_peek_amount">12dp</dimen>
-
<!-- bottom_stack_peek_amount + notification_min_height
+ notification_collapse_second_card_padding -->
<dimen name="min_stack_height">104dp</dimen>
- <!-- The height of the area before the bottom stack in which the notifications slow down -->
- <dimen name="bottom_stack_slow_down_length">12dp</dimen>
-
<!-- Z distance between notifications if they are in the stack -->
<dimen name="z_distance_between_notifications">0.5dp</dimen>
@@ -474,6 +487,9 @@
<!-- TrustDrawable: Thickness of the circle -->
<dimen name="trust_circle_thickness">2dp</dimen>
+ <!-- How much two taps can be apart to still be recognized as a double tap on the lockscreen -->
+ <dimen name="double_tap_slop">32dp</dimen>
+
<!-- Margin on the right side of the system icon group on Keyguard. -->
<fraction name="battery_button_height_fraction">10.5%</fraction>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 94d79f2..8c80c71 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -16,18 +16,21 @@
-->
<resources>
+ <item type="id" name="translation_x_animator_tag"/>
<item type="id" name="translation_y_animator_tag"/>
<item type="id" name="translation_z_animator_tag"/>
<item type="id" name="alpha_animator_tag"/>
<item type="id" name="top_inset_animator_tag"/>
<item type="id" name="height_animator_tag"/>
<item type="id" name="shadow_alpha_animator_tag"/>
+ <item type="id" name="translation_x_animator_end_value_tag"/>
<item type="id" name="translation_y_animator_end_value_tag"/>
<item type="id" name="translation_z_animator_end_value_tag"/>
<item type="id" name="alpha_animator_end_value_tag"/>
<item type="id" name="top_inset_animator_end_value_tag"/>
<item type="id" name="height_animator_end_value_tag"/>
<item type="id" name="shadow_alpha_animator_end_value_tag"/>
+ <item type="id" name="translation_x_animator_start_value_tag"/>
<item type="id" name="translation_y_animator_start_value_tag"/>
<item type="id" name="translation_z_animator_start_value_tag"/>
<item type="id" name="alpha_animator_start_value_tag"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 331d09e..bfc26e3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -840,6 +840,12 @@
<!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to unlock</string>
+ <!-- Text on keyguard screen indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
+ <string name="do_disclosure_generic">This device is managed</string>
+
+ <!-- Text on keyguard screen indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=40] -->
+ <string name="do_disclosure_with_name">This device is managed by <xliff:g id="organization_name" example="Foo, Inc.">%s</xliff:g></string>
+
<!-- Shows when people have clicked on the phone icon [CHAR LIMIT=60] -->
<string name="phone_hint">Swipe from icon for phone</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 21f68f5..e036128 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -26,6 +26,7 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -89,9 +90,10 @@
}
public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
- LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
- ViewGroup container) {
- return new KeyguardBouncer(context, callback, lockPatternUtils, windowManager, container);
+ LockPatternUtils lockPatternUtils,
+ ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry) {
+ return new KeyguardBouncer(context, callback, lockPatternUtils, container,
+ dismissCallbackRegistry);
}
public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 664e886..8fc555f 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -313,7 +313,11 @@
mDataCollector.onNotificationActive();
}
- public void onNotificationDoubleTap() {
+ public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+ if (FalsingLog.ENABLED) {
+ FalsingLog.i("onNotificationDoubleTap", "accepted=" + accepted
+ + " dx=" + dx + " dy=" + dy + " (px)");
+ }
mDataCollector.onNotificationDoubleTap();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
new file mode 100644
index 0000000..262d29d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
@@ -0,0 +1,47 @@
+/*
+ * 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.systemui.keyguard;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import java.util.ArrayList;
+
+/**
+ * Registry holding the current set of {@link IKeyguardDismissCallback}s.
+ */
+public class DismissCallbackRegistry {
+
+ private final ArrayList<DismissCallbackWrapper> mDismissCallbacks = new ArrayList<>();
+
+ public void addCallback(IKeyguardDismissCallback callback) {
+ mDismissCallbacks.add(new DismissCallbackWrapper(callback));
+ }
+
+ public void notifyDismissCancelled() {
+ for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+ mDismissCallbacks.get(i).notifyDismissCancelled();
+ }
+ mDismissCallbacks.clear();
+ }
+
+ public void notifyDismissSucceeded() {
+ for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
+ mDismissCallbacks.get(i).notifyDismissSucceeded();
+ }
+ mDismissCallbacks.clear();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
new file mode 100644
index 0000000..8a91144
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackWrapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.systemui.keyguard;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+/**
+ * A light wrapper around {@link IKeyguardDismissCallback} handling {@link RemoteException}s.
+ */
+public class DismissCallbackWrapper {
+
+ private static final String TAG = "DismissCallbackWrapper";
+
+ private IKeyguardDismissCallback mCallback;
+
+ public DismissCallbackWrapper(IKeyguardDismissCallback callback) {
+ mCallback = callback;
+ }
+
+ public void notifyDismissError() {
+ try {
+ mCallback.onDismissError();
+ } catch (RemoteException e) {
+ Log.i(TAG, "Failed to call callback", e);
+ }
+ }
+
+ public void notifyDismissCancelled() {
+ try {
+ mCallback.onDismissCancelled();
+ } catch (RemoteException e) {
+ Log.i(TAG, "Failed to call callback", e);
+ }
+ }
+
+ public void notifyDismissSucceeded() {
+ try {
+ mCallback.onDismissSucceeded();
+ } catch (RemoteException e) {
+ Log.i(TAG, "Failed to call callback", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index fe9f55f..3532f41 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -26,6 +26,7 @@
import android.os.Trace;
import android.util.Log;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
@@ -89,9 +90,9 @@
}
@Override // Binder interface
- public void dismiss(boolean allowWhileOccluded) {
+ public void dismiss(IKeyguardDismissCallback callback) {
checkPermission();
- mKeyguardViewMediator.dismiss(allowWhileOccluded);
+ mKeyguardViewMediator.dismiss(callback);
}
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 34dc63f..07e1193 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,12 +20,12 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
-import android.app.SearchManager;
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
@@ -48,20 +48,20 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
-import android.view.IWindowManager;
import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicy;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
@@ -252,6 +252,7 @@
* var being non-null as an indicator that there is an in progress request.
*/
private IKeyguardExitCallback mExitSecureCallback;
+ private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
// the properties of the keyguard
@@ -326,6 +327,7 @@
private boolean mWakeAndUnlocking;
private IKeyguardDrawnCallback mDrawnCallback;
+ private boolean mLockWhenSimRemoved;
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -347,7 +349,7 @@
UserInfo info = UserManager.get(mContext).getUserInfo(userId);
if (info != null && (info.isGuest() || info.isDemo())) {
// If we just switched to a guest, try to dismiss keyguard.
- dismiss(false /* allowWhileOccluded */);
+ dismiss(null /* callback */);
}
}
}
@@ -416,7 +418,7 @@
case ABSENT:
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
- synchronized (this) {
+ synchronized (KeyguardViewMediator.this) {
if (shouldWaitForProvisioning()) {
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
@@ -427,11 +429,12 @@
resetStateLocked();
}
}
+ onSimNotReadyLocked();
}
break;
case PIN_REQUIRED:
case PUK_REQUIRED:
- synchronized (this) {
+ synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG,
"INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
@@ -443,7 +446,7 @@
}
break;
case PERM_DISABLED:
- synchronized (this) {
+ synchronized (KeyguardViewMediator.this) {
if (!mShowing) {
if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
+ "keygaurd isn't showing.");
@@ -453,21 +456,40 @@
+ "show permanently disabled message in lockscreen.");
resetStateLocked();
}
+ onSimNotReadyLocked();
}
break;
case READY:
- synchronized (this) {
+ synchronized (KeyguardViewMediator.this) {
if (mShowing) {
resetStateLocked();
}
+ mLockWhenSimRemoved = true;
}
break;
default:
- if (DEBUG_SIM_STATES) Log.v(TAG, "Ignoring state: " + simState);
+ if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
+ synchronized (KeyguardViewMediator.this) {
+ onSimNotReadyLocked();
+ }
break;
}
}
+ private void onSimNotReadyLocked() {
+ if (isSecure() && mLockWhenSimRemoved) {
+ mLockWhenSimRemoved = false;
+ MetricsLogger.action(mContext,
+ MetricsProto.MetricsEvent.ACTION_LOCK_BECAUSE_SIM_REMOVED, mShowing);
+ if (!mShowing) {
+ if (DEBUG_SIM_STATES) Log.d(TAG, "SIM removed, showing keyguard");
+ doKeyguardLocked(null);
+ } else {
+ resetStateLocked();
+ }
+ }
+ }
+
@Override
public void onFingerprintAuthFailed() {
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
@@ -515,7 +537,7 @@
return;
}
- tryKeyguardDone(true);
+ tryKeyguardDone();
if (strongAuth) {
mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
}
@@ -565,10 +587,7 @@
Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#readyForKeyguardDone");
if (mKeyguardDonePending) {
mKeyguardDonePending = false;
-
- // Somebody has called keyguardDonePending before, which means that we are
- // authenticated
- tryKeyguardDone(true);
+ tryKeyguardDone();
}
Trace.endSection();
}
@@ -600,7 +619,7 @@
if (any && !strongAuthTracker.hasUserAuthenticatedSinceBoot()) {
return KeyguardSecurityView.PROMPT_REASON_RESTART;
- } else if (fingerprint && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
+ } else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_TIMEOUT) != 0) {
return KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
} else if (any && (strongAuth & STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW) != 0) {
return KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
@@ -1252,16 +1271,21 @@
/**
* Dismiss the keyguard through the security layers.
- * @param allowWhileOccluded if true, dismiss the keyguard even if it's currently occluded.
+ * @param callback Callback to be informed about the result
*/
- public void handleDismiss(boolean allowWhileOccluded) {
- if (mShowing && (allowWhileOccluded || !mOccluded)) {
+ private void handleDismiss(IKeyguardDismissCallback callback) {
+ if (mShowing) {
+ if (callback != null) {
+ mDismissCallbackRegistry.addCallback(callback);
+ }
mStatusBarKeyguardViewManager.dismissAndCollapse();
+ } else if (callback != null) {
+ new DismissCallbackWrapper(callback).notifyDismissError();
}
}
- public void dismiss(boolean allowWhileOccluded) {
- mHandler.obtainMessage(DISMISS, allowWhileOccluded ? 1 : 0, 0).sendToTarget();
+ public void dismiss(IKeyguardDismissCallback callback) {
+ mHandler.obtainMessage(DISMISS, callback).sendToTarget();
}
/**
@@ -1394,12 +1418,12 @@
}
};
- public void keyguardDone(boolean authenticated) {
+ public void keyguardDone() {
Trace.beginSection("KeyguardViewMediator#keyguardDone");
- if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated +")");
+ if (DEBUG) Log.d(TAG, "keyguardDone()");
userActivity();
EventLog.writeEvent(70000, 2);
- Message msg = mHandler.obtainMessage(KEYGUARD_DONE, authenticated ? 1 : 0);
+ Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
mHandler.sendMessage(msg);
Trace.endSection();
}
@@ -1455,7 +1479,7 @@
break;
case KEYGUARD_DONE:
Trace.beginSection("KeyguardViewMediator#handleMessage KEYGUARD_DONE");
- handleKeyguardDone(msg.arg1 != 0);
+ handleKeyguardDone();
Trace.endSection();
break;
case KEYGUARD_DONE_DRAWING:
@@ -1474,7 +1498,7 @@
}
break;
case DISMISS:
- handleDismiss(msg.arg1 == 1 ? true : false /* allowWhileOccluded */);
+ handleDismiss((IKeyguardDismissCallback) msg.obj);
break;
case START_KEYGUARD_EXIT_ANIM:
Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
@@ -1492,9 +1516,9 @@
}
};
- private void tryKeyguardDone(boolean authenticated) {
+ private void tryKeyguardDone() {
if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
- handleKeyguardDone(authenticated);
+ handleKeyguardDone();
} else if (!mHideAnimationRun) {
mHideAnimationRun = true;
mHideAnimationRunning = true;
@@ -1506,7 +1530,7 @@
* @see #keyguardDone
* @see #KEYGUARD_DONE
*/
- private void handleKeyguardDone(boolean authenticated) {
+ private void handleKeyguardDone() {
Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
if (mLockPatternUtils.isSecure(currentUser)) {
@@ -1517,9 +1541,7 @@
resetKeyguardDonePendingLocked();
}
- if (authenticated) {
- mUpdateMonitor.clearFailedUnlockAttempts();
- }
+ mUpdateMonitor.clearFailedUnlockAttempts();
mUpdateMonitor.clearFingerprintRecognized();
if (mGoingToSleep) {
@@ -1528,22 +1550,21 @@
}
if (mExitSecureCallback != null) {
try {
- mExitSecureCallback.onKeyguardExitResult(authenticated);
+ mExitSecureCallback.onKeyguardExitResult(true /* authenciated */);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to call onKeyguardExitResult(" + authenticated + ")", e);
+ Slog.w(TAG, "Failed to call onKeyguardExitResult()", e);
}
mExitSecureCallback = null;
- if (authenticated) {
- // after succesfully exiting securely, no need to reshow
- // the keyguard when they've released the lock
- mExternallyEnabled = true;
- mNeedToReshowWhenReenabled = false;
- updateInputRestricted();
- }
+ // after succesfully exiting securely, no need to reshow
+ // the keyguard when they've released the lock
+ mExternallyEnabled = true;
+ mNeedToReshowWhenReenabled = false;
+ updateInputRestricted();
}
+ mDismissCallbackRegistry.notifyDismissSucceeded();
handleHide();
Trace.endSection();
}
@@ -1690,7 +1711,7 @@
private final Runnable mHideAnimationFinishedRunnable = () -> {
mHideAnimationRunning = false;
- tryKeyguardDone(true);
+ tryKeyguardDone();
};
/**
@@ -1912,7 +1933,7 @@
public void onWakeAndUnlocking() {
Trace.beginSection("KeyguardViewMediator#onWakeAndUnlocking");
mWakeAndUnlocking = true;
- keyguardDone(true /* authenticated */);
+ keyguardDone();
Trace.endSection();
}
@@ -1921,7 +1942,8 @@
ScrimController scrimController,
FingerprintUnlockController fingerprintUnlockController) {
mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
- statusBarWindowManager, scrimController, fingerprintUnlockController);
+ statusBarWindowManager, scrimController, fingerprintUnlockController,
+ mDismissCallbackRegistry);
return mStatusBarKeyguardViewManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index d789477..0eef864 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -323,7 +323,8 @@
// Create the intent to show the screenshot in gallery
Intent launchIntent = new Intent(Intent.ACTION_VIEW);
launchIntent.setDataAndType(mParams.imageUri, "image/png");
- launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ launchIntent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
final long now = System.currentTimeMillis();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index bc46548..d46d267 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -41,7 +41,7 @@
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
- * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
+ * Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf}
* to implement dimming/activating on Keyguard for the double-tap gesture
*/
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
@@ -86,6 +86,12 @@
*/
private static final float DARK_EXIT_SCALE_START = 0.93f;
+ /**
+ * A sentinel value when no color should be used. Can be used with {@link #setTintColor(int)}
+ * or {@link #setOverrideTintColor(int, float)}.
+ */
+ protected static final int NO_COLOR = 0;
+
private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
= new PathInterpolator(0.6f, 0, 0.5f, 1);
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
@@ -110,6 +116,10 @@
private float mDownY;
private final float mTouchSlop;
+ private float mActivationX;
+ private float mActivationY;
+ private final float mDoubleTapSlop;
+
private OnActivatedListener mOnActivatedListener;
private final Interpolator mSlowOutFastInInterpolator;
@@ -167,10 +177,13 @@
private int mCurrentBackgroundTint;
private int mTargetTint;
private int mStartTint;
+ private int mOverrideTint;
+ private float mOverrideAmount;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ mDoubleTapSlop = context.getResources().getDimension(R.dimen.double_tap_slop);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
setClipChildren(false);
@@ -232,7 +245,6 @@
boolean wasActivated = mActivated;
result = handleTouchEventDimmed(event);
if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
- mFalsingManager.onNotificationDoubleTap();
removeCallbacks(mTapTimeoutRunnable);
}
} else {
@@ -283,9 +295,21 @@
if (!mActivated) {
makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
+ mActivationX = event.getX();
+ mActivationY = event.getY();
} else {
- if (!performClick()) {
- return false;
+ boolean withinDoubleTapSlop = isWithinDoubleTapSlop(event);
+ mFalsingManager.onNotificationDoubleTap(
+ withinDoubleTapSlop,
+ event.getX() - mActivationX,
+ event.getY() - mActivationY);
+ if (withinDoubleTapSlop) {
+ if (!performClick()) {
+ return false;
+ }
+ } else {
+ makeInactive(true /* animate */);
+ mTrackTouch = false;
}
}
} else {
@@ -393,6 +417,16 @@
&& Math.abs(event.getY() - mDownY) < mTouchSlop;
}
+ private boolean isWithinDoubleTapSlop(MotionEvent event) {
+ if (!mActivated) {
+ // If we're not activated there's no double tap slop to satisfy.
+ return true;
+ }
+
+ return Math.abs(event.getX() - mActivationX) < mDoubleTapSlop
+ && Math.abs(event.getY() - mActivationY) < mDoubleTapSlop;
+ }
+
public void setDimmed(boolean dimmed, boolean fade) {
if (mDimmed != dimmed) {
mDimmed = dimmed;
@@ -448,9 +482,20 @@
if (below != mIsBelowSpeedBump) {
mIsBelowSpeedBump = below;
updateBackgroundTint();
+ onBelowSpeedBumpChanged();
}
}
+ protected void onBelowSpeedBumpChanged() {
+ }
+
+ /**
+ * @return whether we are below the speed bump
+ */
+ public boolean isBelowSpeedBump() {
+ return mIsBelowSpeedBump;
+ }
+
/**
* Sets the tint color of the background
*/
@@ -466,6 +511,23 @@
updateBackgroundTint(animated);
}
+ /**
+ * Set an override tint color that is used for the background.
+ *
+ * @param color the color that should be used to tint the background.
+ * This can be {@link #NO_COLOR} if the tint should be normally computed.
+ * @param overrideAmount a value from 0 to 1 how much the override tint should be used. The
+ * background color will then be the interpolation between this and the
+ * regular background color, where 1 means the overrideTintColor is fully
+ * used and the background color not at all.
+ */
+ public void setOverrideTintColor(int color, float overrideAmount) {
+ mOverrideTint = color;
+ mOverrideAmount = overrideAmount;
+ int newColor = calculateBgColor();
+ setBackgroundTintColor(newColor);
+ }
+
protected void updateBackgroundTint() {
updateBackgroundTint(false /* animated */);
}
@@ -673,6 +735,13 @@
}
@Override
+ public void setClipBottomAmount(int clipBottomAmount) {
+ super.setClipBottomAmount(clipBottomAmount);
+ mBackgroundNormal.setClipBottomAmount(clipBottomAmount);
+ mBackgroundDimmed.setClipBottomAmount(clipBottomAmount);
+ }
+
+ @Override
public void performRemoveAnimation(long duration, float translationDirection,
Runnable onFinishedRunnable) {
enableAppearDrawing(true);
@@ -841,11 +910,20 @@
protected abstract View getContentView();
public int calculateBgColor() {
- return calculateBgColor(true /* withTint */);
+ return calculateBgColor(true /* withTint */, true /* withOverRide */);
}
- private int calculateBgColor(boolean withTint) {
- if (withTint && mBgTint != 0) {
+ /**
+ * @param withTint should a possible tint be factored in?
+ * @param withOverRide should the value be interpolated with {@link #mOverrideTint}
+ * @return the calculated background color
+ */
+ private int calculateBgColor(boolean withTint, boolean withOverRide) {
+ if (withOverRide && mOverrideTint != NO_COLOR) {
+ int defaultTint = calculateBgColor(withTint, false);
+ return NotificationUtils.interpolateColors(defaultTint, mOverrideTint, mOverrideAmount);
+ }
+ if (withTint && mBgTint != NO_COLOR) {
return mBgTint;
} else if (mShowingLegacyBackground) {
return mLegacyColor;
@@ -936,7 +1014,7 @@
}
public int getBackgroundColorWithoutTint() {
- return calculateBgColor(false /* withTint */);
+ return calculateBgColor(false /* withTint */, false /* withOverride */);
}
public interface OnActivatedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 20193f7..414ebec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -42,7 +42,6 @@
import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -258,7 +257,7 @@
protected boolean mShowLockscreenNotifications;
protected boolean mAllowLockscreenRemoteInput;
- protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
+ protected NotificationShelf mNotificationShelf;
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
@@ -1025,9 +1024,7 @@
}
}
- if (entry.icon != null) {
- entry.icon.setTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
- }
+ entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
}
public boolean isMediaNotification(NotificationData.Entry entry) {
@@ -1076,8 +1073,8 @@
int appUid = -1;
try {
final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
if (info != null) {
appname = String.valueOf(pmUser.getApplicationLabel(info));
pkgicon = pmUser.getApplicationIcon(info);
@@ -1646,8 +1643,8 @@
String appname = pkg;
try {
final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
if (info != null) {
appname = String.valueOf(pmUser.getApplicationLabel(info));
}
@@ -2160,13 +2157,14 @@
if (DEBUG) {
Log.d(TAG, "createNotificationViews(notification=" + sbn);
}
- final StatusBarIconView iconView = createIcon(sbn);
- if (iconView == null) {
- return null;
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ try {
+ entry.createIcons(mContext, sbn);
+ } catch (NotificationData.IconException exception) {
+ handleNotificationError(sbn, exception.getMessage());
}
// Construct the expanded view.
- NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
if (!inflateViews(entry, mStackScroller)) {
handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
return null;
@@ -2174,33 +2172,6 @@
return entry;
}
- public StatusBarIconView createIcon(StatusBarNotification sbn) {
- // Construct the icon.
- Notification n = sbn.getNotification();
- final StatusBarIconView iconView = new StatusBarIconView(mContext,
- sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
- iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-
- final Icon smallIcon = n.getSmallIcon();
- if (smallIcon == null) {
- handleNotificationError(sbn,
- "No small icon in notification from " + sbn.getPackageName());
- return null;
- }
- final StatusBarIcon ic = new StatusBarIcon(
- sbn.getUser(),
- sbn.getPackageName(),
- smallIcon,
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(mContext, n));
- if (!iconView.set(ic)) {
- handleNotificationError(sbn, "Couldn't create icon: " + ic);
- return null;
- }
- return iconView;
- }
-
protected void addNotificationViews(Entry entry, RankingMap ranking) {
if (entry == null) {
return;
@@ -2220,17 +2191,16 @@
* Updates expanded, dimmed and locked states of notification rows.
*/
protected void updateRowStates() {
- mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
-
ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
final int N = activeNotifications.size();
int visibleNotifications = 0;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
- int maxNotifications = 0;
+ int maxNotifications = -1;
if (onKeyguard) {
maxNotifications = getMaxKeyguardNotifications(true /* recompute */);
}
+ mStackScroller.setMaxDisplayedNotifications(maxNotifications);
for (int i = 0; i < N; i++) {
NotificationData.Entry entry = activeNotifications.get(i);
boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
@@ -2249,12 +2219,8 @@
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
if (suppressedSummary
|| (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
- || (onKeyguard && !childWithVisibleSummary
- && (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
+ || (onKeyguard && !showOnKeyguard)) {
entry.row.setVisibility(View.GONE);
- if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
- mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
- }
} else {
boolean wasGone = entry.row.getVisibility() == View.GONE;
entry.row.setVisibility(View.VISIBLE);
@@ -2269,13 +2235,9 @@
}
}
- mStackScroller.updateOverflowContainerVisibility(onKeyguard
- && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0);
-
mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
- mStackScroller.changeViewPosition(mKeyguardIconOverflowContainer,
- mStackScroller.getChildCount() - 3);
+ mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
}
public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -2367,48 +2329,28 @@
mGroupManager.onEntryUpdated(entry, oldNotification);
boolean updateSuccessful = false;
- if (applyInPlace) {
- if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
- try {
- if (entry.icon != null) {
- // Update the icon
- final StatusBarIcon ic = new StatusBarIcon(
- notification.getUser(),
- notification.getPackageName(),
- n.getSmallIcon(),
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(mContext, n));
- entry.icon.setNotification(n);
- if (!entry.icon.set(ic)) {
- handleNotificationError(notification, "Couldn't update icon: " + ic);
- return;
- }
+ try {
+ if (applyInPlace) {
+ if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
+ try {
+ entry.updateIcons(mContext, n);
+ updateNotificationViews(entry, notification);
+ updateSuccessful = true;
+ } catch (RuntimeException e) {
+ // It failed to apply cleanly.
+ Log.w(TAG, "Couldn't reapply views for package " +
+ notification.getPackageName(), e);
}
- updateNotificationViews(entry, notification);
- updateSuccessful = true;
}
- catch (RuntimeException e) {
- // It failed to apply cleanly.
- Log.w(TAG, "Couldn't reapply views for package " +
- notification.getPackageName(), e);
+ if (!updateSuccessful) {
+ entry.updateIcons(mContext, n);
+ if (!inflateViews(entry, mStackScroller)) {
+ handleNotificationError(notification, "Couldn't update remote views for: "
+ + notification);
+ }
}
- }
- if (!updateSuccessful) {
- if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
- final StatusBarIcon ic = new StatusBarIcon(
- notification.getUser(),
- notification.getPackageName(),
- n.getSmallIcon(),
- n.iconLevel,
- n.number,
- StatusBarIconView.contentDescForNotification(mContext, n));
- entry.icon.setNotification(n);
- entry.icon.set(ic);
- if (!inflateViews(entry, mStackScroller)) {
- handleNotificationError(notification, "Couldn't update remote views for: "
- + notification);
- }
+ } catch (NotificationData.IconException e) {
+ handleNotificationError(notification, e.getMessage());
}
updateHeadsUp(key, entry, shouldPeek, alertAgain);
updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index 1d7bede..5436664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -22,12 +22,17 @@
import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
public class DismissView extends StackScrollerDecorView {
+ private final int mClearAllTopPadding;
private DismissViewButton mDismissButton;
public DismissView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mClearAllTopPadding = context.getResources().getDimensionPixelSize(
+ R.dimen.clear_all_padding_top);
}
@Override
@@ -63,4 +68,21 @@
public boolean isButtonVisible() {
return mDismissButton.getAlpha() != 0.0f;
}
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new DismissViewState();
+ }
+
+ public class DismissViewState extends ExpandableViewState {
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof DismissView) {
+ DismissView dismissView = (DismissView) view;
+ boolean visible = this.clipTopAmount < mClearAllTopPadding;
+ dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 5db0699..19b32af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -23,6 +23,8 @@
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
public class EmptyShadeView extends StackScrollerDecorView {
@@ -40,4 +42,22 @@
protected View findContentView() {
return findViewById(R.id.no_notifications);
}
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new EmptyShadeViewState();
+ }
+
+ public static class EmptyShadeViewState extends ExpandableViewState {
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof EmptyShadeView) {
+ EmptyShadeView emptyShadeView = (EmptyShadeView) view;
+ boolean visible = this.clipTopAmount <= 0;
+ emptyShadeView.performVisibilityAnimation(
+ visible && !emptyShadeView.willBeGone());
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5173176..661cc3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -36,6 +36,7 @@
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -45,16 +46,18 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.NotificationColorUtil;
+import com.android.internal.widget.CachingIconView;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.stack.StackScrollState;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.statusbar.stack.StackViewState;
import java.util.ArrayList;
import java.util.List;
@@ -63,6 +66,8 @@
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
+ private int mIconTransformContentShift;
+ private int mIconTransformContentShiftNoIcon;
private int mNotificationMinHeightLegacy;
private int mMaxHeadsUpHeightLegacy;
private int mMaxHeadsUpHeight;
@@ -188,6 +193,10 @@
private View mChildAfterViewWhenDismissed;
private View mGroupParentWhenDismissed;
private boolean mRefocusOnDismiss;
+ private float mIconTransformationAmount;
+ private boolean mIconsVisible = true;
+ private boolean mAboveShelf;
+ private boolean mIsLastChild;
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
@@ -293,6 +302,7 @@
// The public layouts expand button is always visible
mPublicLayout.updateExpandButtons(true);
updateLimits();
+ updateIconVisibilities();
}
private void updateLimits() {
@@ -318,6 +328,10 @@
return mStatusBarNotification;
}
+ public NotificationData.Entry getEntry() {
+ return mEntry;
+ }
+
public boolean isHeadsUp() {
return mIsHeadsUp;
}
@@ -333,6 +347,9 @@
if (intrinsicBefore != getIntrinsicHeight()) {
notifyHeightChanged(false /* needsAnimation */);
}
+ if (isHeadsUp) {
+ setAboveShelf(true);
+ }
}
public void setGroupManager(NotificationGroupManager groupManager) {
@@ -400,6 +417,7 @@
if (mNotificationParent != null) {
mNotificationParent.updateBackgroundForGroupState();
}
+ updateIconVisibilities();
}
@Override
@@ -459,7 +477,7 @@
public void getChildrenStates(StackScrollState resultState) {
if (mIsSummaryWithChildren) {
- StackViewState parentState = resultState.getViewStateForView(this);
+ ExpandableViewState parentState = resultState.getViewStateForView(this);
mChildrenContainer.getState(resultState, parentState);
}
}
@@ -476,11 +494,9 @@
}
}
- public void startChildAnimation(StackScrollState finalState,
- StackStateAnimator stateAnimator, long delay, long duration) {
+ public void startChildAnimation(StackScrollState finalState, AnimationProperties properties) {
if (mIsSummaryWithChildren) {
- mChildrenContainer.startAnimationToState(finalState, stateAnimator, delay,
- duration);
+ mChildrenContainer.startAnimationToState(finalState, properties);
}
}
@@ -522,12 +538,17 @@
return mIsPinned;
}
+ @Override
+ public int getPinnedHeadsUpHeight() {
+ return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
+ }
+
/**
* @param atLeastMinHeight should the value returned be at least the minimum height.
* Used to avoid cyclic calls
* @return the height of the heads up notification when pinned
*/
- public int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
+ private int getPinnedHeadsUpHeight(boolean atLeastMinHeight) {
if (mIsSummaryWithChildren) {
return mChildrenContainer.getIntrinsicHeight();
}
@@ -764,9 +785,17 @@
return mChildrenContainer;
}
- public void setHeadsupDisappearRunning(boolean running) {
- mHeadsupDisappearRunning = running;
- mPrivateLayout.setHeadsupDisappearRunning(running);
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ mHeadsupDisappearRunning = headsUpAnimatingAway;
+ mPrivateLayout.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+ }
+
+ /**
+ * @return if the view was just heads upped and is now animating away. During such a time the
+ * layout needs to be kept consistent
+ */
+ public boolean isHeadsUpAnimatingAway() {
+ return mHeadsupDisappearRunning;
}
public View getChildAfterViewWhenDismissed() {
@@ -785,6 +814,105 @@
mVetoButton.setOnClickListener(listener);
}
+ public View getNotificationIcon() {
+ NotificationHeaderView notificationHeader = getNotificationHeader();
+ if (notificationHeader != null) {
+ return notificationHeader.getIcon();
+ }
+ return null;
+ }
+
+ /**
+ * @return whether the notification is currently showing a view with an icon.
+ */
+ public boolean isShowingIcon() {
+ if (mIsSummaryWithChildren) {
+ return true;
+ }
+ NotificationContentView showingLayout = getShowingLayout();
+ NotificationHeaderView notificationHeader = showingLayout.getVisibleNotificationHeader();
+ return notificationHeader != null;
+ }
+
+ /**
+ * Set how much this notification is transformed into an icon.
+ *
+ * @param iconTransformationAmount A value from 0 to 1 indicating how much we are transformed
+ * to an icon
+ * @param isLastChild is this the last child in the list. If true, then the transformation is
+ * different since it's content fades out.
+ */
+ public void setIconTransformationAmount(float iconTransformationAmount, boolean isLastChild) {
+ boolean changeTransformation = isLastChild != mIsLastChild;
+ changeTransformation |= mIconTransformationAmount != iconTransformationAmount;
+ mIsLastChild = isLastChild;
+ mIconTransformationAmount = iconTransformationAmount;
+ if (changeTransformation) {
+ updateContentTransformation();
+ boolean iconsVisible = mIconTransformationAmount == 0.0f;
+ if (iconsVisible != mIconsVisible) {
+ mIconsVisible = iconsVisible;
+ updateIconVisibilities();
+ }
+ }
+ }
+
+ @Override
+ protected void onBelowSpeedBumpChanged() {
+ updateIconVisibilities();
+ }
+
+ private void updateContentTransformation() {
+ float contentAlpha;
+ float translationY = - mIconTransformationAmount * mIconTransformContentShift;
+ if (mIsLastChild) {
+ contentAlpha = 1.0f - mIconTransformationAmount;
+ contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
+ contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
+ translationY *= 0.4f;
+ } else {
+ contentAlpha = 1.0f;
+ }
+ mPublicLayout.setAlpha(contentAlpha);
+ mPrivateLayout.setAlpha(contentAlpha);
+ mPublicLayout.setTranslationY(translationY);
+ mPrivateLayout.setTranslationY(translationY);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setAlpha(contentAlpha);
+ mChildrenContainer.setTranslationY(translationY);
+ // TODO: handle children fade out better
+ }
+ }
+
+ private void updateIconVisibilities() {
+ boolean visible = isChildInGroup() || isBelowSpeedBump() || mIconsVisible;
+ mPublicLayout.setIconsVisible(visible);
+ mPrivateLayout.setIconsVisible(visible);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setIconsVisible(visible);
+ }
+ }
+
+ /**
+ * Get the relative top padding of a view relative to this view. This recursively walks up the
+ * hierarchy and does the corresponding measuring.
+ *
+ * @param view the view to the the padding for. The requested view has to be a child of this
+ * notification.
+ * @return the toppadding
+ */
+ public int getRelativeTopPadding(View view) {
+ int topPadding = 0;
+ while (view.getParent() instanceof ViewGroup) {
+ topPadding += view.getTop();
+ view = (View) view.getParent();
+ if (view instanceof ExpandableNotificationRow) {
+ return topPadding;
+ }
+ }
+ return topPadding;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -804,6 +932,8 @@
mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
mIncreasedPaddingBetweenElements = getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
+ mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
+ R.dimen.notification_icon_transform_content_shift);
}
/**
@@ -1276,6 +1406,21 @@
if (mSettingsIconRow != null) {
mSettingsIconRow.updateVerticalLocation();
}
+ updateContentShiftHeight();
+ }
+
+ /**
+ * Updates the content shift height such that the header is completely hidden when coming from
+ * the top.
+ */
+ private void updateContentShiftHeight() {
+ NotificationHeaderView notificationHeader = getNotificationHeader();
+ if (notificationHeader != null) {
+ CachingIconView icon = notificationHeader.getIcon();
+ mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
+ } else {
+ mIconTransformContentShift = mIconTransformContentShiftNoIcon;
+ }
}
private void updateMaxHeights() {
@@ -1532,6 +1677,19 @@
}
}
+ @Override
+ public void setClipBottomAmount(int clipBottomAmount) {
+ super.setClipBottomAmount(clipBottomAmount);
+ mPrivateLayout.setClipBottomAmount(clipBottomAmount);
+ mPublicLayout.setClipBottomAmount(clipBottomAmount);
+ if (mGuts != null) {
+ mGuts.setClipBottomAmount(clipBottomAmount);
+ }
+ if (mChildrenContainer != null) {
+ mChildrenContainer.setClipBottomAmount(clipBottomAmount);
+ }
+ }
+
public boolean isMaxExpandHeightInitialized() {
return mMaxExpandHeight != 0;
}
@@ -1679,4 +1837,54 @@
public interface OnExpandClickListener {
void onExpandClicked(NotificationData.Entry clickedEntry, boolean nowExpanded);
}
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new NotificationViewState(stackScrollState);
+ }
+
+ @Override
+ public boolean isAboveShelf() {
+ return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
+ }
+
+ public void setAboveShelf(boolean aboveShelf) {
+ mAboveShelf = aboveShelf;
+ }
+
+ public class NotificationViewState extends ExpandableViewState {
+
+ private final StackScrollState mOverallState;
+
+
+ private NotificationViewState(StackScrollState stackScrollState) {
+ mOverallState = stackScrollState;
+ }
+
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ row.applyChildrenState(mOverallState);
+ }
+ }
+
+ @Override
+ protected void onYTranslationAnimationFinished() {
+ super.onYTranslationAnimationFinished();
+ if (mHeadsupDisappearRunning) {
+ setHeadsUpAnimatingAway(false);
+ }
+ }
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ row.startChildAnimation(mOverallState, properties);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 9d9f3b9..91abc87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -41,7 +41,7 @@
outline.setRect(translation,
mClipTopAmount,
getWidth() + translation,
- Math.max(getActualHeight(), mClipTopAmount));
+ Math.max(getActualHeight() - mClipBottomAmount, mClipTopAmount));
} else {
outline.setRect(mOutlineRect);
}
@@ -66,6 +66,12 @@
invalidateOutline();
}
+ @Override
+ public void setClipBottomAmount(int clipBottomAmount) {
+ super.setClipBottomAmount(clipBottomAmount);
+ invalidateOutline();
+ }
+
protected void setOutlineAlpha(float alpha) {
if (alpha != mOutlineAlpha) {
mOutlineAlpha = alpha;
@@ -97,15 +103,23 @@
if (mCustomOutline) {
return;
}
- boolean hasOutline = true;
- if (isChildInGroup()) {
- hasOutline = isGroupExpanded() && !isGroupExpansionChanging();
- } else if (isSummaryWithChildren()) {
- hasOutline = !isGroupExpanded() || isGroupExpansionChanging();
- }
+ boolean hasOutline = needsOutline();
setOutlineProvider(hasOutline ? mProvider : null);
}
+ /**
+ * @return whether the view currently needs an outline. This is usually false in case it doesn't
+ * have a background.
+ */
+ protected boolean needsOutline() {
+ if (isChildInGroup()) {
+ return isGroupExpanded() && !isGroupExpansionChanging();
+ } else if (isSummaryWithChildren()) {
+ return !isGroupExpanded() || isGroupExpansionChanging();
+ }
+ return true;
+ }
+
public boolean isOutlineShowing() {
ViewOutlineProvider op = getOutlineProvider();
return op != null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 83b0ee0..37a900e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -25,6 +25,8 @@
import android.widget.FrameLayout;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.StackScrollState;
import java.util.ArrayList;
@@ -36,6 +38,7 @@
protected OnHeightChangedListener mOnHeightChangedListener;
private int mActualHeight;
protected int mClipTopAmount;
+ protected int mClipBottomAmount;
private boolean mDark;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
private static Rect mClipRect = new Rect();
@@ -44,6 +47,8 @@
private boolean mClipToActualHeight = true;
private boolean mChangingPosition = false;
private ViewGroup mTransientContainer;
+ private boolean mInShelf;
+ private boolean mTransformingInShelf;
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -220,10 +225,26 @@
updateClipping();
}
+ /**
+ * Set the amount the the notification is clipped on the bottom in addition to the regular
+ * clipping. This is mainly used to clip something in a non-animated way without changing the
+ * actual height of the notification and is purely visual.
+ *
+ * @param clipBottomAmount the amount to clip.
+ */
+ public void setClipBottomAmount(int clipBottomAmount) {
+ mClipBottomAmount = clipBottomAmount;
+ updateClipping();
+ }
+
public int getClipTopAmount() {
return mClipTopAmount;
}
+ public int getClipBottomAmount() {
+ return mClipBottomAmount;
+ }
+
public void setOnHeightChangedListener(OnHeightChangedListener listener) {
mOnHeightChangedListener = listener;
}
@@ -261,9 +282,18 @@
public abstract void performAddAnimation(long delay, long duration);
+ /**
+ * Set the notification appearance to be below the speed bump.
+ * @param below true if it is below.
+ */
public void setBelowSpeedBump(boolean below) {
}
+ public int getPinnedHeadsUpHeight() {
+ return getIntrinsicHeight();
+ }
+
+
/**
* Sets the translation of the view.
*/
@@ -324,10 +354,8 @@
private void updateClipping() {
if (mClipToActualHeight) {
int top = getClipTopAmount();
- if (top >= getActualHeight()) {
- top = getActualHeight() - 1;
- }
- mClipRect.set(0, top, getWidth(), getActualHeight() + getExtraBottomPadding());
+ mClipRect.set(0, top, getWidth(), Math.max(getActualHeight() + getExtraBottomPadding()
+ - mClipBottomAmount, top));
setClipBounds(mClipRect);
} else {
setClipBounds(null);
@@ -438,6 +466,46 @@
public void setActualHeightAnimating(boolean animating) {}
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return new ExpandableViewState();
+ }
+
+ /**
+ * @return whether the current view doesn't add height to the overall content. This means that
+ * if it is added to a list of items, it's content will still have the same height.
+ * An example is the notification shelf, that is always placed on top of another view.
+ */
+ public boolean hasNoContentHeight() {
+ return false;
+ }
+
+ /**
+ * @param inShelf whether the view is currently fully in the notification shelf.
+ */
+ public void setInShelf(boolean inShelf) {
+ mInShelf = inShelf;
+ }
+
+ public boolean isInShelf() {
+ return mInShelf;
+ }
+
+ /**
+ * @param transformingInShelf whether the view is currently transforming into the shelf in an
+ * animated way
+ */
+ public void setTransformingInShelf(boolean transformingInShelf) {
+ mTransformingInShelf = transformingInShelf;
+ }
+
+ public boolean isTransformingIntoShelf() {
+ return mTransformingInShelf;
+ }
+
+ public boolean isAboveShelf() {
+ return false;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 0ef97152..218c1bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar;
import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -36,6 +37,7 @@
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup;
import com.android.internal.app.IBatteryStats;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -58,7 +60,9 @@
private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
private final Context mContext;
+ private final ViewGroup mIndicationArea;
private final KeyguardIndicationTextView mTextView;
+ private final KeyguardIndicationTextView mDisclosure;
private final UserManager mUserManager;
private final IBatteryStats mBatteryInfo;
@@ -78,10 +82,16 @@
private int mChargingWattage;
private String mMessageToShowOnScreenOn;
- public KeyguardIndicationController(Context context, KeyguardIndicationTextView textView,
- LockIcon lockIcon) {
+ private final DevicePolicyManager mDevicePolicyManager;
+
+ public KeyguardIndicationController(Context context, ViewGroup indicationArea,
+ LockIcon lockIcon) {
mContext = context;
- mTextView = textView;
+ mIndicationArea = indicationArea;
+ mTextView = (KeyguardIndicationTextView) indicationArea.findViewById(
+ R.id.keyguard_indication_text);
+ mDisclosure = (KeyguardIndicationTextView) indicationArea.findViewById(
+ R.id.keyguard_indication_enterprise_disclosure);
mLockIcon = lockIcon;
Resources res = context.getResources();
@@ -92,14 +102,39 @@
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
+ mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
+
+ updateDisclosure();
+ }
+
+ private void updateDisclosure() {
+ if (mDevicePolicyManager == null) {
+ return;
+ }
+
+ if (mDevicePolicyManager.isDeviceManaged()) {
+ final CharSequence organizationName =
+ mDevicePolicyManager.getDeviceOwnerOrganizationName();
+ if (organizationName != null) {
+ mDisclosure.switchIndication(mContext.getResources().getString(
+ R.string.do_disclosure_with_name, organizationName));
+ } else {
+ mDisclosure.switchIndication(R.string.do_disclosure_generic);
+ }
+ mDisclosure.setVisibility(View.VISIBLE);
+ } else {
+ mDisclosure.setVisibility(View.GONE);
+ }
}
public void setVisible(boolean visible) {
mVisible = visible;
- mTextView.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
if (visible) {
hideTransientIndication();
updateIndication();
@@ -242,6 +277,13 @@
}
@Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ if (showing) {
+ updateDisclosure();
+ }
+ }
+
+ @Override
public void onFingerprintHelp(int msgId, String helpString) {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 8688c28..dea9e31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -33,6 +33,7 @@
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
+ private int mClipBottomAmount;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -44,8 +45,9 @@
}
private void draw(Canvas canvas, Drawable drawable) {
- if (drawable != null && mActualHeight > mClipTopAmount) {
- drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+ int bottom = mActualHeight - mClipBottomAmount;
+ if (drawable != null && bottom > mClipTopAmount) {
+ drawable.setBounds(0, mClipTopAmount, getWidth(), bottom);
drawable.draw(canvas);
}
}
@@ -120,6 +122,11 @@
invalidate();
}
+ public void setClipBottomAmount(int clipBottomAmount) {
+ mClipBottomAmount = clipBottomAmount;
+ invalidate();
+ }
+
@Override
public boolean hasOverlappingRendering() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 58d57f6..ad6a5db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -121,7 +121,9 @@
private int mContentHeightAtAnimationStart = UNDEFINED;
private boolean mFocusOnVisibilityChange;
- private boolean mHeadsupDisappearRunning;
+ private boolean mHeadsUpAnimatingAway;
+ private boolean mIconsVisible;
+ private int mClipBottomAmount;
public NotificationContentView(Context context, AttributeSet attrs) {
@@ -456,7 +458,7 @@
isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED)
- && (mIsHeadsUp || mHeadsupDisappearRunning);
+ && (mIsHeadsUp || mHeadsUpAnimatingAway);
if (transitioningBetweenHunAndExpanded || pinned) {
return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
}
@@ -587,9 +589,24 @@
updateClipping();
}
+
+ public void setClipBottomAmount(int clipBottomAmount) {
+ mClipBottomAmount = clipBottomAmount;
+ updateClipping();
+ }
+
+ @Override
+ public void setTranslationY(float translationY) {
+ super.setTranslationY(translationY);
+ updateClipping();
+ }
+
private void updateClipping() {
if (mClipToActualHeight) {
- mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
+ int top = (int) (mClipTopAmount - getTranslationY());
+ int bottom = (int) (mContentHeight - mClipBottomAmount - getTranslationY());
+ bottom = Math.max(top, bottom);
+ mClipBounds.set(0, top, getWidth(), bottom);
setClipBounds(mClipBounds);
} else {
setClipBounds(null);
@@ -840,7 +857,7 @@
return VISIBLE_TYPE_SINGLELINE;
}
- if ((mIsHeadsUp || mHeadsupDisappearRunning) && mHeadsUpChild != null) {
+ if ((mIsHeadsUp || mHeadsUpAnimatingAway) && mHeadsUpChild != null) {
if (viewHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
return VISIBLE_TYPE_HEADSUP;
} else {
@@ -1183,12 +1200,38 @@
}
}
- public void setHeadsupDisappearRunning(boolean headsupDisappearRunning) {
- mHeadsupDisappearRunning = headsupDisappearRunning;
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ mHeadsUpAnimatingAway = headsUpAnimatingAway;
selectLayout(false /* animate */, true /* force */);
}
public void setFocusOnVisibilityChange() {
mFocusOnVisibilityChange = true;
}
+
+ public void setIconsVisible(boolean iconsVisible) {
+ mIconsVisible = iconsVisible;
+ updateIconVisibilities();
+ }
+
+ private void updateIconVisibilities() {
+ if (mContractedWrapper != null) {
+ NotificationHeaderView header = mContractedWrapper.getNotificationHeader();
+ if (header != null) {
+ header.getIcon().setForceHidden(!mIconsVisible);
+ }
+ }
+ if (mHeadsUpWrapper != null) {
+ NotificationHeaderView header = mHeadsUpWrapper.getNotificationHeader();
+ if (header != null) {
+ header.getIcon().setForceHidden(!mIconsVisible);
+ }
+ }
+ if (mExpandedWrapper != null) {
+ NotificationHeaderView header = mExpandedWrapper.getNotificationHeader();
+ if (header != null) {
+ header.getIcon().setForceHidden(!mIconsVisible);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 7019880..3687f6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -19,6 +19,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
+import android.graphics.drawable.Icon;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -26,8 +27,11 @@
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.view.View;
+import android.widget.ImageView;
import android.widget.RemoteViews;
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -48,9 +52,11 @@
public static final class Entry {
private static final long LAUNCH_COOLDOWN = 2000;
private static final long NOT_LAUNCHED_YET = -LAUNCH_COOLDOWN;
+ private static final int COLOR_INVALID = 1;
public String key;
public StatusBarNotification notification;
public StatusBarIconView icon;
+ public StatusBarIconView expandedIcon;
public ExpandableNotificationRow row; // the outer expanded view
private boolean interruption;
public boolean autoRedacted; // whether the redacted notification was generated by us
@@ -62,11 +68,12 @@
public RemoteViews cachedHeadsUpContentView;
public RemoteViews cachedPublicContentView;
public CharSequence remoteInputText;
+ private int mCachedContrastColor = COLOR_INVALID;
+ private int mCachedContrastColorIsFor = COLOR_INVALID;
- public Entry(StatusBarNotification n, StatusBarIconView ic) {
+ public Entry(StatusBarNotification n) {
this.key = n.getKey();
this.notification = n;
- this.icon = ic;
}
public void setInterruption() {
@@ -165,6 +172,85 @@
public boolean hasJustLaunchedFullScreenIntent() {
return SystemClock.elapsedRealtime() < lastFullScreenIntentLaunchTime + LAUNCH_COOLDOWN;
}
+
+ /**
+ * Create the icons for a notification
+ * @param context the context to create the icons with
+ * @param sbn the notification
+ * @throws IconException
+ */
+ public void createIcons(Context context, StatusBarNotification sbn) throws IconException {
+ Notification n = sbn.getNotification();
+ final Icon smallIcon = n.getSmallIcon();
+ if (smallIcon == null) {
+ throw new IconException("No small icon in notification from "
+ + sbn.getPackageName());
+ }
+
+ // Construct the icon.
+ icon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
+ icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+
+ // Construct the expanded icon.
+ expandedIcon = new StatusBarIconView(context,
+ sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n);
+ expandedIcon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ final StatusBarIcon ic = new StatusBarIcon(
+ sbn.getUser(),
+ sbn.getPackageName(),
+ smallIcon,
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ icon = null;
+ expandedIcon = null;
+ throw new IconException("Couldn't create icon: " + ic);
+ }
+ }
+
+ public void setIconTag(int key, Object tag) {
+ if (icon != null) {
+ icon.setTag(key, tag);
+ expandedIcon.setTag(key, tag);
+ }
+ }
+
+ /**
+ * Update the notification icons.
+ * @param context the context to create the icons with.
+ * @param n the notification to read the icon from.
+ * @throws IconException
+ */
+ public void updateIcons(Context context, Notification n) throws IconException {
+ if (icon != null) {
+ // Update the icon
+ final StatusBarIcon ic = new StatusBarIcon(
+ notification.getUser(),
+ notification.getPackageName(),
+ n.getSmallIcon(),
+ n.iconLevel,
+ n.number,
+ StatusBarIconView.contentDescForNotification(context, n));
+ icon.setNotification(n);
+ expandedIcon.setNotification(n);
+ if (!icon.set(ic) || !expandedIcon.set(ic)) {
+ throw new IconException("Couldn't update icon: " + ic);
+ }
+ }
+ }
+
+ public int getContrastedColor(Context context) {
+ int rawColor = notification.getNotification().color;
+ if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
+ return mCachedContrastColor;
+ }
+ final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor);
+ mCachedContrastColorIsFor = rawColor;
+ mCachedContrastColor = contrasted;
+ return mCachedContrastColor;
+ }
}
private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
@@ -472,4 +558,10 @@
public String getCurrentMediaNotificationKey();
public NotificationGroupManager getGroupManager();
}
+
+ public static class IconException extends Exception {
+ IconException(String error) {
+ super(error);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index bb327ef..ed1179a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -62,6 +62,7 @@
private Drawable mBackground;
private int mClipTopAmount;
+ private int mClipBottomAmount;
private int mActualHeight;
private boolean mExposed;
private INotificationManager mINotificationManager;
@@ -136,8 +137,10 @@
}
private void draw(Canvas canvas, Drawable drawable) {
- if (drawable != null) {
- drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+ int top = mClipTopAmount;
+ int bottom = mActualHeight - mClipBottomAmount;
+ if (drawable != null && top < bottom) {
+ drawable.setBounds(0, top, getWidth(), bottom);
drawable.draw(canvas);
}
}
@@ -423,6 +426,11 @@
invalidate();
}
+ public void setClipBottomAmount(int clipBottomAmount) {
+ mClipBottomAmount = clipBottomAmount;
+ invalidate();
+ }
+
@Override
public boolean hasOverlappingRendering() {
// Prevents this view from creating a layer when alpha is animating.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
deleted file mode 100644
index 8e8ce1a..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ /dev/null
@@ -1,73 +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 com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-/**
- * Container view for overflowing notification icons on Keyguard.
- */
-public class NotificationOverflowContainer extends ActivatableNotificationView {
-
- private NotificationOverflowIconsView mIconsView;
- private ViewInvertHelper mViewInvertHelper;
- private boolean mDark;
- private View mContent;
-
- public NotificationOverflowContainer(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
- mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
- mIconsView.setOverflowIndicator(findViewById(R.id.more_icon_overflow));
- mContent = findViewById(R.id.content);
- mViewInvertHelper = new ViewInvertHelper(mContent,
- NotificationPanelView.DOZE_ANIMATION_DURATION);
- }
-
- @Override
- public void setDark(boolean dark, boolean fade, long delay) {
- super.setDark(dark, fade, delay);
- if (mDark == dark) return;
- mDark = dark;
- if (fade) {
- mViewInvertHelper.fade(dark, delay);
- } else {
- mViewInvertHelper.update(dark);
- }
- }
-
- @Override
- protected View getContentView() {
- return mContent;
- }
-
- public NotificationOverflowIconsView getIconsView() {
- return mIconsView;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
deleted file mode 100644
index 88bb714..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowIconsView.java
+++ /dev/null
@@ -1,75 +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 com.android.systemui.statusbar;
-
-import android.app.Notification;
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.internal.util.NotificationColorUtil;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.IconMerger;
-
-/**
- * A view to display all the overflowing icons on Keyguard.
- */
-public class NotificationOverflowIconsView extends IconMerger {
-
- private TextView mMoreText;
- private int mTintColor;
- private int mIconSize;
- private NotificationColorUtil mNotificationColorUtil;
-
- public NotificationOverflowIconsView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mNotificationColorUtil = NotificationColorUtil.getInstance(getContext());
- mTintColor = getContext().getColor(R.color.keyguard_overflow_content_color);
- mIconSize = getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_icon_size);
- }
-
- public void setMoreText(TextView moreText) {
- mMoreText = moreText;
- }
-
- public void addNotification(NotificationData.Entry notification) {
- StatusBarIconView v = new StatusBarIconView(getContext(), "",
- notification.notification.getNotification());
- v.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- addView(v, mIconSize, mIconSize);
- v.set(notification.icon.getStatusBarIcon());
- applyColor(notification.notification.getNotification(), v);
- updateMoreText();
- }
-
- private void applyColor(Notification notification, StatusBarIconView view) {
- view.setColorFilter(mTintColor, PorterDuff.Mode.MULTIPLY);
- }
-
- private void updateMoreText() {
- mMoreText.setText(
- getResources().getString(R.string.keyguard_more_overflow_text, getChildCount()));
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
new file mode 100644
index 0000000..680562a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -0,0 +1,474 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.stack.AmbientState;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackScrollState;
+
+import java.util.ArrayList;
+import java.util.WeakHashMap;
+
+/**
+ * A notification shelf view that is placed inside the notification scroller. It manages the
+ * overflow icons that don't fit into the regular list anymore.
+ */
+public class NotificationShelf extends ActivatableNotificationView {
+
+ private ViewInvertHelper mViewInvertHelper;
+ private boolean mDark;
+ private NotificationIconContainer mShelfIcons;
+ private ArrayList<StatusBarIconView> mIcons = new ArrayList<>();
+ private ShelfState mShelfState;
+ private int[] mTmp = new int[2];
+ private boolean mHideBackground;
+ private int mIconAppearTopPadding;
+ private int mStatusBarHeight;
+ private int mStatusBarPaddingStart;
+ private AmbientState mAmbientState;
+ private NotificationStackScrollLayout mHostLayout;
+ private int mMaxLayoutHeight;
+ private int mPaddingBetweenElements;
+ private int mNotGoneIndex;
+ private boolean mHasItemsInStableShelf;
+ private NotificationIconContainer mCollapsedIcons;
+
+ public NotificationShelf(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mShelfIcons = (NotificationIconContainer) findViewById(R.id.content);
+ mShelfIcons.setClipChildren(false);
+ mShelfIcons.setClipToPadding(false);
+
+ setClipToActualHeight(false);
+ setClipChildren(false);
+ setClipToPadding(false);
+ mShelfIcons.setShowAllIcons(false);
+ mViewInvertHelper = new ViewInvertHelper(mShelfIcons,
+ NotificationPanelView.DOZE_ANIMATION_DURATION);
+ mShelfState = new ShelfState();
+ initDimens();
+ }
+
+ public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) {
+ mAmbientState = ambientState;
+ mHostLayout = hostLayout;
+ }
+
+ private void initDimens() {
+ mIconAppearTopPadding = getResources().getDimensionPixelSize(
+ R.dimen.notification_icon_appear_padding);
+ mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
+ mStatusBarPaddingStart = getResources().getDimensionPixelOffset(
+ R.dimen.status_bar_padding_start);
+ mPaddingBetweenElements = getResources().getDimensionPixelSize(
+ R.dimen.notification_divider_height);
+ ViewGroup.LayoutParams layoutParams = getLayoutParams();
+ layoutParams.height = getResources().getDimensionPixelOffset(
+ R.dimen.notification_shelf_height);
+ setLayoutParams(layoutParams);
+ int padding = getResources().getDimensionPixelOffset(R.dimen.shelf_icon_container_padding);
+ mShelfIcons.setPadding(padding, 0, padding, 0);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ initDimens();
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ super.setDark(dark, fade, delay);
+ if (mDark == dark) return;
+ mDark = dark;
+ if (fade) {
+ mViewInvertHelper.fade(dark, delay);
+ } else {
+ mViewInvertHelper.update(dark);
+ }
+ }
+
+ @Override
+ protected View getContentView() {
+ return mShelfIcons;
+ }
+
+ public NotificationIconContainer getShelfIcons() {
+ return mShelfIcons;
+ }
+
+ @Override
+ public ExpandableViewState createNewViewState(StackScrollState stackScrollState) {
+ return mShelfState;
+ }
+
+ public void updateState(StackScrollState resultState,
+ AmbientState ambientState) {
+ View lastView = ambientState.getLastVisibleBackgroundChild();
+ if (lastView != null) {
+ float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding()
+ + ambientState.getStackTranslation();
+ ExpandableViewState lastViewState = resultState.getViewStateForView(lastView);
+ float viewEnd = lastViewState.yTranslation + lastViewState.height;
+ mShelfState.copyFrom(lastViewState);
+ mShelfState.height = getIntrinsicHeight();
+ mShelfState.yTranslation = Math.max(Math.min(viewEnd, maxShelfEnd) - mShelfState.height,
+ getFullyClosedTranslation());
+ mShelfState.zTranslation = ambientState.getBaseZHeight();
+ float openedAmount = (mShelfState.yTranslation - getFullyClosedTranslation())
+ / (getIntrinsicHeight() * 2);
+ openedAmount = Math.min(1.0f, openedAmount);
+ mShelfState.openedAmount = openedAmount;
+ mShelfState.clipTopAmount = 0;
+ mShelfState.alpha = 1.0f;
+ mShelfState.belowSpeedBump = mAmbientState.getSpeedBumpIndex() == 0;
+ mShelfState.shadowAlpha = 1.0f;
+ mShelfState.hideSensitive = false;
+ mShelfState.xTranslation = getTranslationX();
+ if (mNotGoneIndex != -1) {
+ mShelfState.notGoneIndex = Math.min(mShelfState.notGoneIndex, mNotGoneIndex);
+ }
+ mShelfState.hasItemsInStableShelf = lastViewState.inShelf;
+ } else {
+ mShelfState.hidden = true;
+ mShelfState.location = ExpandableViewState.LOCATION_GONE;
+ mShelfState.hasItemsInStableShelf = false;
+ }
+ }
+
+ /**
+ * Update the shelf appearance based on the other notifications around it. This transforms
+ * the icons from the notification area into the shelf.
+ */
+ public void updateAppearance() {
+ WeakHashMap<View, NotificationIconContainer.IconState> iconStates =
+ mShelfIcons.resetViewStates();
+ float numViewsInShelf = 0.0f;
+ View lastChild = mAmbientState.getLastVisibleBackgroundChild();
+ mNotGoneIndex = -1;
+ float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
+ float expandAmount = 0.0f;
+ if (getTranslationY() >= interpolationStart) {
+ expandAmount = (getTranslationY() - interpolationStart) / getIntrinsicHeight();
+ expandAmount = Math.min(1.0f, expandAmount);
+ }
+ // find the first view that doesn't overlap with the shelf
+ int notificationIndex = 0;
+ int notGoneIndex = 0;
+ int colorOfViewBeforeLast = 0;
+ boolean backgroundForceHidden = false;
+ if (mHideBackground && !mShelfState.hasItemsInStableShelf) {
+ backgroundForceHidden = true;
+ }
+ int colorTwoBefore = NO_COLOR;
+ int previousColor = NO_COLOR;
+ float transitionAmount = 0.0f;
+ while (notificationIndex < mHostLayout.getChildCount()) {
+ ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
+ notificationIndex++;
+ if (!(child instanceof ExpandableNotificationRow)
+ || child.getVisibility() == GONE) {
+ continue;
+ }
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ StatusBarIconView icon = row.getEntry().expandedIcon;
+ NotificationIconContainer.IconState iconState = iconStates.get(icon);
+ float notificationClipEnd;
+ float shelfStart = getTranslationY();
+ boolean aboveShelf = row.getTranslationZ() > mAmbientState.getBaseZHeight();
+ boolean isLastChild = child == lastChild;
+ if (isLastChild || aboveShelf || backgroundForceHidden) {
+ notificationClipEnd = shelfStart + getIntrinsicHeight();
+ } else {
+ notificationClipEnd = shelfStart - mPaddingBetweenElements;
+ float height = notificationClipEnd - row.getTranslationY();
+ if (!row.isBelowSpeedBump() && height <= getNotificationMergeSize()) {
+ // We want the gap to close when we reached the minimum size and only shrink
+ // before
+ notificationClipEnd = Math.min(shelfStart,
+ row.getTranslationY() + getNotificationMergeSize());
+ }
+ }
+ updateNotificationClipHeight(row, notificationClipEnd);
+ float inShelfAmount = updateIconAppearance(row, iconState, icon, expandAmount,
+ isLastChild);
+ numViewsInShelf += inShelfAmount;
+ int ownColorUntinted = row.getBackgroundColorWithoutTint();
+ if (row.getTranslationY() >= getTranslationY() && mNotGoneIndex == -1) {
+ mNotGoneIndex = notGoneIndex;
+ setTintColor(previousColor);
+ setOverrideTintColor(colorTwoBefore, transitionAmount);
+
+ } else if (mNotGoneIndex == -1) {
+ colorTwoBefore = previousColor;
+ transitionAmount = inShelfAmount;
+ }
+ if (isLastChild && colorOfViewBeforeLast != NO_COLOR) {
+ row.setOverrideTintColor(colorOfViewBeforeLast, inShelfAmount);
+ } else {
+ colorOfViewBeforeLast = ownColorUntinted;
+ row.setOverrideTintColor(NO_COLOR, 0 /* overrideAmount */);
+ }
+ if (notGoneIndex != 0 || !aboveShelf) {
+ row.setAboveShelf(false);
+ }
+ notGoneIndex++;
+ previousColor = ownColorUntinted;
+ }
+ mShelfIcons.calculateIconTranslations();
+ mShelfIcons.applyIconStates();
+ setVisibility(numViewsInShelf != 0.0f && mAmbientState.isShadeExpanded()
+ ? VISIBLE
+ : INVISIBLE);
+ boolean hideBackground = numViewsInShelf < 1.0f;
+ setHideBackground(hideBackground || backgroundForceHidden);
+ if (mNotGoneIndex == -1) {
+ mNotGoneIndex = notGoneIndex;
+ }
+ }
+
+ private void updateNotificationClipHeight(ExpandableNotificationRow row,
+ float notificationClipEnd) {
+ float viewEnd = row.getTranslationY() + row.getActualHeight();
+ if (viewEnd > notificationClipEnd
+ && (mAmbientState.isShadeExpanded()
+ || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+ row.setClipBottomAmount((int) (viewEnd - notificationClipEnd));
+ } else {
+ row.setClipBottomAmount(0);
+ }
+ }
+
+ /**
+ * @return the icon amount how much this notification is in the shelf;
+ */
+ private float updateIconAppearance(ExpandableNotificationRow row,
+ NotificationIconContainer.IconState iconState, StatusBarIconView icon,
+ float expandAmount, boolean isLastChild) {
+ // Let calculate how much the view is in the shelf
+ float viewStart = row.getTranslationY();
+ int transformHeight = row.getActualHeight() + mPaddingBetweenElements;
+ if (isLastChild) {
+ transformHeight =
+ Math.min(transformHeight, row.getMinHeight() - getIntrinsicHeight());
+ }
+ float viewEnd = viewStart + transformHeight;
+ float iconAppearAmount;
+ float yTranslation;
+ float alpha = 1.0f;
+ if (viewEnd >= getTranslationY() && (mAmbientState.isShadeExpanded()
+ || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+ if (viewStart < getTranslationY()) {
+ float linearAmount = (getTranslationY() - viewStart) / transformHeight;
+ float interpolatedAmount = Interpolators.ACCELERATE_DECELERATE.getInterpolation(
+ linearAmount);
+ interpolatedAmount = NotificationUtils.interpolate(
+ interpolatedAmount, linearAmount, expandAmount);
+ iconAppearAmount = 1.0f - interpolatedAmount;
+ } else {
+ iconAppearAmount = 1.0f;
+ }
+ } else {
+ iconAppearAmount = 0.0f;
+ }
+
+ // Lets now calculate how much of the transformation has already happened. This is different
+ // from the above, since we only start transforming when the view is already quite a bit
+ // pushed in.
+ View rowIcon = row.getNotificationIcon();
+ float notificationIconPosition = viewStart;
+ float notificationIconSize = 0.0f;
+ int iconTopPadding;
+ if (rowIcon != null) {
+ iconTopPadding = row.getRelativeTopPadding(rowIcon);
+ notificationIconSize = rowIcon.getHeight();
+ } else {
+ iconTopPadding = mIconAppearTopPadding;
+ }
+ notificationIconPosition += iconTopPadding;
+ float shelfIconPosition = getTranslationY() + icon.getTop();
+ shelfIconPosition += ((1.0f - icon.getIconScale()) * icon.getHeight()) / 2.0f;
+ float transitionDistance = getIntrinsicHeight() * 1.5f;
+ if (isLastChild) {
+ transitionDistance = Math.min(transitionDistance, row.getMinHeight()
+ - getIntrinsicHeight());
+ }
+ float transformationStartPosition = getTranslationY() - transitionDistance;
+ float transitionAmount = 0.0f;
+ if (viewStart < transformationStartPosition
+ || (!mAmbientState.isShadeExpanded()
+ && (row.isPinned() || row.isHeadsUpAnimatingAway()))) {
+ // We simply place it on the icon of the notification
+ yTranslation = notificationIconPosition - shelfIconPosition;
+ } else {
+ transitionAmount = (viewStart - transformationStartPosition)
+ / transitionDistance;
+ float startPosition = transformationStartPosition + iconTopPadding;
+ yTranslation = NotificationUtils.interpolate(
+ startPosition - shelfIconPosition, 0, transitionAmount);
+ // If we are merging into the shelf, lets make sure the shelf is at least on our height,
+ // otherwise the icons won't be visible.
+ setTranslationZ(Math.max(getTranslationZ(), row.getTranslationZ()));
+ }
+ float shelfIconSize = icon.getHeight() * icon.getIconScale();
+ if (!row.isShowingIcon()) {
+ // The view currently doesn't have an icon, lets transform it in!
+ alpha = transitionAmount;
+ notificationIconSize = shelfIconSize / 2.0f;
+ }
+ // The notification size is different from the size in the shelf / statusbar
+ float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
+ transitionAmount);
+ row.setIconTransformationAmount(transitionAmount, isLastChild);
+ if (iconState != null) {
+ iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
+ iconState.scaleY = iconState.scaleX;
+ iconState.hidden = transitionAmount == 0.0f;
+ iconState.iconAppearAmount = iconAppearAmount;
+ iconState.alpha = alpha;
+ iconState.yTranslation = yTranslation;
+ icon.setVisibility(transitionAmount == 0.0f ? INVISIBLE : VISIBLE);
+ if (row.isInShelf() && !row.isTransformingIntoShelf()) {
+ iconState.iconAppearAmount = 1.0f;
+ iconState.alpha = 1.0f;
+ iconState.scaleX = 1.0f;
+ iconState.scaleY = 1.0f;
+ iconState.hidden = false;
+ }
+ }
+ return iconAppearAmount;
+ }
+
+ private float getFullyClosedTranslation() {
+ return - (getIntrinsicHeight() - mStatusBarHeight) / 2;
+ }
+
+ public int getNotificationMergeSize() {
+ return getIntrinsicHeight();
+ }
+
+ @Override
+ public boolean hasNoContentHeight() {
+ return true;
+ }
+
+ private void setHideBackground(boolean hideBackground) {
+ mHideBackground = hideBackground;
+ updateBackground();
+ updateOutline();
+ }
+
+ public boolean hidesBackground() {
+ return mHideBackground;
+ }
+
+ @Override
+ protected boolean needsOutline() {
+ return !mHideBackground && super.needsOutline();
+ }
+
+ @Override
+ protected boolean shouldHideBackground() {
+ return super.shouldHideBackground() || mHideBackground;
+ }
+
+ private void setOpenedAmount(float openedAmount) {
+ mCollapsedIcons.getLocationOnScreen(mTmp);
+ int start = mTmp[0];
+ if (isLayoutRtl()) {
+ start = getWidth() - start - mCollapsedIcons.getWidth();
+ }
+ int width = (int) NotificationUtils.interpolate(start + mCollapsedIcons.getWidth(),
+ mShelfIcons.getWidth(),
+ openedAmount);
+ mShelfIcons.setActualLayoutWidth(width);
+ float padding = NotificationUtils.interpolate(mCollapsedIcons.getPaddingEnd(),
+ mShelfIcons.getPaddingEnd(),
+ openedAmount);
+ mShelfIcons.setActualPaddingEnd(padding);
+ float paddingStart = NotificationUtils.interpolate(start,
+ mShelfIcons.getPaddingStart(), openedAmount);
+ mShelfIcons.setActualPaddingStart(paddingStart);
+ }
+
+ public void setMaxLayoutHeight(int maxLayoutHeight) {
+ mMaxLayoutHeight = maxLayoutHeight;
+ }
+
+ /**
+ * @return the index of the notification at which the shelf visually resides
+ */
+ public int getNotGoneIndex() {
+ return mNotGoneIndex;
+ }
+
+ private void setHasItemsInStableShelf(boolean hasItemsInStableShelf) {
+ mHasItemsInStableShelf = hasItemsInStableShelf;
+ }
+
+ /**
+ * @return whether the shelf has any icons in it when a potential animation has finished, i.e
+ * if the current state would be applied right now
+ */
+ public boolean hasItemsInStableShelf() {
+ return mHasItemsInStableShelf;
+ }
+
+ public void setCollapsedIcons(NotificationIconContainer collapsedIcons) {
+ mCollapsedIcons = collapsedIcons;
+ }
+
+ private class ShelfState extends ExpandableViewState {
+ private float openedAmount;
+ private boolean hasItemsInStableShelf;
+
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ updateAppearance();
+ setOpenedAmount(openedAmount);
+ setHasItemsInStableShelf(hasItemsInStableShelf);
+ }
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ setOpenedAmount(openedAmount);
+ updateAppearance();
+ setHasItemsInStableShelf(hasItemsInStableShelf);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index cdfdad4..d635bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -30,20 +33,55 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.util.Log;
+import android.util.Property;
import android.util.TypedValue;
import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Interpolator;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.NotificationUtils;
import java.text.NumberFormat;
public class StatusBarIconView extends AnimatedImageView {
- private static final String TAG = "StatusBarIconView";
- private boolean mAlwaysScaleIcon;
+ public static final int STATE_ICON = 0;
+ public static final int STATE_DOT = 1;
+ public static final int STATE_HIDDEN = 2;
+ private static final String TAG = "StatusBarIconView";
+ private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
+ = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
+
+ @Override
+ public void setValue(StatusBarIconView object, float value) {
+ object.setIconAppearAmount(value);
+ }
+
+ @Override
+ public Float get(StatusBarIconView object) {
+ return object.getIconAppearAmount();
+ }
+ };
+ private static final Property<StatusBarIconView, Float> DOT_APPEAR_AMOUNT
+ = new FloatProperty<StatusBarIconView>("dot_appear_amount") {
+
+ @Override
+ public void setValue(StatusBarIconView object, float value) {
+ object.setDotAppearAmount(value);
+ }
+
+ @Override
+ public Float get(StatusBarIconView object) {
+ return object.getDotAppearAmount();
+ }
+ };
+
+ private boolean mAlwaysScaleIcon;
private StatusBarIcon mIcon;
@ViewDebug.ExportedProperty private String mSlot;
private Drawable mNumberBackground;
@@ -54,6 +92,16 @@
private Notification mNotification;
private final boolean mBlocked;
private int mDensity;
+ private float mIconScale = 1.0f;
+ private final Paint mDotPaint = new Paint();
+ private boolean mDotVisible;
+ private float mDotRadius;
+ private int mStaticDotRadius;
+ private int mVisibleState = STATE_ICON;
+ private float mIconAppearAmount = 1.0f;
+ private ObjectAnimator mIconAppearAnimator;
+ private ObjectAnimator mDotAnimator;
+ private float mDotAppearAmount;
public StatusBarIconView(Context context, String slot, Notification notification) {
this(context, slot, notification, false);
@@ -72,6 +120,11 @@
maybeUpdateIconScale();
setScaleType(ScaleType.CENTER);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
+ if (mNotification != null) {
+ setIconTint(getContext().getColor(
+ com.android.internal.R.color.notification_icon_default_color));
+ }
+ reloadDimens();
}
private void maybeUpdateIconScale() {
@@ -86,9 +139,11 @@
Resources res = mContext.getResources();
final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
- final float scale = (float)imageBounds / (float)outerBounds;
- setScaleX(scale);
- setScaleY(scale);
+ mIconScale = (float)imageBounds / (float)outerBounds;
+ }
+
+ public float getIconScale() {
+ return mIconScale;
}
@Override
@@ -99,6 +154,15 @@
mDensity = density;
maybeUpdateIconScale();
updateDrawable();
+ reloadDimens();
+ }
+ }
+
+ private void reloadDimens() {
+ boolean applyRadius = mDotRadius == mStaticDotRadius;
+ mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ if (applyRadius) {
+ mDotRadius = mStaticDotRadius;
}
}
@@ -259,12 +323,32 @@
@Override
protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
+ if (mIconAppearAmount > 0.0f) {
+ canvas.save();
+ canvas.scale(mIconScale * mIconAppearAmount, mIconScale * mIconAppearAmount,
+ getWidth() / 2, getHeight() / 2);
+ super.onDraw(canvas);
+ canvas.restore();
+ }
if (mNumberBackground != null) {
mNumberBackground.draw(canvas);
canvas.drawText(mNumberText, mNumberX, mNumberY, mNumberPain);
}
+ if (mDotAppearAmount != 0.0f) {
+ float radius;
+ float alpha;
+ if (mDotAppearAmount <= 1.0f) {
+ radius = mDotRadius * mDotAppearAmount;
+ alpha = 1.0f;
+ } else {
+ float fadeOutAmount = mDotAppearAmount - 1.0f;
+ alpha = 1.0f - fadeOutAmount;
+ radius = NotificationUtils.interpolate(mDotRadius, getWidth() / 4, fadeOutAmount);
+ }
+ mDotPaint.setAlpha((int) (alpha * 255));
+ canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mDotPaint);
+ }
}
@Override
@@ -351,4 +435,97 @@
return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
}
+ public void setIconTint(int iconTint) {
+ mDotPaint.setColor(iconTint);
+ }
+
+ public void setVisibleState(int state) {
+ setVisibleState(state, true /* animate */, null /* endRunnable */);
+ }
+
+ public void setVisibleState(int state, boolean animate) {
+ setVisibleState(state, animate, null);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public void setVisibleState(int visibleState, boolean animate, Runnable endRunnable) {
+ if (visibleState != mVisibleState) {
+ mVisibleState = visibleState;
+ if (animate) {
+ if (mIconAppearAnimator != null) {
+ mIconAppearAnimator.cancel();
+ }
+ float targetAmount = 0.0f;
+ Interpolator interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ if (visibleState == STATE_ICON) {
+ targetAmount = 1.0f;
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+ }
+ mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT,
+ targetAmount);
+ mIconAppearAnimator.setInterpolator(interpolator);
+ mIconAppearAnimator.setDuration(100);
+ mIconAppearAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIconAppearAnimator = null;
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
+ }
+ });
+ mIconAppearAnimator.start();
+
+ if (mDotAnimator != null) {
+ mDotAnimator.cancel();
+ }
+ targetAmount = visibleState == STATE_ICON ? 2.0f : 0.0f;
+ interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ if (visibleState == STATE_DOT) {
+ targetAmount = 1.0f;
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+ }
+ mDotAnimator = ObjectAnimator.ofFloat(this, DOT_APPEAR_AMOUNT,
+ targetAmount);
+ mDotAnimator.setInterpolator(interpolator);
+ mDotAnimator.setDuration(100);
+ mDotAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDotAnimator = null;
+ }
+ });
+ mDotAnimator.start();
+ } else {
+ setIconAppearAmount(visibleState == STATE_ICON ? 1.0f : 0.0f);
+ setDotAppearAmount(visibleState == STATE_DOT ? 1.0f : 0.0f);
+ }
+ }
+ }
+
+ public void setIconAppearAmount(float iconAppearAmount) {
+ mIconAppearAmount = iconAppearAmount;
+ invalidate();
+ }
+
+ public float getIconAppearAmount() {
+ return mIconAppearAmount;
+ }
+
+ public int getVisibleState() {
+ return mVisibleState;
+ }
+
+ public void setDotAppearAmount(float dotAppearAmount) {
+ mDotAppearAmount = dotAppearAmount;
+ invalidate();
+ }
+
+ public float getDotAppearAmount() {
+ return mDotAppearAmount;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
deleted file mode 100644
index f86badb..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2008 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.phone;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-
-public class IconMerger extends LinearLayout {
- private static final String TAG = "IconMerger";
- private static final boolean DEBUG = false;
-
- private int mIconSize;
- private int mIconHPadding;
-
- private View mMoreView;
-
- public IconMerger(Context context, AttributeSet attrs) {
- super(context, attrs);
- reloadDimens();
- if (DEBUG) {
- setBackgroundColor(0x800099FF);
- }
- }
-
- private void reloadDimens() {
- Resources res = mContext.getResources();
- mIconSize = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
- mIconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_padding);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- reloadDimens();
- }
-
- public void setOverflowIndicator(View v) {
- mMoreView = v;
- }
-
- private int getFullIconWidth() {
- return mIconSize + 2 * mIconHPadding;
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- // we need to constrain this to an integral multiple of our children
- int width = getMeasuredWidth();
- setMeasuredDimension(width - (width % getFullIconWidth()), getMeasuredHeight());
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- checkOverflow(r - l);
- }
-
- private void checkOverflow(int width) {
- if (mMoreView == null) return;
-
- final int N = getChildCount();
- int visibleChildren = 0;
- for (int i=0; i<N; i++) {
- if (getChildAt(i).getVisibility() != GONE) visibleChildren++;
- }
- final boolean overflowShown = (mMoreView.getVisibility() == View.VISIBLE);
- // let's assume we have one more slot if the more icon is already showing
- if (overflowShown) visibleChildren --;
- final boolean moreRequired = visibleChildren * getFullIconWidth() > width;
- if (moreRequired != overflowShown) {
- post(new Runnable() {
- @Override
- public void run() {
- mMoreView.setVisibility(moreRequired ? View.VISIBLE : View.GONE);
- }
- });
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 89defec..daa57c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -107,6 +107,8 @@
private KeyguardAffordanceView mRightAffordanceView;
private KeyguardAffordanceView mLeftAffordanceView;
private LockIcon mLockIcon;
+ private ViewGroup mIndicationArea;
+ private TextView mEnterpriseDisclosure;
private TextView mIndicationText;
private ViewGroup mPreviewContainer;
@@ -208,6 +210,9 @@
mRightAffordanceView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button);
mLockIcon = (LockIcon) findViewById(R.id.lock_icon);
+ mIndicationArea = (ViewGroup) findViewById(R.id.keyguard_indication_area);
+ mEnterpriseDisclosure = (TextView) findViewById(
+ R.id.keyguard_indication_enterprise_disclosure);
mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text);
watchForCameraPolicyChanges();
updateCameraVisibility();
@@ -252,13 +257,16 @@
super.onConfigurationChanged(newConfig);
int indicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
- MarginLayoutParams mlp = (MarginLayoutParams) mIndicationText.getLayoutParams();
+ MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
if (mlp.bottomMargin != indicationBottomMargin) {
mlp.bottomMargin = indicationBottomMargin;
- mIndicationText.setLayoutParams(mlp);
+ mIndicationArea.setLayoutParams(mlp);
}
// Respect font size setting.
+ mEnterpriseDisclosure.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.text_size_small_material));
mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
@@ -595,8 +603,8 @@
return mLockIcon;
}
- public View getIndicationView() {
- return mIndicationText;
+ public View getIndicationArea() {
+ return mIndicationArea;
}
@Override
@@ -658,8 +666,8 @@
if (mRightAffordanceView.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mRightAffordanceView, delay);
}
- mIndicationText.setAlpha(0f);
- mIndicationText.animate()
+ mIndicationArea.setAlpha(0f);
+ mIndicationArea.animate()
.alpha(1f)
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
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 34b8371..2124011 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -37,6 +37,7 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -48,17 +49,17 @@
final static private String TAG = "KeyguardBouncer";
- protected Context mContext;
- protected ViewMediatorCallback mCallback;
- protected LockPatternUtils mLockPatternUtils;
- protected ViewGroup mContainer;
- private StatusBarWindowManager mWindowManager;
+ protected final Context mContext;
+ protected final ViewMediatorCallback mCallback;
+ protected final LockPatternUtils mLockPatternUtils;
+ protected final ViewGroup mContainer;
+ private final FalsingManager mFalsingManager;
+ private final DismissCallbackRegistry mDismissCallbackRegistry;
protected KeyguardHostView mKeyguardView;
protected ViewGroup mRoot;
private boolean mShowingSoon;
private int mBouncerPromptReason;
- private FalsingManager mFalsingManager;
- private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+ private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onStrongAuthStateChanged(int userId) {
@@ -67,15 +68,15 @@
};
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
- LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
- ViewGroup container) {
+ LockPatternUtils lockPatternUtils, ViewGroup container,
+ DismissCallbackRegistry dismissCallbackRegistry) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
- mWindowManager = windowManager;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
mFalsingManager = FalsingManager.getInstance(mContext);
+ mDismissCallbackRegistry = dismissCallbackRegistry;
}
public void show(boolean resetSecuritySelection) {
@@ -169,6 +170,9 @@
}
public void hide(boolean destroyView) {
+ if (isShowing()) {
+ mDismissCallbackRegistry.notifyDismissCancelled();
+ }
mFalsingManager.onBouncerHidden();
cancelShowRunnable();
if (mKeyguardView != null) {
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 784cb48..70beac8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -80,7 +80,7 @@
mClockYFractionMin = res.getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
mClockYFractionMax = res.getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
mMoreCardNotificationAmount =
- (float) res.getDimensionPixelSize(R.dimen.notification_summary_height) /
+ (float) res.getDimensionPixelSize(R.dimen.notification_shelf_height) /
res.getDimensionPixelSize(R.dimen.notification_min_height);
mDensity = res.getDisplayMetrics().density;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 9bb4936..695b500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -35,6 +35,8 @@
*/
public class LockIcon extends KeyguardAffordanceView {
+ private static final int FP_DRAW_OFF_TIMEOUT = 800;
+
private static final int STATE_LOCKED = 0;
private static final int STATE_LOCK_OPEN = 1;
private static final int STATE_FACE_UNLOCK = 2;
@@ -53,6 +55,8 @@
private boolean mHasFingerPrintIcon;
private int mDensity;
+ private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
+
public LockIcon(Context context, AttributeSet attrs) {
super(context, attrs);
mTrustDrawable = new TrustDrawable(context);
@@ -116,7 +120,6 @@
} else {
mTrustDrawable.stop();
}
- // TODO: Real icon for facelock.
int state = getState();
boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
boolean useAdditionalPadding = anyFingerprintIcon;
@@ -171,6 +174,14 @@
animation.forceAnimationOnUI();
animation.start();
}
+
+ if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
+ removeCallbacks(mDrawOffTimeout);
+ postDelayed(mDrawOffTimeout, FP_DRAW_OFF_TIMEOUT);
+ } else {
+ removeCallbacks(mDrawOffTimeout);
+ }
+
mLastState = state;
mLastDeviceInteractive = mDeviceInteractive;
mLastScreenOn = mScreenOn;
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 97df237..a0ea9bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -577,6 +577,7 @@
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
+ mDeadZone.setDisplayRotation(mCurrentRotation);
// force the low profile & disabled states into compliance
mBarTransitions.init();
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 cbaab14..d543f49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,16 +8,19 @@
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
import java.util.ArrayList;
+import java.util.function.Function;
/**
* A controller for the space in the status bar to the left of the system icons. This area is
@@ -32,13 +35,16 @@
private PhoneStatusBar mPhoneStatusBar;
protected View mNotificationIconArea;
- private IconMerger mNotificationIcons;
- private ImageView mMoreIcon;
+ private NotificationIconContainer mNotificationIcons;
+ private NotificationIconContainer mShelfIcons;
private final Rect mTintArea = new Rect();
+ private NotificationStackScrollLayout mNotificationScrollLayout;
+ private Context mContext;
public NotificationIconAreaController(Context context, PhoneStatusBar phoneStatusBar) {
mPhoneStatusBar = phoneStatusBar;
mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+ mContext = context;
initializeNotificationAreaViews(context);
}
@@ -55,29 +61,30 @@
LayoutInflater layoutInflater = LayoutInflater.from(context);
mNotificationIconArea = inflateIconArea(layoutInflater);
+ mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
+ R.id.notificationIcons);
- mNotificationIcons =
- (IconMerger) mNotificationIconArea.findViewById(R.id.notificationIcons);
+ NotificationShelf shelf = mPhoneStatusBar.getNotificationShelf();
+ mShelfIcons = shelf.getShelfIcons();
+ shelf.setCollapsedIcons(mNotificationIcons);
- mMoreIcon = (ImageView) mNotificationIconArea.findViewById(R.id.moreIcon);
- if (mMoreIcon != null) {
- mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
- mNotificationIcons.setOverflowIndicator(mMoreIcon);
- }
+ mNotificationScrollLayout = mPhoneStatusBar.getNotificationScrollLayout();
}
public void onDensityOrFontScaleChanged(Context context) {
reloadDimens(context);
- final LinearLayout.LayoutParams params = generateIconLayoutParams();
+ final FrameLayout.LayoutParams params = generateIconLayoutParams();
for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
View child = mNotificationIcons.getChildAt(i);
child.setLayoutParams(params);
+ child = mShelfIcons.getChildAt(i);
+ child.setLayoutParams(params);
}
}
@NonNull
- private LinearLayout.LayoutParams generateIconLayoutParams() {
- return new LinearLayout.LayoutParams(
+ private FrameLayout.LayoutParams generateIconLayoutParams() {
+ return new FrameLayout.LayoutParams(
mIconSize + 2 * mIconHPadding, getHeight());
}
@@ -109,14 +116,10 @@
}
/**
- * Sets the color that should be used to tint any icons in the notification area. If this
- * method is not called, the default tint is {@link Color#WHITE}.
+ * Sets the color that should be used to tint any icons in the notification area.
*/
public void setIconTint(int iconTint) {
mIconTint = iconTint;
- if (mMoreIcon != null) {
- mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
- }
applyNotificationIconsTint();
}
@@ -144,24 +147,54 @@
* Updates the notifications with the given list of notifications to display.
*/
public void updateNotificationIcons(NotificationData notificationData) {
- final LinearLayout.LayoutParams params = generateIconLayoutParams();
- ArrayList<NotificationData.Entry> activeNotifications =
- notificationData.getActiveNotifications();
- final int size = activeNotifications.size();
- ArrayList<StatusBarIconView> toShow = new ArrayList<>(size);
+ updateIconsForLayout(notificationData, entry -> entry.icon, mNotificationIcons);
+ updateIconsForLayout(notificationData, entry -> entry.expandedIcon, mShelfIcons);
+
+ applyNotificationIconsTint();
+ ArrayList<NotificationData.Entry> activeNotifications
+ = notificationData.getActiveNotifications();
+ for (int i = 0; i < activeNotifications.size(); i++) {
+ NotificationData.Entry entry = activeNotifications.get(i);
+ boolean isPreL = Boolean.TRUE.equals(entry.expandedIcon.getTag(R.id.icon_is_pre_L));
+ boolean colorize = !isPreL
+ || NotificationUtils.isGrayscale(entry.expandedIcon, mNotificationColorUtil);
+ if (colorize) {
+ int color = entry.getContrastedColor(mContext);
+ entry.expandedIcon.setImageTintList(ColorStateList.valueOf(color));
+ }
+ }
+ }
+
+ /**
+ * Updates the notification icons for a host layout. This will ensure that the notification
+ * host layout will have the same icons like the ones in here.
+ *
+ * @param notificationData the notification data to look up which notifications are relevant
+ * @param function A function to look up an icon view based on an entry
+ * @param hostLayout which layout should be updated
+ */
+ private void updateIconsForLayout(NotificationData notificationData,
+ Function<NotificationData.Entry, StatusBarIconView> function,
+ NotificationIconContainer hostLayout) {
+ ArrayList<StatusBarIconView> toShow = new ArrayList<>(
+ mNotificationScrollLayout.getChildCount());
// Filter out ambient notifications and notification children.
- for (int i = 0; i < size; i++) {
- NotificationData.Entry ent = activeNotifications.get(i);
- if (shouldShowNotification(ent, notificationData)) {
- toShow.add(ent.icon);
+ for (int i = 0; i < mNotificationScrollLayout.getChildCount(); i++) {
+ View view = mNotificationScrollLayout.getChildAt(i);
+ if (view instanceof ExpandableNotificationRow) {
+ NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
+ if (shouldShowNotification(ent, notificationData)) {
+ toShow.add(function.apply(ent));
+ }
}
}
+
ArrayList<View> toRemove = new ArrayList<>();
- for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
- View child = mNotificationIcons.getChildAt(i);
+ for (int i = 0; i < hostLayout.getChildCount(); i++) {
+ View child = hostLayout.getChildAt(i);
if (!toShow.contains(child)) {
toRemove.add(child);
}
@@ -169,29 +202,32 @@
final int toRemoveCount = toRemove.size();
for (int i = 0; i < toRemoveCount; i++) {
- mNotificationIcons.removeView(toRemove.get(i));
+ hostLayout.removeView(toRemove.get(i));
}
+ final FrameLayout.LayoutParams params = generateIconLayoutParams();
for (int i = 0; i < toShow.size(); i++) {
View v = toShow.get(i);
+ // The view might still be transiently added if it was just removed and added again
+ hostLayout.removeTransientView(v);
if (v.getParent() == null) {
- mNotificationIcons.addView(v, i, params);
+ hostLayout.addView(v, i, params);
}
}
+ hostLayout.setChangingViewPositions(true);
// Re-sort notification icons
- final int childCount = mNotificationIcons.getChildCount();
+ final int childCount = hostLayout.getChildCount();
for (int i = 0; i < childCount; i++) {
- View actual = mNotificationIcons.getChildAt(i);
+ View actual = hostLayout.getChildAt(i);
StatusBarIconView expected = toShow.get(i);
if (actual == expected) {
continue;
}
- mNotificationIcons.removeView(expected);
- mNotificationIcons.addView(expected, i);
+ hostLayout.removeView(expected);
+ hostLayout.addView(expected, i);
}
-
- applyNotificationIconsTint();
+ hostLayout.setChangingViewPositions(false);
}
/**
@@ -206,6 +242,7 @@
v.setImageTintList(ColorStateList.valueOf(
StatusBarIconController.getTint(mTintArea, v, mIconTint)));
}
+ v.setIconTint(mIconTint);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
new file mode 100644
index 0000000..03697b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -0,0 +1,341 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.stack.AnimationFilter;
+import com.android.systemui.statusbar.stack.AnimationProperties;
+import com.android.systemui.statusbar.stack.ViewState;
+
+import java.util.WeakHashMap;
+
+/**
+ * A container for notification icons. It handles overflowing icons properly and positions them
+ * correctly on the screen.
+ */
+public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
+ private static final String TAG = "NotificationIconContainer";
+ private static final boolean DEBUG = false;
+ private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateX();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(200);
+
+ private static final AnimationProperties ADD_ICON_PROPERTIES = new AnimationProperties() {
+ private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
+
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ }.setDuration(200).setDelay(50);
+
+ private boolean mShowAllIcons = true;
+ private WeakHashMap<View, IconState> mIconStates = new WeakHashMap<>();
+ private int mDotPadding;
+ private int mStaticDotRadius;
+ private int mActualLayoutWidth = -1;
+ private float mActualPaddingEnd = -1;
+ private float mActualPaddingStart = -1;
+ private boolean mChangingViewPositions;
+ private int mAnimationStartIndex = -1;
+
+ public NotificationIconContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initDimens();
+ setWillNotDraw(!DEBUG);
+ }
+
+ private void initDimens() {
+ mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);
+ mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ Paint paint = new Paint();
+ paint.setColor(Color.RED);
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ initDimens();
+ }
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ float centerY = getHeight() / 2.0f;
+ // we layout all our children on the left at the top
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ // We need to layout all children even the GONE ones, such that the heights are
+ // calculated correctly as they are used to calculate how many we can fit on the screen
+ int width = child.getMeasuredWidth();
+ int height = child.getMeasuredHeight();
+ int top = (int) (centerY - height / 2.0f);
+ child.layout(0, top, width, top + height);
+ }
+ if (mShowAllIcons) {
+ resetViewStates();
+ calculateIconTranslations();
+ applyIconStates();
+ }
+ }
+
+ public void applyIconStates() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ ViewState childState = mIconStates.get(child);
+ if (childState != null) {
+ childState.applyToView(child);
+ }
+ }
+ mAnimationStartIndex = -1;
+ }
+
+ @Override
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+ if (!mChangingViewPositions) {
+ mIconStates.put(child, new IconState());
+ }
+ int childIndex = indexOfChild(child);
+ if (childIndex < getChildCount() - 1
+ && mIconStates.get(getChildAt(childIndex + 1)).iconAppearAmount > 0.0f) {
+ if (mAnimationStartIndex < 0) {
+ mAnimationStartIndex = childIndex;
+ } else {
+ mAnimationStartIndex = Math.min(mAnimationStartIndex, childIndex);
+ }
+ }
+ }
+
+ @Override
+ public void onViewRemoved(View child) {
+ super.onViewRemoved(child);
+ if (child instanceof StatusBarIconView) {
+ final StatusBarIconView icon = (StatusBarIconView) child;
+ if (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+ && child.getVisibility() == VISIBLE) {
+ int animationStartIndex = findFirstViewIndexAfter(icon.getTranslationX());
+ if (mAnimationStartIndex < 0) {
+ mAnimationStartIndex = animationStartIndex;
+ } else {
+ mAnimationStartIndex = Math.min(mAnimationStartIndex, animationStartIndex);
+ }
+ }
+ if (!mChangingViewPositions) {
+ mIconStates.remove(child);
+ addTransientView(icon, 0);
+ icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, true /* animate */,
+ () -> removeTransientView(icon));
+ }
+ }
+ }
+
+ /**
+ * Finds the first view with a translation bigger then a given value
+ */
+ private int findFirstViewIndexAfter(float translationX) {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view.getTranslationX() > translationX) {
+ return i;
+ }
+ }
+ return getChildCount();
+ }
+
+ public WeakHashMap<View, IconState> resetViewStates() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ ViewState iconState = mIconStates.get(view);
+ iconState.initFrom(view);
+ iconState.alpha = 1.0f;
+ }
+ return mIconStates;
+ }
+
+ /**
+ * Calulate the horizontal translations for each notification based on how much the icons
+ * are inserted into the notification container.
+ * If this is not a whole number, the fraction means by how much the icon is appearing.
+ */
+ public void calculateIconTranslations() {
+ float translationX = getActualPaddingStart();
+ int overflowingIconIndex = -1;
+ int lastTwoIconWidth = 0;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation = translationX;
+ iconState.visibleState = StatusBarIconView.STATE_ICON;
+ translationX += iconState.iconAppearAmount * view.getWidth();
+ if (translationX > getLayoutEnd()) {
+ // we are overflowing it with this icon
+ overflowingIconIndex = i - 1;
+ lastTwoIconWidth = view.getWidth();
+ break;
+ }
+ }
+ if (overflowingIconIndex != -1) {
+ int numDots = 1;
+ View overflowIcon = getChildAt(overflowingIconIndex);
+ IconState overflowState = mIconStates.get(overflowIcon);
+ lastTwoIconWidth += overflowIcon.getWidth();
+ int dotWidth = mStaticDotRadius * 2 + mDotPadding;
+ int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding;
+ translationX = (getLayoutEnd() - lastTwoIconWidth / 2 - totalDotLength / 2)
+ - overflowIcon.getWidth() * 0.3f + mStaticDotRadius;
+ float overflowStart = getLayoutEnd() - lastTwoIconWidth;
+ float overlapAmount = (overflowState.xTranslation - overflowStart)
+ / overflowIcon.getWidth();
+ translationX += overlapAmount * dotWidth;
+ for (int i = overflowingIconIndex; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation = translationX;
+ if (numDots <= 3) {
+ iconState.visibleState = StatusBarIconView.STATE_DOT;
+ translationX += numDots == 3 ? 3 * dotWidth : dotWidth;
+ } else {
+ iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
+ }
+ numDots++;
+ }
+ }
+ if (isLayoutRtl()) {
+ for (int i = 0; i < childCount; i++) {
+ View view = getChildAt(i);
+ IconState iconState = mIconStates.get(view);
+ iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
+ }
+ }
+ }
+
+ private float getLayoutEnd() {
+ return getActualWidth() - getActualPaddingEnd();
+ }
+
+ private float getActualPaddingEnd() {
+ if (mActualPaddingEnd < 0) {
+ return getPaddingEnd();
+ }
+ return mActualPaddingEnd;
+ }
+
+ private float getActualPaddingStart() {
+ if (mActualPaddingStart < 0) {
+ return getPaddingStart();
+ }
+ return mActualPaddingStart;
+ }
+
+ /**
+ * Sets whether the layout should always show all icons.
+ * If this is true, the icon positions will be updated on layout.
+ * If this if false, the layout is managed from the outside and layouting won't trigger a
+ * repositioning of the icons.
+ */
+ public void setShowAllIcons(boolean showAllIcons) {
+ mShowAllIcons = showAllIcons;
+ }
+
+ public void setActualLayoutWidth(int actualLayoutWidth) {
+ mActualLayoutWidth = actualLayoutWidth;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public void setActualPaddingEnd(float paddingEnd) {
+ mActualPaddingEnd = paddingEnd;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public void setActualPaddingStart(float paddingStart) {
+ mActualPaddingStart = paddingStart;
+ if (DEBUG) {
+ invalidate();
+ }
+ }
+
+ public int getActualWidth() {
+ if (mActualLayoutWidth < 0) {
+ return getWidth();
+ }
+ return mActualLayoutWidth;
+ }
+
+ public void setChangingViewPositions(boolean changingViewPositions) {
+ mChangingViewPositions = changingViewPositions;
+ }
+
+ public class IconState extends ViewState {
+ public float iconAppearAmount = 1.0f;
+ public int visibleState;
+ public boolean justAdded = true;
+
+ @Override
+ public void applyToView(View view) {
+ if (view instanceof StatusBarIconView) {
+ StatusBarIconView icon = (StatusBarIconView) view;
+ AnimationProperties animationProperties = DOT_ANIMATION_PROPERTIES;
+ if (justAdded) {
+ super.applyToView(icon);
+ icon.setAlpha(0.0f);
+ icon.setVisibleState(StatusBarIconView.STATE_HIDDEN, false /* animate */);
+ animationProperties = ADD_ICON_PROPERTIES;
+ }
+ boolean animate = visibleState != icon.getVisibleState() || justAdded;
+ if (!animate && mAnimationStartIndex >= 0
+ && (icon.getVisibleState() != StatusBarIconView.STATE_HIDDEN
+ || visibleState != StatusBarIconView.STATE_HIDDEN)) {
+ int viewIndex = indexOfChild(view);
+ animate = viewIndex >= mAnimationStartIndex;
+ }
+ icon.setVisibleState(visibleState);
+ if (animate) {
+ animateTo(icon, animationProperties);
+ } else {
+ super.applyToView(view);
+ }
+ }
+ justAdded = 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 068631d..99e98f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -202,11 +202,12 @@
private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
@Override
public void run() {
- mHeadsUpAnimatingAway = false;
+ setHeadsUpAnimatingAway(false);
notifyBarPanelExpansionChanged();
}
};
private NotificationGroupManager mGroupManager;
+ private boolean mOpening;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -403,11 +404,9 @@
mKeyguardStatusView.getHeight());
int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
R.dimen.notification_divider_height));
- final int overflowheight = getResources().getDimensionPixelSize(
- R.dimen.notification_summary_height);
- float bottomStackSize = mNotificationStackScroller.getKeyguardBottomStackSize();
- float availableSpace = mNotificationStackScroller.getHeight() - minPadding - overflowheight
- - bottomStackSize;
+ float shelfSize = mNotificationStackScroller.getNotificationShelf().getIntrinsicHeight()
+ + notificationPadding;
+ float availableSpace = mNotificationStackScroller.getHeight() - minPadding - shelfSize;
int count = 0;
for (int i = 0; i < mNotificationStackScroller.getChildCount(); i++) {
ExpandableView child = (ExpandableView) mNotificationStackScroller.getChildAt(i);
@@ -429,6 +428,16 @@
availableSpace -= child.getMinHeight() + notificationPadding;
if (availableSpace >= 0 && count < maximum) {
count++;
+ } else if (availableSpace > -shelfSize) {
+ // if we are exactly the last view, then we can show us still!
+ for (int j = i + 1; j < mNotificationStackScroller.getChildCount(); j++) {
+ if (mNotificationStackScroller.getChildAt(j)
+ instanceof ExpandableNotificationRow) {
+ return count;
+ }
+ }
+ count++;
+ return count;
} else {
return count;
}
@@ -546,9 +555,7 @@
protected void flingToHeight(float vel, boolean expand, float target,
float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
mHeadsUpTouchHelper.notifyFling(!expand);
- setClosingWithAlphaFadeout(!expand
- && mNotificationStackScroller.getFirstChildIntrinsicHeight() <= mMaxFadeoutHeight
- && getFadeoutAlpha() == 1.0f);
+ setClosingWithAlphaFadeout(!expand && getFadeoutAlpha() == 1.0f);
super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
@@ -723,6 +730,11 @@
}
@Override
+ protected float getOpeningHeight() {
+ return mNotificationStackScroller.getMinExpansionHeight();
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
return false;
@@ -1415,7 +1427,7 @@
if (mKeyguardShowing) {
// On Keyguard, interpolate the QS expansion linearly to the panel expansion
- t = expandedHeight / getMaxPanelHeight();
+ t = expandedHeight / (getMaxPanelHeight());
} else {
// In Shade, interpolate linearly such that QS is closed whenever panel height is
@@ -1475,9 +1487,7 @@
// and expanding/collapsing the whole panel from/to quick settings.
if (mNotificationStackScroller.getNotGoneChildCount() == 0
&& mShadeEmpty) {
- notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
- + mNotificationStackScroller.getBottomStackPeekSize()
- + mNotificationStackScroller.getBottomStackSlowDownHeight();
+ notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -1508,8 +1518,7 @@
private float getFadeoutAlpha() {
float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
- / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
- - mNotificationStackScroller.getBottomStackSlowDownHeight());
+ / mQsMinExpansionHeight;
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
return alpha;
@@ -1988,9 +1997,9 @@
@Override
protected float getCannedFlingDurationFactor() {
if (mQsExpanded) {
- return 0.7f;
+ return 0.9f;
} else {
- return 0.6f;
+ return 0.8f;
}
}
@@ -2180,16 +2189,22 @@
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
+ mNotificationStackScroller.setInHeadsUpPinnedMode(inPinnedMode);
if (inPinnedMode) {
mHeadsUpExistenceChangedRunnable.run();
updateNotificationTranslucency();
} else {
- mHeadsUpAnimatingAway = true;
+ setHeadsUpAnimatingAway(true);
mNotificationStackScroller.runAfterAnimationFinished(
mHeadsUpExistenceChangedRunnable);
}
}
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ mHeadsUpAnimatingAway = headsUpAnimatingAway;
+ mNotificationStackScroller.setHeadsUpAnimatingAway(headsUpAnimatingAway);
+ }
+
@Override
public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
mNotificationStackScroller.generateHeadsUpAnimation(headsUp, true);
@@ -2265,6 +2280,14 @@
protected void updateExpandedHeight(float expandedHeight) {
mNotificationStackScroller.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
+ setOpening(expandedHeight <= getOpeningHeight());
+ }
+
+ private void setOpening(boolean opening) {
+ if (opening != mOpening) {
+ mOpening = opening;
+ mStatusBar.recomputeDisableFlags(false);
+ }
}
public void setPanelScrimMinFraction(float minFraction) {
@@ -2316,7 +2339,18 @@
@Override
public void setAlpha(float alpha) {
super.setAlpha(alpha);
- mNotificationStackScroller.setParentFadingOut(alpha != 1.0f);
+ updateFullyVisibleState();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ updateFullyVisibleState();
+ }
+
+ private void updateFullyVisibleState() {
+ mNotificationStackScroller.setParentNotFullyVisible(getAlpha() != 1.0f
+ || getVisibility() != VISIBLE);
}
/**
@@ -2358,6 +2392,15 @@
mGroupManager = groupManager;
}
+ public boolean shouldHideNotificationIcons() {
+ return !mOpening && !isFullyCollapsed();
+ }
+
+ public boolean shouldAnimateIconHiding() {
+ // TODO: handle this correctly, not completely working yet
+ return mNotificationStackScroller.getTranslationX() != 0;
+ }
+
private final FragmentListener mFragmentListener = new FragmentListener() {
@Override
public void onFragmentViewCreated(String tag, Fragment fragment) {
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 f2c57e5..87a3848 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -118,7 +118,7 @@
boolean fullyOpened = false;
if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
PanelView pv = mPanel;
- pv.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
+ pv.setVisibility(expanded ? 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 3de03b5..f16c834 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -50,6 +51,10 @@
public abstract class PanelView extends FrameLayout {
public static final boolean DEBUG = PanelBar.DEBUG;
public static final String TAG = PanelView.class.getSimpleName();
+ private static final int INITIAL_OPENING_PEEK_DURATION = 200;
+ private static final int PEEK_ANIMATION_DURATION = 360;
+ private long mDownTime;
+ private float mMinExpandHeight;
private final void logf(String fmt, Object... args) {
Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
@@ -88,6 +93,7 @@
private ObjectAnimator mPeekAnimator;
private VelocityTrackerInterface mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private FlingAnimationUtils mFlingAnimationUtilsClosing;
private FalsingManager mFalsingManager;
/**
@@ -106,9 +112,6 @@
private Interpolator mBounceInterpolator;
protected KeyguardBottomAreaView mKeyguardBottomArea;
- private boolean mPeekPending;
- private boolean mCollapseAfterPeek;
-
/**
* Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
*/
@@ -118,13 +121,6 @@
private boolean mGestureWaitForTouchSlop;
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
- private Runnable mPeekRunnable = new Runnable() {
- @Override
- public void run() {
- mPeekPending = false;
- runPeekAnimation();
- }
- };
protected void onExpandingFinished() {
mBar.onExpandingFinished();
@@ -148,21 +144,17 @@
}
}
- private void schedulePeek() {
- mPeekPending = true;
- long timeout = ViewConfiguration.getTapTimeout();
- postOnAnimationDelayed(mPeekRunnable, timeout);
- notifyBarPanelExpansionChanged();
- }
-
- private void runPeekAnimation() {
- mPeekHeight = getPeekHeight();
+ private void runPeekAnimation(long duration, float peekHeight, boolean collapseWhenFinished) {
+ mPeekHeight = peekHeight;
if (DEBUG) logf("peek to height=%.1f", mPeekHeight);
if (mHeightAnimator != null) {
return;
}
+ if (mPeekAnimator != null) {
+ mPeekAnimator.cancel();
+ }
mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
- .setDuration(250);
+ .setDuration(duration);
mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mPeekAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -175,10 +167,10 @@
@Override
public void onAnimationEnd(Animator animation) {
mPeekAnimator = null;
- if (mCollapseAfterPeek && !mCancelled) {
+ if (!mCancelled && collapseWhenFinished) {
postOnAnimation(mPostCollapseRunnable);
}
- mCollapseAfterPeek = false;
+
}
});
notifyExpandingStarted();
@@ -189,6 +181,7 @@
public PanelView(Context context, AttributeSet attrs) {
super(context, attrs);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
+ mFlingAnimationUtilsClosing = new FlingAnimationUtils(context, 0.4f);
mBounceInterpolator = new BounceInterpolator();
mFalsingManager = FalsingManager.getInstance(context);
}
@@ -267,11 +260,13 @@
case MotionEvent.ACTION_DOWN:
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mJustPeeked = false;
+ mMinExpandHeight = 0.0f;
mPanelClosedOnDown = isFullyCollapsed();
mHasLayoutedSinceDown = false;
mUpdateFlingOnLayout = false;
mMotionAborted = false;
mPeekTouching = mPanelClosedOnDown;
+ mDownTime = SystemClock.uptimeMillis();
mTouchAboveFalsingThreshold = false;
mCollapsedAndHeadsUpOnDown = isFullyCollapsed()
&& mHeadsUpManager.hasPinnedHeadsUp();
@@ -279,16 +274,16 @@
initVelocityTracker();
}
trackMovement(event);
- if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) ||
- mPeekPending || mPeekAnimator != null) {
+ if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning)
+ || mPeekAnimator != null) {
cancelHeightAnimator();
cancelPeek();
mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning)
- || mPeekPending || mPeekAnimator != null;
+ || mPeekAnimator != null;
onTrackingStarted();
}
if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()) {
- schedulePeek();
+ startOpening();
}
break;
@@ -317,7 +312,7 @@
// y-component of the gesture, as we have no conflicting horizontal gesture.
if (Math.abs(h) > mTouchSlop
&& (Math.abs(h) > Math.abs(x - mInitialTouchX)
- || mIgnoreXTouchSlop)) {
+ || mIgnoreXTouchSlop)) {
mTouchSlopExceeded = true;
if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
@@ -325,23 +320,30 @@
h = 0;
}
cancelHeightAnimator();
- removeCallbacks(mPeekRunnable);
- mPeekPending = false;
onTrackingStarted();
}
}
- final float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
+ float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
if (newHeight > mPeekHeight) {
if (mPeekAnimator != null) {
mPeekAnimator.cancel();
}
mJustPeeked = false;
+ } else if (mPeekAnimator == null && mJustPeeked) {
+ // The initial peek has finished, but we haven't dragged as far yet, lets
+ // speed it up by starting at the peek height.
+ mInitialOffsetOnTouch = mExpandedHeight;
+ mInitialTouchY = y;
+ mMinExpandHeight = mExpandedHeight;
+ mJustPeeked = false;
}
+ newHeight = Math.max(newHeight, mMinExpandHeight);
if (-h >= getFalsingThreshold()) {
mTouchAboveFalsingThreshold = true;
mUpwardsWhenTresholdReached = isDirectionUpwards(x, y);
}
- if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+ if (!mJustPeeked && (!mGestureWaitForTouchSlop || mTracking) &&
+ !isTrackingBlocked()) {
setExpandedHeightInternal(newHeight);
}
@@ -357,6 +359,14 @@
return !mGestureWaitForTouchSlop || mTracking;
}
+ private void startOpening() {;
+ runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(),
+ false /* collapseWhenFinished */);
+ notifyBarPanelExpansionChanged();
+ }
+
+ protected abstract float getOpeningHeight();
+
/**
* @return whether the swiping direction is upwards and above a 45 degree angle compared to the
* horizontal direction
@@ -418,6 +428,15 @@
if (mUpdateFlingOnLayout) {
mUpdateFlingVelocity = vel;
}
+ } else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking) {
+ long timePassed = SystemClock.uptimeMillis() - mDownTime;
+ if (timePassed < ViewConfiguration.getLongPressTimeout()) {
+ // Lets show the user that he can actually expand the panel
+ runPeekAnimation(PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
+ } else {
+ // We need to collapse the panel since we peeked to the small height.
+ postOnAnimation(mPostCollapseRunnable);
+ }
} else {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
@@ -448,7 +467,6 @@
protected void onTrackingStarted() {
endClosing();
mTracking = true;
- mCollapseAfterPeek = false;
mBar.onTrackingStarted();
notifyExpandingStarted();
notifyBarPanelExpansionChanged();
@@ -482,7 +500,10 @@
case MotionEvent.ACTION_DOWN:
mStatusBar.userActivity();
mAnimatingOnDown = mHeightAnimator != null;
- if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) {
+ mMinExpandHeight = 0.0f;
+ mDownTime = SystemClock.uptimeMillis();
+ if (mAnimatingOnDown && mClosing && !mHintAnimationRunning
+ || mPeekAnimator != null) {
cancelHeightAnimator();
cancelPeek();
mTouchSlopExceeded = true;
@@ -639,7 +660,7 @@
protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
boolean expandBecauseOfFalsing) {
cancelPeek();
- float target = expand ? getMaxPanelHeight() : 0.0f;
+ float target = expand ? getMaxPanelHeight() : 0;
if (!expand) {
mClosing = true;
}
@@ -672,8 +693,7 @@
animator.setDuration(350);
}
} else {
- mFlingAnimationUtils.applyDismissing(animator, mExpandedHeight, target, vel,
- getHeight());
+ mFlingAnimationUtilsClosing.apply(animator, mExpandedHeight, target, vel, getHeight());
// Make it shorter if we run a canned animation
if (vel == 0) {
@@ -742,7 +762,6 @@
&& mHeightAnimator == null
&& !isFullyCollapsed()
&& currentMaxPanelHeight != mExpandedHeight
- && !mPeekPending
&& mPeekAnimator == null
&& !mPeekTouching) {
setExpandedHeight(currentMaxPanelHeight);
@@ -769,10 +788,8 @@
}
}
- mExpandedHeight = Math.max(0, mExpandedHeight);
- mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
- ? 0
- : mExpandedHeight / fhWithoutOverExpansion);
+ mExpandedFraction = Math.min(1f,
+ fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
onHeightUpdated(mExpandedHeight);
notifyBarPanelExpansionChanged();
}
@@ -816,7 +833,7 @@
}
public boolean isFullyCollapsed() {
- return mExpandedHeight <= 0;
+ return mExpandedFraction <= 0.0f;
}
public boolean isCollapsing() {
@@ -833,16 +850,7 @@
public void collapse(boolean delayed, float speedUpFactor) {
if (DEBUG) logf("collapse: " + this);
- if (mPeekPending || mPeekAnimator != null) {
- mCollapseAfterPeek = true;
- if (mPeekPending) {
-
- // We know that the whole gesture is just a peek triggered by a simple click, so
- // better start it now.
- removeCallbacks(mPeekRunnable);
- mPeekRunnable.run();
- }
- } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
+ if (!isFullyCollapsed() && !mTracking && !mClosing) {
cancelHeightAnimator();
notifyExpandingStarted();
@@ -866,13 +874,11 @@
};
public void cancelPeek() {
- boolean cancelled = mPeekPending;
+ boolean cancelled = false;
if (mPeekAnimator != null) {
cancelled = true;
mPeekAnimator.cancel();
}
- removeCallbacks(mPeekRunnable);
- mPeekPending = false;
if (cancelled) {
// When peeking, we already tell mBar that we expanded ourselves. Make sure that we also
@@ -1000,14 +1006,14 @@
});
animator.start();
mHeightAnimator = animator;
- mKeyguardBottomArea.getIndicationView().animate()
+ mKeyguardBottomArea.getIndicationArea().animate()
.translationY(-mHintDistance)
.setDuration(250)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
- mKeyguardBottomArea.getIndicationView().animate()
+ mKeyguardBottomArea.getIndicationArea().animate()
.translationY(0)
.setDuration(450)
.setInterpolator(mBounceInterpolator)
@@ -1048,7 +1054,7 @@
}
protected void notifyBarPanelExpansionChanged() {
- mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f || mPeekPending
+ mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
|| mPeekAnimator != null || mInstantExpanding || isPanelVisibleBecauseOfHeadsUp()
|| mTracking || mHeightAnimator != null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 6f13ba5..2b74c84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -164,7 +164,7 @@
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
-import com.android.systemui.statusbar.NotificationOverflowContainer;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
@@ -197,7 +197,7 @@
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout
.OnChildLocationsChangedListener;
import com.android.systemui.statusbar.stack.StackStateAnimator;
-import com.android.systemui.statusbar.stack.StackViewState;
+import com.android.systemui.statusbar.stack.ExpandableViewState;
import com.android.systemui.volume.VolumeComponent;
import java.io.FileDescriptor;
@@ -569,8 +569,8 @@
*/
protected boolean mStartedGoingToSleep;
- private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_HUN
- | StackViewState.LOCATION_MAIN_AREA;
+ private static final int VISIBLE_LOCATIONS = ExpandableViewState.LOCATION_FIRST_HUN
+ | ExpandableViewState.LOCATION_MAIN_AREA;
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {
@@ -659,10 +659,12 @@
array.clear();
}
- private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
+ private final View.OnClickListener mShelfClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
- goToLockedShade(null);
+ if (mState == StatusBarState.KEYGUARD) {
+ goToLockedShade(null);
+ }
}
};
private HashMap<ExpandableNotificationRow, List<ExpandableNotificationRow>> mTmpChildOrderMap
@@ -812,7 +814,7 @@
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setOnGroupChangeListener(mStackScroller);
- inflateOverflowContainer();
+ inflateShelf();
inflateEmptyShadeView();
inflateDismissView();
mExpandedContents = mStackScroller;
@@ -855,8 +857,7 @@
mKeyguardBottomArea.setActivityStarter(this);
mKeyguardBottomArea.setAssistManager(mAssistManager);
mKeyguardIndicationController = new KeyguardIndicationController(mContext,
- (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
- R.id.keyguard_indication_text),
+ (ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
mKeyguardBottomArea.getLockIcon());
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
@@ -1049,13 +1050,13 @@
return new BatteryControllerImpl(mContext);
}
- private void inflateOverflowContainer() {
- mKeyguardIconOverflowContainer =
- (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
- mKeyguardIconOverflowContainer.setOnActivatedListener(this);
- mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
- mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
+ private void inflateShelf() {
+ mNotificationShelf =
+ (NotificationShelf) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_notification_shelf, mStackScroller, false);
+ mNotificationShelf.setOnActivatedListener(this);
+ mNotificationShelf.setOnClickListener(mShelfClickListener);
+ mStackScroller.setShelf(mNotificationShelf);
}
@Override
@@ -1072,7 +1073,6 @@
updateClearAll();
inflateEmptyShadeView();
updateEmptyShadeView();
- inflateOverflowContainer();
mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
mUserInfoController.onDensityOrFontScaleChanged();
if (mUserSwitcherController != null) {
@@ -1866,12 +1866,15 @@
mTmpChildOrderMap.clear();
updateRowStates();
- updateSpeedbump();
+ updateSpeedBumpIndex();
updateClearAll();
updateEmptyShadeView();
updateQsExpansionEnabled();
mShadeUpdates.check();
+
+ // Let's also update the icons
+ mIconController.updateNotificationIcons(mNotificationData);
}
/**
@@ -1987,8 +1990,8 @@
mNotificationPanel.setShadeEmpty(showEmptyShade);
}
- private void updateSpeedbump() {
- int speedbumpIndex = -1;
+ private void updateSpeedBumpIndex() {
+ int speedBumpIndex = -1;
int currentIndex = 0;
final int N = mStackScroller.getChildCount();
for (int i = 0; i < N; i++) {
@@ -1998,12 +2001,17 @@
}
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
- speedbumpIndex = currentIndex;
+ speedBumpIndex = currentIndex;
break;
}
currentIndex++;
}
- mStackScroller.updateSpeedBumpIndex(speedbumpIndex);
+ boolean noAmbient = false;
+ if (speedBumpIndex == -1) {
+ speedBumpIndex = currentIndex;
+ noAmbient = true;
+ }
+ mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
}
public static boolean isTopLevelChild(Entry entry) {
@@ -2015,7 +2023,6 @@
mNotificationData.filterAndSort();
updateNotificationShade();
- mIconController.updateNotificationIcons(mNotificationData);
}
public void requestNotificationUpdate() {
@@ -2375,8 +2382,7 @@
}
protected int adjustDisableFlags(int state) {
- if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway
- && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
+ if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && shouldHideNotificationIcons()) {
state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
state |= StatusBarManager.DISABLE_SYSTEM_INFO;
}
@@ -2391,6 +2397,10 @@
return state;
}
+ private boolean shouldHideNotificationIcons() {
+ return mExpandedVisible && mNotificationPanel.shouldHideNotificationIcons();
+ }
+
/**
* State is one or more of the DISABLE constants from StatusBarManager.
*/
@@ -2497,7 +2507,7 @@
*
* This needs to be called if state used by {@link #adjustDisableFlags} changes.
*/
- private void recomputeDisableFlags(boolean animate) {
+ public void recomputeDisableFlags(boolean animate) {
disable(mDisabledUnmodified1, mDisabledUnmodified2, animate);
}
@@ -2694,6 +2704,14 @@
mFalsingManager.onScreenOff();
}
+ public NotificationShelf getNotificationShelf() {
+ return mNotificationShelf;
+ }
+
+ public NotificationStackScrollLayout getNotificationScrollLayout() {
+ return mStackScroller;
+ }
+
public boolean isPulsing() {
return mDozeScrimController.isPulsing();
}
@@ -2935,7 +2953,7 @@
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
showBouncer();
- recomputeDisableFlags(true /* animate */);
+ recomputeDisableFlags(shouldAnimatIconHiding() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -2944,6 +2962,10 @@
}
}
+ private boolean shouldAnimatIconHiding() {
+ return mNotificationPanel.shouldAnimateIconHiding();
+ }
+
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -4153,7 +4175,7 @@
mScrimController.forceHideScrims(true /* hide */);
updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
- mStackScroller.setParentFadingOut(true);
+ mStackScroller.setParentNotFullyVisible(true);
mNotificationPanel.animate()
.alpha(0)
.setStartDelay(FADE_KEYGUARD_START_DELAY)
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 a4b76ebb..0e74e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -21,7 +21,6 @@
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Color;
import android.graphics.Rect;
import android.support.v4.graphics.ColorUtils;
import android.view.View;
@@ -37,7 +36,7 @@
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
+import com.android.systemui.statusbar.stack.ViewState;
/**
* Controls both the scrim behind the notifications and in front of the notifications (when a
@@ -79,7 +78,7 @@
private boolean mWakeAndUnlocking;
protected boolean mAnimateChange;
private boolean mUpdatePending;
- private boolean mExpanding;
+ private boolean mTracking;
private boolean mAnimateKeyguardFadingOut;
protected long mDurationOverride = -1;
private long mAnimationDelay;
@@ -123,12 +122,12 @@
}
public void onTrackingStarted() {
- mExpanding = true;
+ mTracking = true;
mDarkenWhileDragging = !mUnlockMethodCache.canSkipBouncer();
}
public void onExpandingFinished() {
- mExpanding = false;
+ mTracking = false;
}
public void setPanelExpansion(float fraction) {
@@ -138,7 +137,7 @@
if (mPinnedHeadsUpCount != 0) {
updateHeadsUpScrim(false);
}
- if (mKeyguardFadeoutAnimation != null) {
+ if (mKeyguardFadeoutAnimation != null && mTracking) {
mKeyguardFadeoutAnimation.cancel();
}
}
@@ -146,7 +145,7 @@
public void setBouncerShowing(boolean showing) {
mBouncerShowing = showing;
- mAnimateChange = !mExpanding && !mDontAnimateBouncerChanges;
+ mAnimateChange = !mTracking && !mDontAnimateBouncerChanges;
scheduleUpdate();
}
@@ -269,7 +268,7 @@
}
private void updateScrimKeyguard() {
- if (mExpanding && mDarkenWhileDragging) {
+ if (mTracking && mDarkenWhileDragging) {
float behindFraction = Math.max(0, Math.min(mFraction, 1));
float fraction = 1 - behindFraction;
fraction = (float) Math.pow(fraction, 0.8f);
@@ -278,7 +277,7 @@
setScrimBehindColor(behindFraction * mScrimBehindAlphaKeyguard);
} else if (mBouncerShowing && !mBouncerIsKeyguard) {
setScrimInFrontColor(getScrimInFrontAlpha());
- setScrimBehindColor(0f);
+ updateScrimNormal();
} else if (mBouncerShowing) {
setScrimInFrontColor(0f);
setScrimBehindColor(mScrimBehindAlpha);
@@ -474,18 +473,18 @@
}
private void updateScrim(boolean animate, View scrim, float alpha, float currentAlpha) {
- if (mKeyguardFadingOutInProgress) {
+ if (mKeyguardFadingOutInProgress && mKeyguardFadeoutAnimation.getCurrentPlayTime() != 0) {
return;
}
- ValueAnimator previousAnimator = StackStateAnimator.getChildTag(scrim,
+ ValueAnimator previousAnimator = ViewState.getChildTag(scrim,
TAG_KEY_ANIM);
float animEndValue = -1;
if (previousAnimator != null) {
if (animate || alpha == currentAlpha) {
previousAnimator.cancel();
} else {
- animEndValue = StackStateAnimator.getChildTag(scrim, TAG_END_ALPHA);
+ animEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
}
}
if (alpha != currentAlpha && alpha != animEndValue) {
@@ -495,10 +494,8 @@
scrim.setTag(TAG_END_ALPHA, alpha);
} else {
if (previousAnimator != null) {
- float previousStartValue = StackStateAnimator.getChildTag(scrim,
- TAG_START_ALPHA);
- float previousEndValue = StackStateAnimator.getChildTag(scrim,
- TAG_END_ALPHA);
+ float previousStartValue = ViewState.getChildTag(scrim, TAG_START_ALPHA);
+ float previousEndValue = ViewState.getChildTag(scrim, TAG_END_ALPHA);
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
PropertyValuesHolder[] values = previousAnimator.getValues();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index dbe7f96..a948a08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -44,6 +44,7 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.tuner.TunerService;
@@ -74,6 +75,7 @@
private NotificationIconAreaController mNotificationIconAreaController;
private View mNotificationIconAreaInner;
+ private NotificationShelf mNotificationShelf;
private BatteryMeterView mBatteryMeterView;
private BatteryMeterView mBatteryMeterViewKeyguard;
@@ -123,6 +125,7 @@
mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons);
mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster);
+ mNotificationShelf = phoneStatusBar.getNotificationShelf();
mNotificationIconAreaController = SystemUIFactory.getInstance()
.createNotificationIconAreaController(context, phoneStatusBar);
mNotificationIconAreaInner =
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 69decd7..4263670 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -33,6 +33,7 @@
import com.android.systemui.DejankUtils;
import com.android.keyguard.LatencyTracker;
import com.android.systemui.SystemUIFactory;
+import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.RemoteInputController;
@@ -102,14 +103,15 @@
public void registerStatusBar(PhoneStatusBar phoneStatusBar,
ViewGroup container, StatusBarWindowManager statusBarWindowManager,
ScrimController scrimController,
- FingerprintUnlockController fingerprintUnlockController) {
+ FingerprintUnlockController fingerprintUnlockController,
+ DismissCallbackRegistry dismissCallbackRegistry) {
mPhoneStatusBar = phoneStatusBar;
mContainer = container;
mStatusBarWindowManager = statusBarWindowManager;
mScrimController = scrimController;
mFingerprintUnlockController = fingerprintUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
- mViewMediatorCallback, mLockPatternUtils, mStatusBarWindowManager, container);
+ mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
}
/**
@@ -330,17 +332,21 @@
});
} else {
executeAfterKeyguardGoneAction();
- if (mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING) {
- mFingerprintUnlockController.startKeyguardFadingAway();
- mPhoneStatusBar.setKeyguardFadingAway(startTime, 0, 240);
+ boolean wakeUnlockPulsing =
+ mFingerprintUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
+ if (wakeUnlockPulsing) {
+ delay = 0;
+ fadeoutDuration = 240;
+ }
+ mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
+ mFingerprintUnlockController.startKeyguardFadingAway();
+ mBouncer.hide(true /* destroyView */);
+ updateStates();
+ if (wakeUnlockPulsing) {
mStatusBarWindowManager.setKeyguardFadingAway(true);
mPhoneStatusBar.fadeKeyguardWhilePulsing();
- animateScrimControllerKeyguardFadingOut(0, 240, new Runnable() {
- @Override
- public void run() {
- mPhoneStatusBar.hideKeyguard();
- }
- }, false /* skipFirstFrame */);
+ animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
+ mPhoneStatusBar::hideKeyguard, false /* skipFirstFrame */);
} else {
mFingerprintUnlockController.startKeyguardFadingAway();
mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
@@ -367,9 +373,7 @@
}
}
mStatusBarWindowManager.setKeyguardShowing(false);
- mBouncer.hide(true /* destroyView */);
mViewMediatorCallback.keyguardGone();
- updateStates();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 6217433..f6dd88d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -235,7 +235,7 @@
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
- && mNotificationPanel.getExpandedHeight() == 0f) {
+ && mNotificationPanel.isFullyCollapsed()) {
mNotificationPanel.startExpandLatencyTracking();
}
mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 1cad61f..4c879c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -24,6 +24,7 @@
import android.util.AttributeSet;
import android.util.Slog;
import android.view.MotionEvent;
+import android.view.Surface;
import android.view.View;
import com.android.systemui.R;
@@ -54,6 +55,7 @@
private int mHold, mDecay;
private boolean mVertical;
private long mLastPokeTime;
+ private int mDisplayRotation;
private final Runnable mDebugFlash = new Runnable() {
@Override
@@ -132,7 +134,16 @@
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
- final boolean consumeEvent = mVertical ? event.getX() < size : event.getY() < size;
+ final boolean consumeEvent;
+ if (mVertical) {
+ if (mDisplayRotation == Surface.ROTATION_270) {
+ consumeEvent = event.getX() > getWidth() - size;
+ } else {
+ consumeEvent = event.getX() < size;
+ }
+ } else {
+ consumeEvent = event.getY() < size;
+ }
if (consumeEvent) {
if (CHATTY) {
Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
@@ -170,7 +181,16 @@
}
final int size = (int) getSize(SystemClock.uptimeMillis());
- can.clipRect(0, 0, mVertical ? size : can.getWidth(), mVertical ? can.getHeight() : size);
+ if (mVertical) {
+ if (mDisplayRotation == Surface.ROTATION_270) {
+ can.clipRect(can.getWidth() - size, 0, can.getWidth(), can.getHeight());
+ } else {
+ can.clipRect(0, 0, size, can.getHeight());
+ }
+ } else {
+ can.clipRect(0, 0, can.getWidth(), size);
+ }
+
final float frac = DEBUG ? (mFlashFrac - 0.5f) + 0.5f : mFlashFrac;
can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
@@ -178,4 +198,8 @@
// crazy aggressive redrawing here, for debugging only
postInvalidateDelayed(100);
}
+
+ public void setDisplayRotation(int rotation) {
+ mDisplayRotation = rotation;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index f6c0942..c21c493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -103,6 +103,7 @@
private boolean mWaitingOnCollapseWhenGoingAway;
private boolean mIsObserving;
private boolean mRemoteInputActive;
+ private float mExpandedHeight;
public HeadsUpManager(final Context context, View statusBarWindowView,
NotificationGroupManager groupManager) {
@@ -513,7 +514,7 @@
row = groupSummary;
}
}
- return row.getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
+ return row.getPinnedHeadsUpHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index fafbdd1..0396613 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -92,20 +92,6 @@
return mCanSkipBouncer;
}
- public void unlock() {
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- }
-
- public void lock() {
- try {
- WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
- } catch (RemoteException e) {
- }
- }
-
public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
mShowing = showing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 81da672..26f74ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -16,9 +16,12 @@
package com.android.systemui.statusbar.stack;
+import android.content.Context;
import android.view.View;
+import com.android.systemui.R;
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
@@ -44,6 +47,38 @@
private float mMaxHeadsUpTranslation;
private boolean mDismissAllInProgress;
private int mLayoutMinHeight;
+ private NotificationShelf mShelf;
+ private int mZDistanceBetweenElements;
+ private int mBaseZHeight;
+ private int mMaxLayoutHeight;
+ private ActivatableNotificationView mLastVisibleBackgroundChild;
+
+ public AmbientState(Context context) {
+ reload(context);
+ }
+
+ /**
+ * Reload the dimens e.g. if the density changed.
+ */
+ public void reload(Context context) {
+ mZDistanceBetweenElements = Math.max(1, context.getResources()
+ .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
+ mBaseZHeight = 4 * mZDistanceBetweenElements;
+ }
+
+ /**
+ * @return the basic Z height on which notifications remain.
+ */
+ public int getBaseZHeight() {
+ return mBaseZHeight;
+ }
+
+ /**
+ * @return the distance in Z between two overlaying notifications.
+ */
+ public int getZDistanceBetweenElements() {
+ return mZDistanceBetweenElements;
+ }
public int getScrollY() {
return mScrollY;
@@ -122,8 +157,8 @@
return mSpeedBumpIndex;
}
- public void setSpeedBumpIndex(int speedBumpIndex) {
- mSpeedBumpIndex = speedBumpIndex;
+ public void setSpeedBumpIndex(int shelfIndex) {
+ mSpeedBumpIndex = shelfIndex;
}
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -151,7 +186,7 @@
}
public int getInnerHeight() {
- return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
+ return Math.max(Math.min(mLayoutHeight, mMaxLayoutHeight) - mTopPadding, mLayoutMinHeight);
}
public boolean isShadeExpanded() {
@@ -181,4 +216,29 @@
public void setLayoutMinHeight(int layoutMinHeight) {
mLayoutMinHeight = layoutMinHeight;
}
+
+ public void setShelf(NotificationShelf shelf) {
+ mShelf = shelf;
+ }
+
+ public NotificationShelf getShelf() {
+ return mShelf;
+ }
+
+ public void setLayoutMaxHeight(int maxLayoutHeight) {
+ mMaxLayoutHeight = maxLayoutHeight;
+ }
+
+ /**
+ * Sets the last visible view of the host layout, that has a background, i.e the very last
+ * view in the shade, without the clear all button.
+ */
+ public void setLastVisibleBackgroundChild(
+ ActivatableNotificationView lastVisibleBackgroundChild) {
+ mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
+ }
+
+ public ActivatableNotificationView getLastVisibleBackgroundChild() {
+ return mLastVisibleBackgroundChild;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 561b18a..d3d58f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -23,6 +23,7 @@
*/
public class AnimationFilter {
boolean animateAlpha;
+ boolean animateX;
boolean animateY;
boolean animateZ;
boolean animateHeight;
@@ -42,6 +43,11 @@
return this;
}
+ public AnimationFilter animateX() {
+ animateX = true;
+ return this;
+ }
+
public AnimationFilter animateY() {
animateY = true;
return this;
@@ -116,6 +122,7 @@
private void combineFilter(AnimationFilter filter) {
animateAlpha |= filter.animateAlpha;
+ animateX |= filter.animateX;
animateY |= filter.animateY;
animateZ |= filter.animateZ;
animateHeight |= filter.animateHeight;
@@ -129,6 +136,7 @@
private void reset() {
animateAlpha = false;
+ animateX = false;
animateY = false;
animateZ = false;
animateHeight = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
new file mode 100644
index 0000000..0de774d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationProperties.java
@@ -0,0 +1,65 @@
+/*
+ * 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.systemui.statusbar.stack;
+
+import android.animation.AnimatorListenerAdapter;
+import android.util.Property;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+/**
+ * Properties for a View animation
+ */
+public class AnimationProperties {
+ public long duration;
+ public long delay;
+
+ /**
+ * @return an animation filter for this animation.
+ */
+ public AnimationFilter getAnimationFilter() {
+ return new AnimationFilter();
+ }
+
+ /**
+ * @return a listener that should be run whenever any property finished its animation
+ */
+ public AnimatorListenerAdapter getAnimationFinishListener() {
+ return null;
+ }
+
+ public boolean wasAdded(View view) {
+ return false;
+ }
+
+ /**
+ * Get a custom interpolator for a property instead of the normal one.
+ */
+ public Interpolator getCustomInterpolator(View child, Property property) {
+ return null;
+ }
+
+ public AnimationProperties setDuration(long duration) {
+ this.duration = duration;
+ return this;
+ }
+
+ public AnimationProperties setDelay(long delay) {
+ this.delay = delay;
+ return this;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
new file mode 100644
index 0000000..7854c98
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -0,0 +1,449 @@
+/*
+ * 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.systemui.statusbar.stack;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.view.View;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
+
+/**
+* A state of an expandable view
+*/
+public class ExpandableViewState extends ViewState {
+
+ private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
+ private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
+ private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
+ private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+ private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
+ private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+ private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
+ private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
+
+ // These are flags such that we can create masks for filtering.
+
+ /**
+ * No known location. This is the default and should not be set after an invocation of the
+ * algorithm.
+ */
+ public static final int LOCATION_UNKNOWN = 0x00;
+
+ /**
+ * The location is the first heads up notification, so on the very top.
+ */
+ public static final int LOCATION_FIRST_HUN = 0x01;
+
+ /**
+ * The location is hidden / scrolled away on the top.
+ */
+ public static final int LOCATION_HIDDEN_TOP = 0x02;
+
+ /**
+ * The location is in the main area of the screen and visible.
+ */
+ public static final int LOCATION_MAIN_AREA = 0x04;
+
+ /**
+ * The location is in the bottom stack and it's peeking
+ */
+ public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
+
+ /**
+ * The location is in the bottom stack and it's hidden.
+ */
+ public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
+
+ /**
+ * The view isn't laid out at all.
+ */
+ public static final int LOCATION_GONE = 0x40;
+
+ public int height;
+ public boolean dimmed;
+ public boolean dark;
+ public boolean hideSensitive;
+ public boolean belowSpeedBump;
+ public float shadowAlpha;
+ public boolean inShelf;
+
+ /**
+ * How much the child overlaps with the previous child on top. This is used to
+ * show the background properly when the child on top is translating away.
+ */
+ public int clipTopAmount;
+
+ /**
+ * The index of the view, only accounting for views not equal to GONE
+ */
+ public int notGoneIndex;
+
+ /**
+ * The location this view is currently rendered at.
+ *
+ * <p>See <code>LOCATION_</code> flags.</p>
+ */
+ public int location;
+
+ @Override
+ public void copyFrom(ViewState viewState) {
+ super.copyFrom(viewState);
+ if (viewState instanceof ExpandableViewState) {
+ ExpandableViewState svs = (ExpandableViewState) viewState;
+ height = svs.height;
+ dimmed = svs.dimmed;
+ shadowAlpha = svs.shadowAlpha;
+ dark = svs.dark;
+ hideSensitive = svs.hideSensitive;
+ belowSpeedBump = svs.belowSpeedBump;
+ clipTopAmount = svs.clipTopAmount;
+ notGoneIndex = svs.notGoneIndex;
+ location = svs.location;
+ }
+ }
+
+ /**
+ * Applies a {@link ExpandableViewState} to a {@link ExpandableView}.
+ */
+ @Override
+ public void applyToView(View view) {
+ super.applyToView(view);
+ if (view instanceof ExpandableView) {
+ ExpandableView expandableView = (ExpandableView) view;
+
+ int height = expandableView.getActualHeight();
+ int newHeight = this.height;
+
+ // apply height
+ if (height != newHeight) {
+ expandableView.setActualHeight(newHeight, false /* notifyListeners */);
+ }
+
+ float shadowAlpha = expandableView.getShadowAlpha();
+ float newShadowAlpha = this.shadowAlpha;
+
+ // apply shadowAlpha
+ if (shadowAlpha != newShadowAlpha) {
+ expandableView.setShadowAlpha(newShadowAlpha);
+ }
+
+ // apply dimming
+ expandableView.setDimmed(this.dimmed, false /* animate */);
+
+ // apply hiding sensitive
+ expandableView.setHideSensitive(
+ this.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
+ // apply below shelf speed bump
+ expandableView.setBelowSpeedBump(this.belowSpeedBump);
+
+ // apply dark
+ expandableView.setDark(this.dark, false /* animate */, 0 /* delay */);
+
+ // apply clipping
+ float oldClipTopAmount = expandableView.getClipTopAmount();
+ if (oldClipTopAmount != this.clipTopAmount) {
+ expandableView.setClipTopAmount(this.clipTopAmount);
+ }
+
+ expandableView.setTransformingInShelf(false);
+ expandableView.setInShelf(inShelf);
+ }
+ }
+
+ @Override
+ public void animateTo(View child, AnimationProperties properties) {
+ super.animateTo(child, properties);
+ if (!(child instanceof ExpandableView)) {
+ return;
+ }
+ ExpandableView expandableView = (ExpandableView) child;
+ AnimationFilter animationFilter = properties.getAnimationFilter();
+
+ // start height animation
+ if (this.height != expandableView.getActualHeight()) {
+ startHeightAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_HEIGHT);
+ }
+
+ // start shadow alpha animation
+ if (this.shadowAlpha != expandableView.getShadowAlpha()) {
+ startShadowAlphaAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
+ }
+
+ // start top inset animation
+ if (this.clipTopAmount != expandableView.getClipTopAmount()) {
+ startInsetAnimation(expandableView, properties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
+ }
+
+ // start dimmed animation
+ expandableView.setDimmed(this.dimmed, animationFilter.animateDimmed);
+
+ // apply below the speed bump
+ expandableView.setBelowSpeedBump(this.belowSpeedBump);
+
+ // start hiding sensitive animation
+ expandableView.setHideSensitive(this.hideSensitive, animationFilter.animateHideSensitive,
+ properties.delay, properties.duration);
+
+ // start dark animation
+ expandableView.setDark(this.dark, animationFilter.animateDark, properties.delay);
+
+ if (properties.wasAdded(child) && !hidden) {
+ expandableView.performAddAnimation(properties.delay, properties.duration);
+ }
+
+ if (!expandableView.isInShelf() && this.inShelf) {
+ expandableView.setTransformingInShelf(true);
+ }
+ expandableView.setInShelf(this.inShelf);
+ }
+
+ private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) {
+ Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+ Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+ int newEndValue = this.height;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateHeight) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_HEIGHT, newStartValue);
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setActualHeight(newEndValue, false);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setActualHeight((int) animation.getAnimatedValue(),
+ false /* notifyListeners */);
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_HEIGHT, null);
+ child.setTag(TAG_START_HEIGHT, null);
+ child.setTag(TAG_END_HEIGHT, null);
+ child.setActualHeightAnimating(false);
+ if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
+ ((ExpandableNotificationRow) child).setGroupExpansionChanging(
+ false /* isExpansionChanging */);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_HEIGHT, animator);
+ child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+ child.setTag(TAG_END_HEIGHT, newEndValue);
+ child.setActualHeightAnimating(true);
+ }
+
+ private void startShadowAlphaAnimation(final ExpandableView child,
+ AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
+ Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
+ float newEndValue = this.shadowAlpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateShadowAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setShadowAlpha(newEndValue);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setShadowAlpha((float) animation.getAnimatedValue());
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
+ child.setTag(TAG_START_SHADOW_ALPHA, null);
+ child.setTag(TAG_END_SHADOW_ALPHA, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
+ child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ }
+
+ private void startInsetAnimation(final ExpandableView child, AnimationProperties properties) {
+ Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
+ Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
+ int newEndValue = this.clipTopAmount;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateTopInset) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ int relativeDiff = newEndValue - previousEndValue;
+ int newStartValue = previousStartValue + relativeDiff;
+ values[0].setIntValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TOP_INSET, newStartValue);
+ child.setTag(TAG_END_TOP_INSET, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setClipTopAmount(newEndValue);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setClipTopAmount((int) animation.getAnimatedValue());
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TOP_INSET, null);
+ child.setTag(TAG_START_TOP_INSET, null);
+ child.setTag(TAG_END_TOP_INSET, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
+ child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
+ child.setTag(TAG_END_TOP_INSET, newEndValue);
+ }
+
+ /**
+ * Get the end value of the height animation running on a view or the actualHeight
+ * if no animation is running.
+ */
+ public static int getFinalActualHeight(ExpandableView view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
+ if (heightAnimator == null) {
+ return view.getActualHeight();
+ } else {
+ return getChildTag(view, TAG_END_HEIGHT);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index d7920a9..b8f8cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -76,6 +76,7 @@
private NotificationViewWrapper mNotificationHeaderWrapper;
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
+ private int mClipBottomAmount;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -185,6 +186,11 @@
}
@Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ @Override
public boolean pointInView(float localX, float localY, float slop) {
return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
localY < (mRealHeight + slop);
@@ -207,6 +213,7 @@
mDividers.add(newIndex, divider);
updateGroupOverflow();
+ row.setIconTransformationAmount(0, false /* isLastChild */);
}
public void removeNotification(ExpandableNotificationRow row) {
@@ -412,7 +419,7 @@
* @param resultState the state to update
* @param parentState the state of the parent
*/
- public void getState(StackScrollState resultState, StackViewState parentState) {
+ public void getState(StackScrollState resultState, ExpandableViewState parentState) {
int childCount = mChildren.size();
int yPosition = mNotificationHeaderMargin;
boolean firstChild = true;
@@ -427,7 +434,6 @@
boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
&& mChildrenExpanded;
- int parentHeight = parentState.height;
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
@@ -449,22 +455,11 @@
firstChild = false;
}
- StackViewState childState = resultState.getViewStateForView(child);
+ ExpandableViewState childState = resultState.getViewStateForView(child);
int intrinsicHeight = child.getIntrinsicHeight();
- if (childrenExpanded) {
- // When a group is expanded and moving into bottom stack, the bottom visible child
- // adjusts its height to move into it. Children after it are hidden.
- if (updateChildStateForExpandedGroup(child, parentHeight, childState, yPosition)) {
- // Clipping might be deactivated if the view is transforming, however, clipping
- // the child into the bottom stack should take precedent over this.
- childState.isBottomClipped = true;
- }
- } else {
- childState.hidden = false;
- childState.height = intrinsicHeight;
- childState.isBottomClipped = false;
- }
+ childState.height = intrinsicHeight;
childState.yTranslation = yPosition;
+ childState.hidden = false;
// When the group is expanded, the children cast the shadows rather than the parent
// so use the parent's elevation here.
childState.zTranslation = childrenExpanded
@@ -530,7 +525,7 @@
* @return true if children after this one should be hidden.
*/
private boolean updateChildStateForExpandedGroup(ExpandableNotificationRow child,
- int parentHeight, StackViewState childState, int yPosition) {
+ int parentHeight, ExpandableViewState childState, int yPosition) {
final int top = yPosition + child.getClipTopAmount();
final int intrinsicHeight = child.getIntrinsicHeight();
final int bottom = top + intrinsicHeight;
@@ -570,8 +565,8 @@
|| mNotificationParent.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
- StackViewState viewState = state.getViewStateForView(child);
- state.applyState(child, viewState);
+ ExpandableViewState viewState = state.getViewStateForView(child);
+ viewState.applyToView(child);
// layout the divider
View divider = mDividers.get(i);
@@ -584,16 +579,44 @@
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
- state.applyViewState(divider, tmpState);
+ tmpState.applyToView(divider);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
- if (mOverflowNumber != null) {
- state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+ if (mGroupOverFlowState != null) {
+ mGroupOverFlowState.applyToView(mOverflowNumber);
mNeverAppliedGroupState = false;
}
- if (mNotificationHeader != null) {
- state.applyViewState(mNotificationHeader, mHeaderViewState);
+ if (mHeaderViewState != null) {
+ mHeaderViewState.applyToView(mNotificationHeader);
+ }
+ updateChildrenClipping();
+ }
+
+ private void updateChildrenClipping() {
+ int childCount = mChildren.size();
+ int layoutEnd = mNotificationParent.getActualHeight() - mClipBottomAmount;
+ for (int i = 0; i < childCount; i++) {
+ ExpandableNotificationRow child = mChildren.get(i);
+ if (child.getVisibility() == GONE) {
+ continue;
+ }
+ float childTop = child.getTranslationY();
+ float childBottom = childTop + child.getActualHeight();
+ boolean visible = true;
+ int clipBottomAmount = 0;
+ if (childTop > layoutEnd) {
+ visible = false;
+ } else if (childBottom > layoutEnd) {
+ clipBottomAmount = (int) (childBottom - layoutEnd);
+ }
+
+ boolean isVisible = child.getVisibility() == VISIBLE;
+ if (visible != isVisible) {
+ child.setVisibility(visible ? VISIBLE : INVISIBLE);
+ }
+
+ child.setClipBottomAmount(clipBottomAmount);
}
}
@@ -608,8 +631,7 @@
return;
}
- public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
- long baseDelay, long duration) {
+ public void startAnimationToState(StackScrollState state, AnimationProperties properties) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
float expandFraction = getGroupExpandFraction();
@@ -617,8 +639,8 @@
|| mNotificationParent.isGroupExpansionChanging();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
- StackViewState viewState = state.getViewStateForView(child);
- stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay);
+ ExpandableViewState viewState = state.getViewStateForView(child);
+ viewState.animateTo(child, properties);
// layout the divider
View divider = mDividers.get(i);
@@ -631,7 +653,7 @@
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
- stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
+ tmpState.animateTo(divider, properties);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
@@ -639,16 +661,16 @@
if (mNeverAppliedGroupState) {
float alpha = mGroupOverFlowState.alpha;
mGroupOverFlowState.alpha = 0;
- state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+ mGroupOverFlowState.applyToView(mOverflowNumber);
mGroupOverFlowState.alpha = alpha;
mNeverAppliedGroupState = false;
}
- stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
- baseDelay, duration);
+ mGroupOverFlowState.animateTo(mOverflowNumber, properties);
}
if (mNotificationHeader != null) {
- state.applyViewState(mNotificationHeader, mHeaderViewState);
+ mHeaderViewState.applyToView(mNotificationHeader);
}
+ updateChildrenClipping();
}
public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -876,4 +898,18 @@
}
return 0;
}
+
+ public void setIconsVisible(boolean iconsVisible) {
+ if (mNotificationHeaderWrapper != null) {
+ NotificationHeaderView header = mNotificationHeaderWrapper.getNotificationHeader();
+ if (header != null) {
+ header.getIcon().setForceHidden(!iconsVisible);
+ }
+ }
+ }
+
+ public void setClipBottomAmount(int clipBottomAmount) {
+ mClipBottomAmount = clipBottomAmount;
+ updateChildrenClipping();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 72a0e59..10d995c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -69,9 +69,9 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationGuts;
-import com.android.systemui.statusbar.NotificationOverflowContainer;
import com.android.systemui.statusbar.NotificationSettingsIconRow;
import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRowListener;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -135,8 +135,6 @@
private Paint mDebugPaint;
private int mContentHeight;
private int mCollapsedSize;
- private int mBottomStackSlowDownHeight;
- private int mBottomStackPeekSize;
private int mPaddingBetweenElements;
private int mIncreasedPaddingBetweenElements;
private int mTopPadding;
@@ -151,7 +149,7 @@
* The current State this Layout is in
*/
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
- private AmbientState mAmbientState = new AmbientState();
+ private final AmbientState mAmbientState;
private NotificationGroupManager mGroupManager;
private HashSet<View> mChildrenToAddAnimated = new HashSet<>();
private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
@@ -261,18 +259,14 @@
private boolean mTrackingHeadsUp;
private ScrimController mScrimController;
private boolean mForceNoOverlappingRendering;
- private NotificationOverflowContainer mOverflowContainer;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
private FalsingManager mFalsingManager;
private boolean mAnimationRunning;
- private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater
+ private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- // if it needs animation
- if (!mNeedsAnimation && !mChildrenUpdateRequested) {
- updateBackground();
- }
+ onPreDrawDuringAnimation();
return true;
}
};
@@ -334,7 +328,7 @@
private boolean mPulsing;
private boolean mDrawBackgroundAsSrc;
private boolean mFadingOut;
- private boolean mParentFadingOut;
+ private boolean mParentNotFullyVisible;
private boolean mGroupExpandedForMeasure;
private boolean mScrollable;
private View mForcedScroll;
@@ -354,6 +348,15 @@
private boolean mQsExpanded;
private boolean mForwardScrollable;
private boolean mBackwardScrollable;
+ private NotificationShelf mShelf;
+ private int mMaxDisplayedNotifications = -1;
+ private int mStatusBarHeight;
+ private boolean mNoAmbient;
+ private final Rect mClipRect = new Rect();
+ private boolean mIsClipped;
+ private Rect mRequestedClipBounds;
+ private boolean mInHeadsUpPinnedMode;
+ private boolean mHeadsUpAnimatingAway;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -370,6 +373,7 @@
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mAmbientState = new AmbientState(context);
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
@@ -418,11 +422,6 @@
if (DEBUG) {
int y = mTopPadding;
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- y = (int) (getLayoutHeight() - mBottomStackPeekSize
- - mBottomStackSlowDownHeight);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
- y = (int) (getLayoutHeight() - mBottomStackPeekSize);
- canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
y = (int) getLayoutHeight();
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
y = getHeight() - getEmptyBottomMargin();
@@ -459,16 +458,15 @@
mOverflingDistance = configuration.getScaledOverflingDistance();
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
- mBottomStackPeekSize = context.getResources()
- .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mStackScrollAlgorithm.initView(context);
+ mAmbientState.reload(context);
mPaddingBetweenElements = Math.max(1, context.getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height));
mIncreasedPaddingBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
- mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
+ mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
}
public void setDrawBackgroundAsSrc(boolean asSrc) {
@@ -477,7 +475,7 @@
}
private void updateSrcDrawing() {
- mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && (!mFadingOut && !mParentFadingOut)
+ mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadingOut && !mParentNotFullyVisible
? mSrcMode : null);
invalidate();
}
@@ -529,8 +527,9 @@
}
}
- public void updateSpeedBumpIndex(int newIndex) {
+ public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
mAmbientState.setSpeedBumpIndex(newIndex);
+ mNoAmbient = noAmbient;
}
public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
@@ -541,21 +540,22 @@
* Returns the location the given child is currently rendered at.
*
* @param child the child to get the location for
- * @return one of {@link StackViewState}'s <code>LOCATION_*</code> constants
+ * @return one of {@link ExpandableViewState}'s <code>LOCATION_*</code> constants
*/
public int getChildLocation(View child) {
- StackViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
+ ExpandableViewState childViewState = mCurrentStackScrollState.getViewStateForView(child);
if (childViewState == null) {
- return StackViewState.LOCATION_UNKNOWN;
+ return ExpandableViewState.LOCATION_UNKNOWN;
}
if (childViewState.gone) {
- return StackViewState.LOCATION_GONE;
+ return ExpandableViewState.LOCATION_GONE;
}
return childViewState.location;
}
private void setMaxLayoutHeight(int maxLayoutHeight) {
mMaxLayoutHeight = maxLayoutHeight;
+ mShelf.setMaxLayoutHeight(maxLayoutHeight);
updateAlgorithmHeightAndPadding();
}
@@ -584,6 +584,13 @@
}
}
+ private void onPreDrawDuringAnimation() {
+ mShelf.updateAppearance();
+ if (!mNeedsAnimation && !mChildrenUpdateRequested) {
+ updateBackground();
+ }
+ }
+
private void updateScrollStateForAddedChildren() {
if (mChildrenToAddAnimated.isEmpty()) {
return;
@@ -671,7 +678,18 @@
*/
public void setExpandedHeight(float height) {
mExpandedHeight = height;
- setIsExpanded(height > 0.0f);
+ setIsExpanded(height > 0);
+ int minExpansionHeight = getMinExpansionHeight();
+ if (height < minExpansionHeight) {
+ mClipRect.left = 0;
+ mClipRect.right = getWidth();
+ mClipRect.top = 0;
+ mClipRect.bottom = (int) height;
+ height = minExpansionHeight;
+ setRequestedClipBounds(mClipRect);
+ } else {
+ setRequestedClipBounds(null);
+ }
int stackHeight;
float translationY;
float appearEndPosition = getAppearEndPosition();
@@ -697,6 +715,26 @@
requestChildrenUpdate();
}
setStackTranslation(translationY);
+ requestChildrenUpdate();
+ }
+
+ private void setRequestedClipBounds(Rect clipRect) {
+ mRequestedClipBounds = clipRect;
+ updateClipping();
+ }
+
+ public void updateClipping() {
+ boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
+ && !mHeadsUpAnimatingAway;
+ if (mIsClipped != clipped) {
+ mIsClipped = clipped;
+ updateFadingState();
+ }
+ if (clipped) {
+ setClipBounds(mRequestedClipBounds);
+ } else {
+ setClipBounds(null);
+ }
}
/**
@@ -704,13 +742,7 @@
* Measured relative to the resting position.
*/
private float getExpandTranslationStart() {
- int startPosition = 0;
- if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
- startPosition = - Math.min(getFirstChildIntrinsicHeight(),
- mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
- - mBottomStackPeekSize);
- }
- return startPosition - mTopPadding;
+ return - mTopPadding;
}
/**
@@ -718,9 +750,14 @@
* Measured in absolute height.
*/
private float getAppearStartPosition() {
- return mTrackingHeadsUp
- ? mHeadsUpManager.getTopHeadsUpPinnedHeight()
- : 0;
+ if (mTrackingHeadsUp && mFirstVisibleBackgroundChild != null) {
+ if (mFirstVisibleBackgroundChild.isAboveShelf()) {
+ // If we ever expanded beyond the first notification, it's allowed to merge into
+ // the shelf
+ return mFirstVisibleBackgroundChild.getPinnedHeadsUpHeight();
+ }
+ }
+ return getMinExpansionHeight();
}
/**
@@ -728,11 +765,18 @@
* Measured in absolute height.
*/
private float getAppearEndPosition() {
- int firstItemHeight = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
- ? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
- + mBottomStackSlowDownHeight
- : getLayoutMinHeight();
- return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
+ int appearPosition;
+ int minNotificationsForShelf = 1;
+ if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
+ appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
+ minNotificationsForShelf = 2;
+ } else {
+ appearPosition = 0;
+ }
+ if (getNotGoneChildCount() >= minNotificationsForShelf) {
+ appearPosition += mShelf.getIntrinsicHeight();
+ }
+ return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
}
/**
@@ -773,14 +817,6 @@
return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
}
- public int getBottomStackPeekSize() {
- return mBottomStackPeekSize;
- }
-
- public int getBottomStackSlowDownHeight() {
- return mBottomStackSlowDownHeight;
- }
-
public void setLongPressListener(SwipeHelper.LongPressListener listener) {
mSwipeHelper.setLongPressListener(listener);
mLongPressListener = listener;
@@ -957,7 +993,8 @@
}
float childTop = slidingChild.getTranslationY();
float top = childTop + slidingChild.getClipTopAmount();
- float bottom = childTop + slidingChild.getActualHeight();
+ float bottom = childTop + slidingChild.getActualHeight()
+ - slidingChild.getClipBottomAmount();
float dist = Math.min(Math.abs(top - localTouchY), Math.abs(bottom - localTouchY));
if (dist < minDist) {
@@ -986,7 +1023,8 @@
}
float childTop = slidingChild.getTranslationY();
float top = childTop + slidingChild.getClipTopAmount();
- float bottom = childTop + slidingChild.getActualHeight();
+ float bottom = childTop + slidingChild.getActualHeight()
+ - slidingChild.getClipBottomAmount();
// Allow the full width of this view to prevent gesture conflict on Keyguard (phone and
// camera affordance).
@@ -1056,29 +1094,7 @@
@Override
public int getMaxExpandHeight(ExpandableView view) {
- int maxContentHeight = view.getMaxContentHeight();
- if (view.isSummaryWithChildren() && view.getParent() == this) {
- // Faking a measure with the group expanded to simulate how the group would look if
- // it was. Doing a calculation here would be highly non-trivial because of the
- // algorithm
- mGroupExpandedForMeasure = true;
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- mGroupManager.toggleGroupExpansion(row.getStatusBarNotification());
- row.setForceUnlocked(true);
- mAmbientState.setLayoutHeight(mMaxLayoutHeight);
- mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
- mAmbientState.setLayoutHeight(getLayoutHeight());
- mGroupManager.toggleGroupExpansion(
- row.getStatusBarNotification());
- mGroupExpandedForMeasure = false;
- row.setForceUnlocked(false);
- StackViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
- if (viewState != null) {
- // The view could have been removed
- return Math.min(viewState.height, maxContentHeight);
- }
- }
- return maxContentHeight;
+ return view.getMaxContentHeight();
}
public void setScrollingEnabled(boolean enable) {
@@ -1748,8 +1764,7 @@
private int getScrollRange() {
int contentHeight = getContentHeight();
- int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
- + mBottomStackSlowDownHeight);
+ int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
int imeInset = getImeInset();
scrollRange += Math.min(imeInset, Math.max(0,
getContentHeight() - (getHeight() - imeInset)));
@@ -1767,7 +1782,7 @@
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) {
+ if (child.getVisibility() != View.GONE && child != mShelf) {
return (ExpandableView) child;
}
}
@@ -1814,7 +1829,7 @@
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) {
+ if (child.getVisibility() != View.GONE && child != mShelf) {
return child;
}
}
@@ -1829,7 +1844,7 @@
int count = 0;
for (int i = 0; i < childCount; i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
- if (child.getVisibility() != View.GONE && !child.willBeGone()) {
+ if (child.getVisibility() != View.GONE && !child.willBeGone() && child != mShelf) {
count++;
}
}
@@ -1843,9 +1858,17 @@
private void updateContentHeight() {
int height = 0;
float previousIncreasedAmount = 0.0f;
+ int numShownItems = 0;
+ boolean finish = false;
for (int i = 0; i < getChildCount(); i++) {
ExpandableView expandableView = (ExpandableView) getChildAt(i);
- if (expandableView.getVisibility() != View.GONE) {
+ if (expandableView.getVisibility() != View.GONE
+ && !expandableView.hasNoContentHeight()) {
+ if (mMaxDisplayedNotifications != -1
+ && numShownItems >= mMaxDisplayedNotifications) {
+ expandableView = mShelf;
+ finish = true;
+ }
float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount();
if (height != 0) {
height += (int) NotificationUtils.interpolate(
@@ -1855,10 +1878,15 @@
}
previousIncreasedAmount = increasedPaddingAmount;
height += expandableView.getIntrinsicHeight();
+ numShownItems++;
+ if (finish) {
+ break;
+ }
}
}
mContentHeight = height + mTopPadding;
updateScrollability();
+ mAmbientState.setLayoutMaxHeight(mContentHeight);
}
private void updateScrollability() {
@@ -2036,7 +2064,7 @@
private void applyCurrentBackgroundBounds() {
mScrimController.setExcludedBackgroundArea(
- mFadingOut || mParentFadingOut || mAmbientState.isDark() ? null
+ mFadingOut || mParentNotFullyVisible || mAmbientState.isDark() || mIsClipped ? null
: mCurrentBounds);
invalidate();
}
@@ -2056,7 +2084,7 @@
ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
int top = 0;
if (firstView != null) {
- int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(firstView);
+ int finalTranslationY = (int) ViewState.getFinalTranslationY(firstView);
if (mAnimateNextBackgroundTop
|| mTopAnimator == null && mCurrentBounds.top == finalTranslationY
|| mTopAnimator != null && mEndAnimationRect.top == finalTranslationY) {
@@ -2066,12 +2094,19 @@
top = (int) firstView.getTranslationY();
}
}
- ActivatableNotificationView lastView = mLastVisibleBackgroundChild;
+ ActivatableNotificationView lastView = mShelf.hasItemsInStableShelf()
+ ? mShelf
+ : mLastVisibleBackgroundChild;
int bottom = 0;
if (lastView != null) {
- int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(lastView);
- int finalHeight = StackStateAnimator.getFinalActualHeight(lastView);
- int finalBottom = finalTranslationY + finalHeight;
+ int finalTranslationY;
+ if (lastView == mShelf) {
+ finalTranslationY = (int) mShelf.getTranslationY();
+ } else {
+ finalTranslationY = (int) ViewState.getFinalTranslationY(lastView);
+ }
+ int finalHeight = ExpandableViewState.getFinalActualHeight(lastView);
+ int finalBottom = finalTranslationY + finalHeight - lastView.getClipBottomAmount();
finalBottom = Math.min(finalBottom, getHeight());
if (mAnimateNextBackgroundBottom
|| mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
@@ -2079,7 +2114,8 @@
// we're ending up at the same location as we are now, lets just skip the animation
bottom = finalBottom;
} else {
- bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
+ bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
+ - lastView.getClipBottomAmount());
bottom = Math.min(bottom, getHeight());
}
} else {
@@ -2115,8 +2151,8 @@
int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View child = getChildAt(i);
- if (child.getVisibility() != View.GONE
- && child instanceof ActivatableNotificationView) {
+ if (child.getVisibility() != View.GONE && child instanceof ActivatableNotificationView
+ && child != mShelf) {
return (ActivatableNotificationView) child;
}
}
@@ -2127,8 +2163,8 @@
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
- if (child.getVisibility() != View.GONE
- && child instanceof ActivatableNotificationView) {
+ if (child.getVisibility() != View.GONE && child instanceof ActivatableNotificationView
+ && child != mShelf) {
return (ActivatableNotificationView) child;
}
}
@@ -2211,9 +2247,7 @@
}
public int getLayoutMinHeight() {
- int firstChildMinHeight = getFirstChildIntrinsicHeight();
- return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
- mMaxLayoutHeight - mIntrinsicPadding);
+ return mShelf.getIntrinsicHeight();
}
public int getFirstChildIntrinsicHeight() {
@@ -2237,8 +2271,11 @@
final ExpandableView firstChild = getFirstChildNotGone();
final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
: mCollapsedSize;
- return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
- + mBottomStackSlowDownHeight;
+ int shelfHeight = 0;
+ if (mLastVisibleBackgroundChild != null) {
+ shelfHeight = mShelf.getIntrinsicHeight();
+ }
+ return mIntrinsicPadding + firstChildMinHeight + shelfHeight;
}
private int clampPadding(int desiredPadding) {
@@ -2467,7 +2504,7 @@
if (hasAddEvent) {
// This child was just added lets remove all events.
mHeadsUpChangeAnimations.removeAll(mTmpList);
- ((ExpandableNotificationRow ) child).setHeadsupDisappearRunning(false);
+ ((ExpandableNotificationRow ) child).setHeadsUpAnimatingAway(false);
}
mTmpList.clear();
return hasAddEvent;
@@ -2536,7 +2573,7 @@
for (int i = 0; i < getChildCount(); i++) {
ExpandableView child = (ExpandableView) getChildAt(i);
boolean notGone = child.getVisibility() != View.GONE;
- if (notGone) {
+ if (notGone && !child.hasNoContentHeight()) {
float increasedPaddingAmount = child.getIncreasedPaddingAmount();
if (position != 0) {
position += (int) NotificationUtils.interpolate(
@@ -2577,6 +2614,7 @@
}
mFirstVisibleBackgroundChild = firstChild;
mLastVisibleBackgroundChild = lastChild;
+ mAmbientState.setLastVisibleBackgroundChild(lastChild);
}
private void onViewAddedInternal(View child) {
@@ -2727,10 +2765,10 @@
: AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
if (row.isChildInGroup()) {
// We can otherwise get stuck in there if it was just isolated
- row.setHeadsupDisappearRunning(false);
+ row.setHeadsUpAnimatingAway(false);
}
} else {
- StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
+ ExpandableViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
if (viewState == null) {
// A view state was never generated for this view, so we don't need to animate
// this. This may happen with notification children.
@@ -2755,7 +2793,7 @@
mAddedHeadsUpChildren.clear();
}
- private boolean shouldHunAppearFromBottom(StackViewState viewState) {
+ private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
return false;
}
@@ -3078,14 +3116,7 @@
}
public int getEmptyBottomMargin() {
- int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
- - mBottomStackSlowDownHeight;
- return Math.max(emptyMargin, 0);
- }
-
- public float getKeyguardBottomStackSize() {
- return mBottomStackPeekSize + getResources().getDimensionPixelSize(
- R.dimen.bottom_stack_slow_down_length);
+ return Math.max(mMaxLayoutHeight - mContentHeight, 0);
}
public void onExpansionStarted() {
@@ -3195,20 +3226,18 @@
if (row.isChildInGroup()) {
endPosition += row.getNotificationParent().getTranslationY();
}
- int stackEnd = getStackEndPosition();
- if (endPosition > stackEnd) {
- setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
+ int layoutEnd = mMaxLayoutHeight + (int) mStackTranslation;
+ if (row != mLastVisibleBackgroundChild) {
+ layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
+ }
+ if (endPosition > layoutEnd) {
+ setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd));
mDisallowScrollingInThisMotion = true;
}
}
}
}
- private int getStackEndPosition() {
- return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight
- + mPaddingBetweenElements + (int) mStackTranslation;
- }
-
public void setOnHeightChangedListener(
ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
this.mOnHeightChangedListener = mOnHeightChangedListener;
@@ -3231,10 +3260,10 @@
View view = getChildAt(i);
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- row.setHeadsupDisappearRunning(false);
+ row.setHeadsUpAnimatingAway(false);
if (row.isSummaryWithChildren()) {
for (ExpandableNotificationRow child : row.getNotificationChildren()) {
- child.setHeadsupDisappearRunning(false);
+ child.setHeadsUpAnimatingAway(false);
}
}
}
@@ -3538,50 +3567,6 @@
}
}
- public void setOverflowContainer(NotificationOverflowContainer overFlowContainer) {
- int index = -1;
- if (mOverflowContainer != null) {
- index = indexOfChild(mOverflowContainer);
- removeView(mOverflowContainer);
- }
- mOverflowContainer = overFlowContainer;
- addView(mOverflowContainer, index);
- }
-
- public void updateOverflowContainerVisibility(boolean visible) {
- int oldVisibility = mOverflowContainer.willBeGone() ? GONE
- : mOverflowContainer.getVisibility();
- final int newVisibility = visible ? VISIBLE : GONE;
- if (oldVisibility != newVisibility) {
- Runnable onFinishedRunnable = new Runnable() {
- @Override
- public void run() {
- mOverflowContainer.setVisibility(newVisibility);
- mOverflowContainer.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(mOverflowContainer);
- }
- };
- if (!mAnimationsEnabled || !mIsExpanded) {
- mOverflowContainer.cancelAppearDrawing();
- onFinishedRunnable.run();
- } else if (newVisibility != GONE) {
- mOverflowContainer.performAddAnimation(0,
- StackStateAnimator.ANIMATION_DURATION_STANDARD);
- mOverflowContainer.setVisibility(newVisibility);
- mOverflowContainer.setWillBeGone(false);
- updateContentHeight();
- notifyHeightChangeListener(mOverflowContainer);
- } else {
- mOverflowContainer.performRemoveAnimation(
- StackStateAnimator.ANIMATION_DURATION_STANDARD,
- 0.0f,
- onFinishedRunnable);
- mOverflowContainer.setWillBeGone(true);
- }
- }
- }
-
public void updateDismissView(boolean visible) {
int oldVisibility = mDismissView.willBeGone() ? GONE : mDismissView.getVisibility();
int newVisibility = visible ? VISIBLE : GONE;
@@ -3663,7 +3648,8 @@
if (child.getVisibility() == GONE) {
continue;
}
- float bottom = child.getTranslationY() + child.getActualHeight();
+ float bottom = child.getTranslationY() + child.getActualHeight()
+ - child.getClipBottomAmount();
if (bottom > max) {
max = bottom;
}
@@ -3701,7 +3687,8 @@
// we are above a notification entirely let's abort
return false;
}
- boolean belowChild = touchY > childTop + child.getActualHeight();
+ boolean belowChild = touchY > childTop + child.getActualHeight()
+ - child.getClipBottomAmount();
if (child == mDismissView) {
if(!belowChild && !mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
touchY - childTop)) {
@@ -3795,7 +3782,7 @@
// fall through
case android.R.id.accessibilityActionScrollUp:
final int viewportHeight = getHeight() - mPaddingBottom - mTopPadding - mPaddingTop
- - mBottomStackPeekSize - mBottomStackSlowDownHeight;
+ - mShelf.getIntrinsicHeight();
final int targetScrollY = Math.max(0,
Math.min(mOwnScrollY + direction * viewportHeight, getScrollRange()));
if (targetScrollY != mOwnScrollY) {
@@ -3835,7 +3822,7 @@
mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
mNeedsAnimation = true;
if (!mIsExpanded && !isHeadsUp) {
- row.setHeadsupDisappearRunning(true);
+ row.setHeadsUpAnimatingAway(true);
}
requestChildrenUpdate();
}
@@ -3885,9 +3872,9 @@
public void setAnimationRunning(boolean animationRunning) {
if (animationRunning != mAnimationRunning) {
if (animationRunning) {
- getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
+ getViewTreeObserver().addOnPreDrawListener(mRunningAnimationUpdater);
} else {
- getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
+ getViewTreeObserver().removeOnPreDrawListener(mRunningAnimationUpdater);
}
mAnimationRunning = animationRunning;
updateContinuousShadowDrawing();
@@ -3910,9 +3897,13 @@
}
}
- public void setParentFadingOut(boolean fadingOut) {
- if (fadingOut != mParentFadingOut) {
- mParentFadingOut = fadingOut;
+ public void setParentNotFullyVisible(boolean parentNotFullyVisible) {
+ if (mScrimController == null) {
+ // we're not set up yet.
+ return;
+ }
+ if (parentNotFullyVisible != mParentNotFullyVisible) {
+ mParentNotFullyVisible = parentNotFullyVisible;
updateFadingState();
}
}
@@ -3949,6 +3940,45 @@
}
}
+ public void setShelf(NotificationShelf shelf) {
+ int index = -1;
+ if (mShelf != null) {
+ index = indexOfChild(mShelf);
+ removeView(mShelf);
+ }
+ mShelf = shelf;
+ addView(mShelf, index);
+ mAmbientState.setShelf(shelf);
+ mStateAnimator.setShelf(shelf);
+ shelf.bind(mAmbientState, this);
+ }
+
+ public NotificationShelf getNotificationShelf() {
+ return mShelf;
+ }
+
+ public void setMaxDisplayedNotifications(int maxDisplayedNotifications) {
+ if (mMaxDisplayedNotifications != maxDisplayedNotifications) {
+ mMaxDisplayedNotifications = maxDisplayedNotifications;
+ updateContentHeight();
+ notifyHeightChangeListener(mShelf);
+ }
+ }
+
+ public int getMinExpansionHeight() {
+ return mShelf.getIntrinsicHeight() - (mShelf.getIntrinsicHeight() - mStatusBarHeight) / 2;
+ }
+
+ public void setInHeadsUpPinnedMode(boolean inHeadsUpPinnedMode) {
+ mInHeadsUpPinnedMode = inHeadsUpPinnedMode;
+ updateClipping();
+ }
+
+ public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
+ mHeadsUpAnimatingAway = headsUpAnimatingAway;
+ updateClipping();
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
deleted file mode 100644
index 1c37c35..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
+++ /dev/null
@@ -1,111 +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 com.android.systemui.statusbar.stack;
-
-import java.util.ArrayList;
-
-/**
- * A Functor which interpolates the stack distance linearly based on base values.
- * The base values are based on an interpolation between a linear function and a
- * quadratic function
- */
-public class PiecewiseLinearIndentationFunctor extends StackIndentationFunctor {
-
- private final ArrayList<Float> mBaseValues;
- private final float mLinearPart;
-
- /**
- * @param maxItemsInStack The maximum number of items which should be visible at the same time,
- * i.e the function returns totalTransitionDistance for the element with
- * index maxItemsInStack
- * @param peekSize The visual appearance of this is how far the cards in the stack peek
- * out below the top card and it is measured in real pixels.
- * Note that the visual appearance does not necessarily always correspond to
- * the actual visual distance below the top card but is a maximum,
- * achieved when the next card just starts transitioning into the stack and
- * the stack is full.
- * If distanceToPeekStart is 0, we directly start at the peek, otherwise the
- * first element transitions between 0 and distanceToPeekStart.
- * Visualization:
- * --------------------------------------------------- ---
- * | | |
- * | FIRST ITEM | | <- distanceToPeekStart
- * | | |
- * |---------------------------------------------------| --- ---
- * |__________________SECOND ITEM______________________| | <- peekSize
- * |===================================================| _|_
- *
- * @param distanceToPeekStart The distance to the start of the peak.
- * @param linearPart The interpolation factor between the linear and the quadratic amount taken.
- * This factor must be somewhere in [0 , 1]
- */
- PiecewiseLinearIndentationFunctor(int maxItemsInStack,
- int peekSize,
- int distanceToPeekStart,
- float linearPart) {
- super(maxItemsInStack, peekSize, distanceToPeekStart);
- mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
- initBaseValues();
- mLinearPart = linearPart;
- }
-
- private void initBaseValues() {
- int sumOfSquares = getSumOfSquares(mMaxItemsInStack-1);
- int totalWeight = 0;
- mBaseValues.add(0.0f);
- for (int i = 0; i < mMaxItemsInStack - 1; i++) {
- totalWeight += (mMaxItemsInStack - i - 1) * (mMaxItemsInStack - i - 1);
- mBaseValues.add((float) totalWeight / sumOfSquares);
- }
- }
-
- /**
- * Get the sum of squares up to and including n, i.e sum(i * i, 1, n)
- *
- * @param n the maximum square to include
- * @return
- */
- private int getSumOfSquares(int n) {
- return n * (n + 1) * (2 * n + 1) / 6;
- }
-
- @Override
- public float getValue(float itemsBefore) {
- if (mStackStartsAtPeek) {
- // We directly start at the stack, so no initial interpolation.
- itemsBefore++;
- }
- if (itemsBefore < 0) {
- return 0;
- } else if (itemsBefore >= mMaxItemsInStack) {
- return mTotalTransitionDistance;
- }
- int below = (int) itemsBefore;
- float partialIn = itemsBefore - below;
-
- if (below == 0) {
- return mDistanceToPeekStart * partialIn;
- } else {
- float result = mDistanceToPeekStart;
- float progress = mBaseValues.get(below - 1) * (1 - partialIn)
- + mBaseValues.get(below) * partialIn;
- result += (progress * (1 - mLinearPart)
- + (itemsBefore - 1) / (mMaxItemsInStack - 1) * mLinearPart) * mPeekSize;
- return result;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
deleted file mode 100644
index 034eba6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
+++ /dev/null
@@ -1,84 +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 com.android.systemui.statusbar.stack;
-
-/**
- * A functor which can be queried for offset given the number of items before it.
- */
-public abstract class StackIndentationFunctor {
-
- protected int mTotalTransitionDistance;
- protected int mDistanceToPeekStart;
- protected int mMaxItemsInStack;
- protected int mPeekSize;
- protected boolean mStackStartsAtPeek;
-
- /**
- * @param maxItemsInStack The maximum number of items which should be visible at the same time,
- * i.e the function returns totalTransitionDistance for the element with
- * index maxItemsInStack
- * @param peekSize The visual appearance of this is how far the cards in the stack peek
- * out below the top card and it is measured in real pixels.
- * Note that the visual appearance does not necessarily always correspond to
- * the actual visual distance below the top card but is a maximum,
- * achieved when the next card just starts transitioning into the stack and
- * the stack is full.
- * If distanceToPeekStart is 0, we directly start at the peek, otherwise the
- * first element transitions between 0 and distanceToPeekStart.
- * Visualization:
- * --------------------------------------------------- ---
- * | | |
- * | FIRST ITEM | | <- distanceToPeekStart
- * | | |
- * |---------------------------------------------------| --- ---
- * |__________________SECOND ITEM______________________| | <- peekSize
- * |===================================================| _|_
- *
- * @param distanceToPeekStart The distance to the start of the peak.
- */
- StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) {
- mDistanceToPeekStart = distanceToPeekStart;
- mStackStartsAtPeek = mDistanceToPeekStart == 0;
- mMaxItemsInStack = maxItemsInStack;
- mPeekSize = peekSize;
- updateTotalTransitionDistance();
-
- }
-
- private void updateTotalTransitionDistance() {
- mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize;
- }
-
- public void setPeekSize(int mPeekSize) {
- this.mPeekSize = mPeekSize;
- updateTotalTransitionDistance();
- }
-
- public void setDistanceToPeekStart(int distanceToPeekStart) {
- mDistanceToPeekStart = distanceToPeekStart;
- mStackStartsAtPeek = mDistanceToPeekStart == 0;
- updateTotalTransitionDistance();
- }
-
- /**
- * Gets the offset of this Functor given a the quantity of items before it
- *
- * @param itemsBefore how many items are already in the stack before this element
- * @return the offset
- */
- public abstract float getValue(float itemsBefore);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index c9e4eac..7afc7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -22,9 +22,10 @@
import android.view.ViewGroup;
import com.android.systemui.R;
+import com.android.systemui.statusbar.DismissView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.NotificationUtils;
import java.util.ArrayList;
@@ -40,20 +41,13 @@
private static final String LOG_TAG = "StackScrollAlgorithm";
- private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
-
private int mPaddingBetweenElements;
private int mIncreasedPaddingBetweenElements;
private int mCollapsedSize;
- private int mBottomStackPeekSize;
- private int mZDistanceBetweenElements;
- private int mZBasicHeight;
-
- private StackIndentationFunctor mBottomStackIndentationFunctor;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
private boolean mIsExpanded;
- private int mBottomStackSlowDownLength;
+ private int mStatusBarHeight;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -63,29 +57,14 @@
initConstants(context);
}
- public int getBottomStackSlowDownLength() {
- return mBottomStackSlowDownLength + mPaddingBetweenElements;
- }
-
private void initConstants(Context context) {
- mPaddingBetweenElements = Math.max(1, context.getResources()
- .getDimensionPixelSize(R.dimen.notification_divider_height));
+ mPaddingBetweenElements = context.getResources().getDimensionPixelSize(
+ R.dimen.notification_divider_height);
mIncreasedPaddingBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
- mBottomStackPeekSize = context.getResources()
- .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
- mZDistanceBetweenElements = Math.max(1, context.getResources()
- .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
- mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
- mBottomStackSlowDownLength = context.getResources()
- .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
- mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
- MAX_ITEMS_IN_BOTTOM_STACK,
- mBottomStackPeekSize,
- getBottomStackSlowDownLength(),
- 0.5f);
+ mStatusBarHeight = context.getResources().getDimensionPixelSize(R.dimen.status_bar_height);
}
public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -107,7 +86,8 @@
handleDraggedViews(ambientState, resultState, algorithmState);
updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
updateClipping(resultState, algorithmState, ambientState);
- updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
+ updateSpeedBumpState(resultState, algorithmState, ambientState);
+ updateShelfState(resultState, ambientState);
getNotificationChildrenStates(resultState, algorithmState);
}
@@ -124,16 +104,22 @@
}
private void updateSpeedBumpState(StackScrollState resultState,
- StackScrollAlgorithmState algorithmState, int speedBumpIndex) {
+ StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
int childCount = algorithmState.visibleChildren.size();
+ int belowSpeedBump = ambientState.getSpeedBumpIndex();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
- StackViewState childViewState = resultState.getViewStateForView(child);
+ ExpandableViewState childViewState = resultState.getViewStateForView(child);
// The speed bump can also be gone, so equality needs to be taken when comparing
// indices.
- childViewState.belowSpeedBump = speedBumpIndex != -1 && i >= speedBumpIndex;
+ childViewState.belowSpeedBump = i >= belowSpeedBump;
}
+
+ }
+ private void updateShelfState(StackScrollState resultState, AmbientState ambientState) {
+ NotificationShelf shelf = ambientState.getShelf();
+ shelf.updateState(resultState, ambientState);
}
private void updateClipping(StackScrollState resultState,
@@ -144,7 +130,7 @@
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackViewState state = resultState.getViewStateForView(child);
+ ExpandableViewState state = resultState.getViewStateForView(child);
if (!child.mustStayOnScreen()) {
previousNotificationEnd = Math.max(drawStart, previousNotificationEnd);
previousNotificationStart = Math.max(drawStart, previousNotificationStart);
@@ -154,7 +140,7 @@
float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow)
&& ((ExpandableNotificationRow) child).isPinned();
- if (newYTranslation < previousNotificationEnd
+ if (!state.inShelf && newYTranslation < previousNotificationEnd
&& (!isHeadsUp || ambientState.isShadeExpanded())) {
// The previous view is overlapping on top, clip!
float overlapAmount = previousNotificationEnd - newYTranslation;
@@ -195,13 +181,13 @@
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
View child = algorithmState.visibleChildren.get(i);
- StackViewState childViewState = resultState.getViewStateForView(child);
+ ExpandableViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
childViewState.dark = dark;
childViewState.hideSensitive = hideSensitive;
boolean isActivatedChild = activatedChild == child;
if (dimmed && isActivatedChild) {
- childViewState.zTranslation += 2.0f * mZDistanceBetweenElements;
+ childViewState.zTranslation += 2.0f * ambientState.getZDistanceBetweenElements();
}
}
}
@@ -219,7 +205,7 @@
if (!draggedViews.contains(nextChild)) {
// only if the view is not dragged itself we modify its state to be fully
// visible
- StackViewState viewState = resultState.getViewStateForView(
+ ExpandableViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
if (ambientState.isShadeExpanded()) {
@@ -229,7 +215,7 @@
}
// Lets set the alpha to the one it currently has, as its currently being dragged
- StackViewState viewState = resultState.getViewStateForView(draggedView);
+ ExpandableViewState viewState = resultState.getViewStateForView(draggedView);
// The dragged child should keep the set alpha
viewState.alpha = draggedView.getAlpha();
}
@@ -241,8 +227,6 @@
*/
private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state,
AmbientState ambientState) {
- state.itemsInBottomStack = 0.0f;
- state.partialInBottom = 0.0f;
float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
int scrollY = ambientState.getScrollY();
@@ -263,6 +247,9 @@
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
+ if (v == ambientState.getShelf()) {
+ continue;
+ }
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
float increasedPadding = v.getIncreasedPaddingAmount();
if (increasedPadding != 0.0f) {
@@ -284,7 +271,7 @@
if (row.isSummaryWithChildren() && children != null) {
for (ExpandableNotificationRow childRow : children) {
if (childRow.getVisibility() != View.GONE) {
- StackViewState childState
+ ExpandableViewState childState
= resultState.getViewStateForView(childRow);
childState.notGoneIndex = notGoneIndex;
notGoneIndex++;
@@ -300,7 +287,7 @@
private int updateNotGoneIndex(StackScrollState resultState,
StackScrollAlgorithmState state, int notGoneIndex,
ExpandableView v) {
- StackViewState viewState = resultState.getViewStateForView(v);
+ ExpandableViewState viewState = resultState.getViewStateForView(v);
viewState.notGoneIndex = notGoneIndex;
state.visibleChildren.add(v);
notGoneIndex++;
@@ -317,72 +304,39 @@
private void updatePositionsForState(StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
- // The starting position of the bottom stack peek
- float bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize;
-
- // The position where the bottom stack starts.
- float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
-
// The y coordinate of the current child.
float currentYPosition = -algorithmState.scrollY;
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
currentYPosition = updateChild(i, resultState, algorithmState, ambientState,
- currentYPosition, bottomStackStart);
+ currentYPosition);
}
}
protected float updateChild(int i, StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState,
- float currentYPosition, float bottomStackStart) {
+ float currentYPosition) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackViewState childViewState = resultState.getViewStateForView(child);
- childViewState.location = StackViewState.LOCATION_UNKNOWN;
+ ExpandableViewState childViewState = resultState.getViewStateForView(child);
+ childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
- int collapsedHeight = child.getCollapsedHeight();
childViewState.yTranslation = currentYPosition;
- if (i == 0) {
- updateFirstChildHeight(child, childViewState, childHeight, ambientState);
- }
+ boolean isDismissView = child instanceof DismissView;
- // The y position after this element
- float nextYPosition = currentYPosition + childHeight +
- paddingAfterChild;
- if (nextYPosition >= bottomStackStart) {
- // Case 1:
- // We are in the bottom stack.
- if (currentYPosition >= bottomStackStart) {
- // According to the regular scroll view we are fully translated out of the
- // bottom of the screen so we are fully in the bottom stack
- updateStateForChildFullyInBottomStack(algorithmState,
- bottomStackStart, childViewState, collapsedHeight, ambientState, child);
- } else {
- // According to the regular scroll view we are currently translating out of /
- // into the bottom of the screen
- updateStateForChildTransitioningInBottom(algorithmState,
- bottomStackStart, child, currentYPosition,
- childViewState, childHeight);
- }
+ childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
+ if (isDismissView) {
+ childViewState.yTranslation = Math.min(childViewState.yTranslation,
+ ambientState.getInnerHeight() - childHeight);
} else {
- // Case 2:
- // We are in the regular scroll area.
- childViewState.location = StackViewState.LOCATION_MAIN_AREA;
- clampPositionToBottomStackStart(childViewState, childViewState.height, childHeight,
- ambientState);
+ clampPositionToShelf(childViewState, ambientState);
}
- if (i == 0 && ambientState.getScrollY() <= 0) {
- // The first card can get into the bottom stack if it's the only one
- // on the lockscreen which pushes it up. Let's make sure that doesn't happen and
- // it stays at the top
- childViewState.yTranslation = Math.max(0, childViewState.yTranslation);
- }
currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
if (currentYPosition <= 0) {
- childViewState.location = StackViewState.LOCATION_HIDDEN_TOP;
+ childViewState.location = ExpandableViewState.LOCATION_HIDDEN_TOP;
}
- if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
+ if (childViewState.location == ExpandableViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
@@ -393,12 +347,7 @@
protected int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
ExpandableView child) {
- Float paddingValue = algorithmState.increasedPaddingMap.get(child);
- return paddingValue == null
- ? mPaddingBetweenElements
- : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
- mIncreasedPaddingBetweenElements,
- paddingValue);
+ return algorithmState.getPaddingAfterChild(child);
}
private void updateHeadsUpStates(StackScrollState resultState,
@@ -414,22 +363,26 @@
if (!row.isHeadsUp()) {
break;
}
- StackViewState childState = resultState.getViewStateForView(row);
+ ExpandableViewState childState = resultState.getViewStateForView(row);
if (topHeadsUpEntry == null) {
topHeadsUpEntry = row;
- childState.location = StackViewState.LOCATION_FIRST_HUN;
+ childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
}
boolean isTopEntry = topHeadsUpEntry == row;
float unmodifiedEndLocation = childState.yTranslation + childState.height;
if (mIsExpanded) {
// Ensure that the heads up is always visible even when scrolled off
clampHunToTop(ambientState, row, childState);
- clampHunToMaxTranslation(ambientState, row, childState);
+ if (i == 0) {
+ // the first hun can't get off screen.
+ clampHunToMaxTranslation(ambientState, row, childState);
+ }
}
if (row.isPinned()) {
childState.yTranslation = Math.max(childState.yTranslation, 0);
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
- StackViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
+ childState.hidden = false;
+ ExpandableViewState topState = resultState.getViewStateForView(topHeadsUpEntry);
if (!isTopEntry && (!mIsExpanded
|| unmodifiedEndLocation < topState.yTranslation + topState.height)) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
@@ -439,11 +392,14 @@
- childState.height;
}
}
+ if (row.isHeadsUpAnimatingAway()) {
+ childState.hidden = false;
+ }
}
}
private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
- StackViewState childState) {
+ ExpandableViewState childState) {
float newTranslation = Math.max(ambientState.getTopPadding()
+ ambientState.getStackTranslation(), childState.yTranslation);
childState.height = (int) Math.max(childState.height - (newTranslation
@@ -452,7 +408,7 @@
}
private void clampHunToMaxTranslation(AmbientState ambientState, ExpandableNotificationRow row,
- StackViewState childState) {
+ ExpandableViewState childState) {
float newTranslation;
float bottomPosition = ambientState.getMaxHeadsUpTranslation() - row.getCollapsedHeight();
newTranslation = Math.min(childState.yTranslation, bottomPosition);
@@ -462,26 +418,23 @@
}
/**
- * Clamp the yTranslation of the child down such that its end is at most on the beginning of
- * the bottom stack.
+ * Clamp the height of the child down such that its end is at most on the beginning of
+ * the shelf.
*
* @param childViewState the view state of the child
- * @param childHeight the height of this child
- * @param minHeight the minumum Height of the View
+ * @param ambientState the ambient state
*/
- private void clampPositionToBottomStackStart(StackViewState childViewState,
- int childHeight, int minHeight, AmbientState ambientState) {
-
- int bottomStackStart = ambientState.getInnerHeight()
- - mBottomStackPeekSize - mBottomStackSlowDownLength;
- int childStart = bottomStackStart - childHeight;
- if (childStart < childViewState.yTranslation) {
- float newHeight = bottomStackStart - childViewState.yTranslation;
- if (newHeight < minHeight) {
- newHeight = minHeight;
- childViewState.yTranslation = bottomStackStart - minHeight;
- }
- childViewState.height = (int) newHeight;
+ private void clampPositionToShelf(ExpandableViewState childViewState,
+ AmbientState ambientState) {
+ int shelfStart = ambientState.getInnerHeight()
+ - ambientState.getShelf().getIntrinsicHeight();
+ childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
+ if (childViewState.yTranslation >= shelfStart) {
+ childViewState.hidden = true;
+ childViewState.inShelf = true;
+ }
+ if (!ambientState.isShadeExpanded()) {
+ childViewState.height = (int) (mStatusBarHeight - childViewState.yTranslation);
}
}
@@ -493,77 +446,6 @@
return child == null? mCollapsedSize : child.getHeight();
}
- private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
- float transitioningPositionStart, ExpandableView child, float currentYPosition,
- StackViewState childViewState, int childHeight) {
-
- // This is the transitioning element on top of bottom stack, calculate how far we are in.
- algorithmState.partialInBottom = 1.0f - (
- (transitioningPositionStart - currentYPosition) / (childHeight +
- getPaddingAfterChild(algorithmState, child)));
-
- // the offset starting at the transitionPosition of the bottom stack
- float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
- algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
- int newHeight = childHeight;
- if (childHeight > child.getCollapsedHeight()) {
- newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
- getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
- child.getCollapsedHeight());
- childViewState.height = newHeight;
- }
- childViewState.yTranslation = transitioningPositionStart + offset - newHeight
- - getPaddingAfterChild(algorithmState, child);
- childViewState.location = StackViewState.LOCATION_MAIN_AREA;
- }
-
- private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
- float transitioningPositionStart, StackViewState childViewState,
- int collapsedHeight, AmbientState ambientState, ExpandableView child) {
- float currentYPosition;
- algorithmState.itemsInBottomStack += 1.0f;
- if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
- // We are visually entering the bottom stack
- currentYPosition = transitioningPositionStart
- + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
- - getPaddingAfterChild(algorithmState, child);
- childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
- } else {
- // we are fully inside the stack
- if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
- childViewState.hidden = true;
- childViewState.shadowAlpha = 0.0f;
- } else if (algorithmState.itemsInBottomStack
- > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
- childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
- }
- childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
- currentYPosition = ambientState.getInnerHeight();
- }
- childViewState.height = collapsedHeight;
- childViewState.yTranslation = currentYPosition - collapsedHeight;
- }
-
-
- /**
- * Update the height of the first child i.e clamp it to the bottom stack
- *
- * @param child the child to update
- * @param childViewState the viewstate of the child
- * @param childHeight the height of the child
- * @param ambientState The ambient state of the algorithm
- */
- protected void updateFirstChildHeight(ExpandableView child, StackViewState childViewState,
- int childHeight, AmbientState ambientState) {
-
- // The starting position of the bottom stack peek
- int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
- mBottomStackSlowDownLength + ambientState.getScrollY();
- // Collapse and expand the first child while the shade is being expanded
- childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
- child.getCollapsedHeight());
- }
-
/**
* Calculate the Z positions for all children based on the number of items in both stacks and
* save it in the resultState
@@ -576,37 +458,19 @@
int childCount = algorithmState.visibleChildren.size();
float childrenOnTop = 0.0f;
for (int i = childCount - 1; i >= 0; i--) {
- updateChildZValue(i, childCount, childrenOnTop,
+ updateChildZValue(i, childrenOnTop,
resultState, algorithmState, ambientState);
}
}
- protected void updateChildZValue(int i, int childCount, float childrenOnTop,
+ protected void updateChildZValue(int i, float childrenOnTop,
StackScrollState resultState, StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
ExpandableView child = algorithmState.visibleChildren.get(i);
- StackViewState childViewState = resultState.getViewStateForView(child);
- if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
- // We are in the bottom stack
- float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
- float zSubtraction;
- if (numItemsAbove <= 1.0f) {
- float factor = 0.2f;
- // Lets fade in slower to the threshold to make the shadow fade in look nicer
- if (numItemsAbove <= factor) {
- zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
- * numItemsAbove * (1.0f / factor);
- } else {
- zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
- + (numItemsAbove - factor) * (1.0f / (1.0f - factor))
- * (mZDistanceBetweenElements
- - FakeShadowView.SHADOW_SIBLING_TRESHOLD);
- }
- } else {
- zSubtraction = numItemsAbove * mZDistanceBetweenElements;
- }
- childViewState.zTranslation = mZBasicHeight - zSubtraction;
- } else if (child.mustStayOnScreen()
+ ExpandableViewState childViewState = resultState.getViewStateForView(child);
+ int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
+ float baseZ = ambientState.getBaseZHeight();
+ if (child.mustStayOnScreen()
&& childViewState.yTranslation < ambientState.getTopPadding()
+ ambientState.getStackTranslation()) {
if (childrenOnTop != 0.0f) {
@@ -616,37 +480,34 @@
+ ambientState.getStackTranslation() - childViewState.yTranslation;
childrenOnTop += Math.min(1.0f, overlap / childViewState.height);
}
- childViewState.zTranslation = mZBasicHeight
- + childrenOnTop * mZDistanceBetweenElements;
- } else {
- childViewState.zTranslation = mZBasicHeight;
- }
- }
-
- private boolean isMaxSizeInitialized(ExpandableView child) {
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- return row.isMaxExpandHeightInitialized();
- }
- return child == null || child.getWidth() != 0;
- }
-
- private View findFirstVisibleChild(ViewGroup container) {
- int childCount = container.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = container.getChildAt(i);
- if (child.getVisibility() != View.GONE) {
- return child;
+ childViewState.zTranslation = baseZ
+ + childrenOnTop * zDistanceBetweenElements;
+ } else if (i == 0 && child.isAboveShelf()) {
+ // In case this is a new view that has never been measured before, we don't want to
+ // elevate if we are currently expanded more then the notification
+ int shelfHeight = ambientState.getShelf().getIntrinsicHeight();
+ float shelfStart = ambientState.getInnerHeight()
+ - shelfHeight + ambientState.getTopPadding()
+ + ambientState.getStackTranslation();
+ float notificationEnd = childViewState.yTranslation + child.getPinnedHeadsUpHeight()
+ + mPaddingBetweenElements;
+ if (shelfStart > notificationEnd) {
+ childViewState.zTranslation = baseZ;
+ } else {
+ float factor = (notificationEnd - shelfStart) / shelfHeight;
+ factor = Math.min(factor, 1.0f);
+ childViewState.zTranslation = baseZ + factor * zDistanceBetweenElements;
}
+ } else {
+ childViewState.zTranslation = baseZ;
}
- return null;
}
public void setIsExpanded(boolean isExpanded) {
this.mIsExpanded = isExpanded;
}
- protected class StackScrollAlgorithmState {
+ public class StackScrollAlgorithmState {
/**
* The scroll position of the algorithm
@@ -654,16 +515,6 @@
public int scrollY;
/**
- * The quantity of items which are in the bottom stack.
- */
- public float itemsInBottomStack;
-
- /**
- * how far in is the element currently transitioning into the bottom stack
- */
- public float partialInBottom;
-
- /**
* The children from the host view which are not gone.
*/
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
@@ -673,6 +524,15 @@
* no increased padding, a value of 1 means full padding.
*/
public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>();
+
+ public int getPaddingAfterChild(ExpandableView child) {
+ Float paddingValue = increasedPaddingMap.get(child);
+ return paddingValue == null
+ ? mPaddingBetweenElements
+ : (int) NotificationUtils.interpolate(mPaddingBetweenElements,
+ mIncreasedPaddingBetweenElements,
+ paddingValue);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8f0cd8e..e3c746b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -21,8 +21,6 @@
import android.view.ViewGroup;
import com.android.systemui.R;
-import com.android.systemui.statusbar.DismissView;
-import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
@@ -38,14 +36,11 @@
private static final String CHILD_NOT_FOUND_TAG = "StackScrollStateNoSuchChild";
private final ViewGroup mHostView;
- private WeakHashMap<ExpandableView, StackViewState> mStateMap;
- private final int mClearAllTopPadding;
+ private WeakHashMap<ExpandableView, ExpandableViewState> mStateMap;
public StackScrollState(ViewGroup hostView) {
mHostView = hostView;
mStateMap = new WeakHashMap<>();
- mClearAllTopPadding = hostView.getContext().getResources().getDimensionPixelSize(
- R.dimen.clear_all_padding_top);
}
public ViewGroup getHostView() {
@@ -73,9 +68,9 @@
}
private void resetViewState(ExpandableView view) {
- StackViewState viewState = mStateMap.get(view);
+ ExpandableViewState viewState = mStateMap.get(view);
if (viewState == null) {
- viewState = new StackViewState();
+ viewState = view.createNewViewState(this);
mStateMap.put(view, viewState);
}
// initialize with the default values of the view
@@ -84,10 +79,14 @@
viewState.alpha = 1f;
viewState.shadowAlpha = 1f;
viewState.notGoneIndex = -1;
+ viewState.xTranslation = view.getTranslationX();
viewState.hidden = false;
+ viewState.scaleX = view.getScaleX();
+ viewState.scaleY = view.getScaleY();
+ viewState.inShelf = false;
}
- public StackViewState getViewStateForView(View requestedView) {
+ public ExpandableViewState getViewStateForView(View requestedView) {
return mStateMap.get(requestedView);
}
@@ -103,130 +102,16 @@
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
ExpandableView child = (ExpandableView) mHostView.getChildAt(i);
- StackViewState state = mStateMap.get(child);
- if (!applyState(child, state)) {
+ ExpandableViewState state = mStateMap.get(child);
+ if (state == null) {
+ Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
+ "to the hostView");
continue;
}
- if (child instanceof DismissView) {
- DismissView dismissView = (DismissView) child;
- boolean visible = state.clipTopAmount < mClearAllTopPadding;
- dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
- } else if (child instanceof EmptyShadeView) {
- EmptyShadeView emptyShadeView = (EmptyShadeView) child;
- boolean visible = state.clipTopAmount <= 0;
- emptyShadeView.performVisibilityAnimation(
- visible && !emptyShadeView.willBeGone());
+ if (state.gone) {
+ continue;
}
- }
- }
-
- /**
- * Applies a {@link StackViewState} to an {@link ExpandableView}.
- *
- * @return whether the state was applied correctly
- */
- public boolean applyState(ExpandableView view, StackViewState state) {
- if (state == null) {
- Log.wtf(CHILD_NOT_FOUND_TAG, "No child state was found when applying this state " +
- "to the hostView");
- return false;
- }
- if (state.gone) {
- return false;
- }
- applyViewState(view, state);
-
- int height = view.getActualHeight();
- int newHeight = state.height;
-
- // apply height
- if (height != newHeight) {
- view.setActualHeight(newHeight, false /* notifyListeners */);
- }
-
- float shadowAlpha = view.getShadowAlpha();
- float newShadowAlpha = state.shadowAlpha;
-
- // apply shadowAlpha
- if (shadowAlpha != newShadowAlpha) {
- view.setShadowAlpha(newShadowAlpha);
- }
-
- // apply dimming
- view.setDimmed(state.dimmed, false /* animate */);
-
- // apply hiding sensitive
- view.setHideSensitive(
- state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
-
- // apply speed bump state
- view.setBelowSpeedBump(state.belowSpeedBump);
-
- // apply dark
- view.setDark(state.dark, false /* animate */, 0 /* delay */);
-
- // apply clipping
- float oldClipTopAmount = view.getClipTopAmount();
- if (oldClipTopAmount != state.clipTopAmount) {
- view.setClipTopAmount(state.clipTopAmount);
- }
- if (view instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- if (state.isBottomClipped) {
- row.setClipToActualHeight(true);
- }
- row.applyChildrenState(this);
- }
- return true;
- }
-
- /**
- * Applies a {@link ViewState} to a normal view.
- */
- public void applyViewState(View view, ViewState state) {
- float alpha = view.getAlpha();
- float yTranslation = view.getTranslationY();
- float xTranslation = view.getTranslationX();
- float zTranslation = view.getTranslationZ();
- float newAlpha = state.alpha;
- float newYTranslation = state.yTranslation;
- float newZTranslation = state.zTranslation;
- boolean becomesInvisible = newAlpha == 0.0f || state.hidden;
- if (alpha != newAlpha && xTranslation == 0) {
- // apply layer type
- boolean becomesFullyVisible = newAlpha == 1.0f;
- boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
- && view.hasOverlappingRendering();
- int layerType = view.getLayerType();
- int newLayerType = newLayerTypeIsHardware
- ? View.LAYER_TYPE_HARDWARE
- : View.LAYER_TYPE_NONE;
- if (layerType != newLayerType) {
- view.setLayerType(newLayerType, null);
- }
-
- // apply alpha
- view.setAlpha(newAlpha);
- }
-
- // apply visibility
- int oldVisibility = view.getVisibility();
- int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
- if (newVisibility != oldVisibility) {
- if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
- // We don't want views to change visibility when they are animating to GONE
- view.setVisibility(newVisibility);
- }
- }
-
- // apply yTranslation
- if (yTranslation != newYTranslation) {
- view.setTranslationY(newYTranslation);
- }
-
- // apply zTranslation
- if (zTranslation != newZTranslation) {
- view.setTranslationZ(newZTranslation);
+ state.applyToView(child);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 3804b42..1f29b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,9 +18,8 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
@@ -29,7 +28,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.NotificationShelf;
import java.util.ArrayList;
import java.util.HashSet;
@@ -54,28 +53,10 @@
public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
public static final int ANIMATION_DELAY_HEADS_UP = 120;
- private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
- private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
- private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
- private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
- private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
- private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
- private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
- private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
- private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
- private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
- private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
- private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
- private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
- private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
- private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
- private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
- private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
- private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
-
private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
- private final StackViewState mTmpState = new StackViewState();
+ private final ExpandableViewState mTmpState = new ExpandableViewState();
+ private final AnimationProperties mAnimationProperties;
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
@@ -95,6 +76,7 @@
private int mHeadsUpAppearHeightBottom;
private boolean mShadeExpanded;
private ArrayList<View> mChildrenToClearFromOverlay = new ArrayList<>();
+ private NotificationShelf mShelf;
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
@@ -102,6 +84,30 @@
hostLayout.getContext().getResources().getDimensionPixelSize(
R.dimen.go_to_full_shade_appearing_translation);
mHeadsUpAppearInterpolator = new HeadsUpAppearInterpolator();
+ mAnimationProperties = new AnimationProperties() {
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+
+ @Override
+ public AnimatorListenerAdapter getAnimationFinishListener() {
+ return getGlobalAnimationFinishedListener();
+ }
+
+ @Override
+ public boolean wasAdded(View view) {
+ return mNewAddChildren.contains(view);
+ }
+
+ @Override
+ public Interpolator getCustomInterpolator(View child, Property property) {
+ if (mHeadsUpAppearChildren.contains(child) && View.TRANSLATION_Y.equals(property)) {
+ return mHeadsUpAppearInterpolator;
+ }
+ return null;
+ }
+ };
}
public boolean isRunning() {
@@ -122,13 +128,14 @@
for (int i = 0; i < childCount; i++) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
- StackViewState viewState = finalState.getViewStateForView(child);
+ ExpandableViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE
|| applyWithoutAnimation(child, viewState, finalState)) {
continue;
}
- startStackAnimations(child, viewState, finalState, i, -1 /* fixedDelay */);
+ initAnimationProperties(finalState, child, viewState);
+ viewState.animateTo(child, mAnimationProperties);
}
if (!isRunning()) {
// no child has preformed any animation, lets finish
@@ -140,17 +147,47 @@
mNewAddChildren.clear();
}
+ private void initAnimationProperties(StackScrollState finalState, ExpandableView child,
+ ExpandableViewState viewState) {
+ boolean wasAdded = mAnimationProperties.wasAdded(child);
+ mAnimationProperties.duration = mCurrentLength;
+ adaptDurationWhenGoingToFullShade(child, viewState, wasAdded);
+ mAnimationProperties.delay = 0;
+ if (wasAdded || mAnimationFilter.hasDelays
+ && (viewState.yTranslation != child.getTranslationY()
+ || viewState.zTranslation != child.getTranslationZ()
+ || viewState.alpha != child.getAlpha()
+ || viewState.height != child.getActualHeight()
+ || viewState.clipTopAmount != child.getClipTopAmount()
+ || viewState.dark != child.isDark()
+ || viewState.shadowAlpha != child.getShadowAlpha())) {
+ mAnimationProperties.delay = mCurrentAdditionalDelay
+ + calculateChildAnimationDelay(viewState, finalState);
+ }
+ }
+
+ private void adaptDurationWhenGoingToFullShade(ExpandableView child,
+ ExpandableViewState viewState, boolean wasAdded) {
+ if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
+ child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
+ float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
+ longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
+ mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
+ (long) (100 * longerDurationFactor);
+ }
+ }
+
/**
* Determines if a view should not perform an animation and applies it directly.
*
* @return true if no animation should be performed
*/
- private boolean applyWithoutAnimation(ExpandableView child, StackViewState viewState,
+ private boolean applyWithoutAnimation(ExpandableView child, ExpandableViewState viewState,
StackScrollState finalState) {
if (mShadeExpanded) {
return false;
}
- if (getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null) {
+ if (ViewState.isAnimatingY(child)) {
// A Y translation animation is running
return false;
}
@@ -162,7 +199,7 @@
// This is another headsUp which might move. Let's animate!
return false;
}
- finalState.applyState(child, viewState);
+ viewState.applyToView(child);
return true;
}
@@ -171,7 +208,7 @@
for (int i = childCount - 1; i >= 0; i--) {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
- StackViewState viewState = finalState.getViewStateForView(child);
+ ExpandableViewState viewState = finalState.getViewStateForView(child);
if (viewState == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -182,144 +219,7 @@
return -1;
}
-
- /**
- * Start an animation to the given {@link StackViewState}.
- *
- * @param child the child to start the animation on
- * @param viewState the {@link StackViewState} of the view to animate to
- * @param finalState the final state after the animation
- * @param i the index of the view; only relevant if the view is the speed bump and is
- * ignored otherwise
- * @param fixedDelay a fixed delay if desired or -1 if the delay should be calculated
- */
- public void startStackAnimations(final ExpandableView child, StackViewState viewState,
- StackScrollState finalState, int i, long fixedDelay) {
- boolean wasAdded = mNewAddChildren.contains(child);
- long duration = mCurrentLength;
- if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
- child.setTranslationY(child.getTranslationY() + mGoToFullShadeAppearingTranslation);
- float longerDurationFactor = viewState.notGoneIndex - mCurrentLastNotAddedIndex;
- longerDurationFactor = (float) Math.pow(longerDurationFactor, 0.7f);
- duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 +
- (long) (100 * longerDurationFactor);
- }
- boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
- boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
- boolean alphaChanging = viewState.alpha != child.getAlpha();
- boolean heightChanging = viewState.height != child.getActualHeight();
- boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
- boolean darkChanging = viewState.dark != child.isDark();
- boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
- boolean hasDelays = mAnimationFilter.hasDelays;
- boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging
- || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
- long delay = 0;
- if (fixedDelay != -1) {
- delay = fixedDelay;
- } else if (hasDelays && isDelayRelevant || wasAdded) {
- delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, finalState);
- }
-
- startViewAnimations(child, viewState, delay, duration);
-
- // start height animation
- if (heightChanging) {
- startHeightAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_HEIGHT);
- }
-
- // start shadow alpha animation
- if (shadowAlphaChanging) {
- startShadowAlphaAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_SHADOW_ALPHA);
- }
-
- // start top inset animation
- if (topInsetChanging) {
- startInsetAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TOP_INSET);
- }
-
- // start dimmed animation
- child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
-
- // apply speed bump state
- child.setBelowSpeedBump(viewState.belowSpeedBump);
-
- // start hiding sensitive animation
- child.setHideSensitive(viewState.hideSensitive, mAnimationFilter.animateHideSensitive,
- delay, duration);
-
- // start dark animation
- child.setDark(viewState.dark, mAnimationFilter.animateDark, delay);
-
- if (wasAdded) {
- child.performAddAnimation(delay, mCurrentLength);
- }
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- row.startChildAnimation(finalState, this, delay, duration);
- }
- }
-
- /**
- * Start an animation to a new {@link ViewState}.
- *
- * @param child the child to start the animation on
- * @param viewState the {@link StackViewState} of the view to animate to
- * @param delay a fixed delay
- * @param duration the duration of the animation
- */
- public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
- boolean wasVisible = child.getVisibility() == View.VISIBLE;
- final float alpha = viewState.alpha;
- if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
- && !viewState.gone && !viewState.hidden) {
- child.setVisibility(View.VISIBLE);
- }
- boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
- boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
- float childAlpha = child.getAlpha();
- boolean alphaChanging = viewState.alpha != childAlpha;
- if (child instanceof ExpandableView) {
- // We don't want views to change visibility when they are animating to GONE
- alphaChanging &= !((ExpandableView) child).willBeGone();
- }
-
- // start translationY animation
- if (yTranslationChanging) {
- startYTranslationAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
- }
-
- // start translationZ animation
- if (zTranslationChanging) {
- startZTranslationAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
- }
-
- // start alpha animation
- if (alphaChanging && child.getTranslationX() == 0) {
- startAlphaAnimation(child, viewState, duration, delay);
- } else {
- abortAnimation(child, TAG_ANIMATOR_ALPHA);
- }
- }
-
- private void abortAnimation(View child, int animatorTag) {
- Animator previousAnimator = getChildTag(child, animatorTag);
- if (previousAnimator != null) {
- previousAnimator.cancel();
- }
- }
-
- private long calculateChildAnimationDelay(StackViewState viewState,
+ private long calculateChildAnimationDelay(ExpandableViewState viewState,
StackScrollState finalState) {
if (mAnimationFilter.hasDarkEvent) {
return calculateDelayDark(viewState);
@@ -374,7 +274,7 @@
return minDelay;
}
- private long calculateDelayDark(StackViewState viewState) {
+ private long calculateDelayDark(ExpandableViewState viewState) {
int referenceIndex;
if (mAnimationFilter.darkAnimationOriginIndex ==
NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE) {
@@ -388,400 +288,19 @@
return Math.abs(referenceIndex - viewState.notGoneIndex) * ANIMATION_DELAY_PER_ELEMENT_DARK;
}
- private long calculateDelayGoToFullShade(StackViewState viewState) {
+ private long calculateDelayGoToFullShade(ExpandableViewState viewState) {
+ int shelfIndex = mShelf.getNotGoneIndex();
float index = viewState.notGoneIndex;
+ long result = 0;
+ if (index > shelfIndex) {
+ float diff = index - shelfIndex;
+ diff = (float) Math.pow(diff, 0.7f);
+ result += (long) (diff * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE * 0.25);
+ index = shelfIndex;
+ }
index = (float) Math.pow(index, 0.7f);
- return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
- }
-
- private void startShadowAlphaAnimation(final ExpandableView child,
- StackViewState viewState, long duration, long delay) {
- Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
- Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
- float newEndValue = viewState.shadowAlpha;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
- if (!mAnimationFilter.animateShadowAlpha) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
- child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setShadowAlpha(newEndValue);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setShadowAlpha((float) animation.getAnimatedValue());
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
- child.setTag(TAG_START_SHADOW_ALPHA, null);
- child.setTag(TAG_END_SHADOW_ALPHA, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
- child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
- child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
- }
-
- private void startHeightAnimation(final ExpandableView child,
- StackViewState viewState, long duration, long delay) {
- Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
- Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
- int newEndValue = viewState.height;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
- if (!mAnimationFilter.animateHeight) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- int relativeDiff = newEndValue - previousEndValue;
- int newStartValue = previousStartValue + relativeDiff;
- values[0].setIntValues(newStartValue, newEndValue);
- child.setTag(TAG_START_HEIGHT, newStartValue);
- child.setTag(TAG_END_HEIGHT, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setActualHeight(newEndValue, false);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setActualHeight((int) animation.getAnimatedValue(),
- false /* notifyListeners */);
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- boolean mWasCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_HEIGHT, null);
- child.setTag(TAG_START_HEIGHT, null);
- child.setTag(TAG_END_HEIGHT, null);
- child.setActualHeightAnimating(false);
- if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
- ((ExpandableNotificationRow) child).setGroupExpansionChanging(
- false /* isExpansionChanging */);
- }
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mWasCancelled = false;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_HEIGHT, animator);
- child.setTag(TAG_START_HEIGHT, child.getActualHeight());
- child.setTag(TAG_END_HEIGHT, newEndValue);
- child.setActualHeightAnimating(true);
- }
-
- private void startInsetAnimation(final ExpandableView child,
- StackViewState viewState, long duration, long delay) {
- Integer previousStartValue = getChildTag(child, TAG_START_TOP_INSET);
- Integer previousEndValue = getChildTag(child, TAG_END_TOP_INSET);
- int newEndValue = viewState.clipTopAmount;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TOP_INSET);
- if (!mAnimationFilter.animateTopInset) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- int relativeDiff = newEndValue - previousEndValue;
- int newStartValue = previousStartValue + relativeDiff;
- values[0].setIntValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TOP_INSET, newStartValue);
- child.setTag(TAG_END_TOP_INSET, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setClipTopAmount(newEndValue);
- return;
- }
- }
-
- ValueAnimator animator = ValueAnimator.ofInt(child.getClipTopAmount(), newEndValue);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- child.setClipTopAmount((int) animation.getAnimatedValue());
- }
- });
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_TOP_INSET, null);
- child.setTag(TAG_START_TOP_INSET, null);
- child.setTag(TAG_END_TOP_INSET, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TOP_INSET, animator);
- child.setTag(TAG_START_TOP_INSET, child.getClipTopAmount());
- child.setTag(TAG_END_TOP_INSET, newEndValue);
- }
-
- private void startAlphaAnimation(final View child,
- final ViewState viewState, long duration, long delay) {
- Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
- Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
- final float newEndValue = viewState.alpha;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
- if (!mAnimationFilter.animateAlpha) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_ALPHA, newStartValue);
- child.setTag(TAG_END_ALPHA, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setAlpha(newEndValue);
- if (newEndValue == 0) {
- child.setVisibility(View.INVISIBLE);
- }
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
- child.getAlpha(), newEndValue);
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- // Handle layer type
- child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- animator.addListener(new AnimatorListenerAdapter() {
- public boolean mWasCancelled;
-
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setLayerType(View.LAYER_TYPE_NONE, null);
- if (newEndValue == 0 && !mWasCancelled) {
- child.setVisibility(View.INVISIBLE);
- }
- // remove the tag when the animation is finished
- child.setTag(TAG_ANIMATOR_ALPHA, null);
- child.setTag(TAG_START_ALPHA, null);
- child.setTag(TAG_END_ALPHA, null);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mWasCancelled = true;
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- mWasCancelled = false;
- }
- });
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
-
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_ALPHA, animator);
- child.setTag(TAG_START_ALPHA, child.getAlpha());
- child.setTag(TAG_END_ALPHA, newEndValue);
- }
-
- private void startZTranslationAnimation(final View child,
- final ViewState viewState, long duration, long delay) {
- Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
- Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
- float newEndValue = viewState.zTranslation;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
- if (!mAnimationFilter.animateZ) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
- child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setTranslationZ(newEndValue);
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
- child.getTranslationZ(), newEndValue);
- animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
- child.setTag(TAG_START_TRANSLATION_Z, null);
- child.setTag(TAG_END_TRANSLATION_Z, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
- child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
- child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
- }
-
- private void startYTranslationAnimation(final View child,
- ViewState viewState, long duration, long delay) {
- Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
- Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
- float newEndValue = viewState.yTranslation;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
- if (!mAnimationFilter.animateY) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
- child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setTranslationY(newEndValue);
- return;
- }
- }
-
- ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
- child.getTranslationY(), newEndValue);
- Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
- mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN;
- animator.setInterpolator(interpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- if (delay > 0 && (previousAnimator == null
- || previousAnimator.getAnimatedFraction() == 0)) {
- animator.setStartDelay(delay);
- }
- animator.addListener(getGlobalAnimationFinishedListener());
- final boolean isHeadsUpDisappear = mHeadsUpDisappearChildren.contains(child);
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- HeadsUpManager.setIsClickedNotification(child, false);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
- child.setTag(TAG_START_TRANSLATION_Y, null);
- child.setTag(TAG_END_TRANSLATION_Y, null);
- if (isHeadsUpDisappear) {
- ((ExpandableNotificationRow) child).setHeadsupDisappearRunning(false);
- }
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
- child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
- child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
- }
-
- private void startAnimator(ValueAnimator animator) {
- mAnimatorSet.add(animator);
- animator.start();
+ result += (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
+ return result;
}
/**
@@ -814,33 +333,11 @@
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
+ mAnimatorSet.add(animation);
}
};
}
- public static <T> T getChildTag(View child, int tag) {
- return (T) child.getTag(tag);
- }
-
- /**
- * Cancel the previous animator and get the duration of the new animation.
- *
- * @param duration the new duration
- * @param previousAnimator the animator which was running before
- * @return the new duration
- */
- private long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
- long newDuration = duration;
- if (previousAnimator != null) {
- // We take either the desired length of the new animation or the remaining time of
- // the previous animator, whichever is longer.
- newDuration = Math.max(previousAnimator.getDuration()
- - previousAnimator.getCurrentPlayTime(), newDuration);
- previousAnimator.cancel();
- }
- return newDuration;
- }
-
private void onAnimationFinished() {
mHostLayout.onChildAnimationFinished();
for (View v : mChildrenToClearFromOverlay) {
@@ -864,25 +361,25 @@
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD) {
// This item is added, initialize it's properties.
- StackViewState viewState = finalState
+ ExpandableViewState viewState = finalState
.getViewStateForView(changingView);
if (viewState == null) {
// The position for this child was never generated, let's continue.
continue;
}
- finalState.applyState(changingView, viewState);
+ viewState.applyToView(changingView);
mNewAddChildren.add(changingView);
} else if (event.animationType ==
NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE) {
- if (changingView.getVisibility() == View.GONE) {
+ if (changingView.getVisibility() != View.VISIBLE) {
removeFromOverlay(changingView);
continue;
}
// Find the amount to translate up. This is needed in order to understand the
// direction of the remove animation (either downwards or upwards)
- StackViewState viewState = finalState
+ ExpandableViewState viewState = finalState
.getViewStateForView(event.viewAfterChangingView);
int actualHeight = changingView.getActualHeight();
// upwards by default
@@ -920,7 +417,7 @@
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR) {
// This item is added, initialize it's properties.
- StackViewState viewState = finalState.getViewStateForView(changingView);
+ ExpandableViewState viewState = finalState.getViewStateForView(changingView);
mTmpState.copyFrom(viewState);
if (event.headsUpFromBottom) {
mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
@@ -928,7 +425,7 @@
mTmpState.yTranslation = -mTmpState.height;
}
mHeadsUpAppearChildren.add(changingView);
- finalState.applyState(changingView, mTmpState);
+ mTmpState.applyToView(changingView);
} else if (event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
event.animationType == NotificationStackScrollLayout
@@ -942,12 +439,13 @@
// We temporarily enable Y animations, the real filter will be combined
// afterwards anyway
mAnimationFilter.animateY = true;
- startViewAnimations(changingView, mTmpState,
+ mAnimationProperties.delay =
event.animationType == NotificationStackScrollLayout
.AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
- ? ANIMATION_DELAY_HEADS_UP
- : 0,
- ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
+ ? ANIMATION_DELAY_HEADS_UP
+ : 0;
+ mAnimationProperties.duration = ANIMATION_DURATION_HEADS_UP_DISAPPEAR;
+ mTmpState.animateTo(changingView, mAnimationProperties);
mChildrenToClearFromOverlay.add(changingView);
}
}
@@ -1007,38 +505,6 @@
}
}
- /**
- * Get the end value of the height animation running on a view or the actualHeight
- * if no animation is running.
- */
- public static int getFinalActualHeight(ExpandableView view) {
- if (view == null) {
- return 0;
- }
- ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT);
- if (heightAnimator == null) {
- return view.getActualHeight();
- } else {
- return getChildTag(view, TAG_END_HEIGHT);
- }
- }
-
- /**
- * Get the end value of the yTranslation animation running on a view or the yTranslation
- * if no animation is running.
- */
- public static float getFinalTranslationY(View view) {
- if (view == null) {
- return 0;
- }
- ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
- if (yAnimator == null) {
- return view.getTranslationY();
- } else {
- return getChildTag(view, TAG_END_TRANSLATION_Y);
- }
- }
-
public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
}
@@ -1046,4 +512,8 @@
public void setShadeExpanded(boolean shadeExpanded) {
mShadeExpanded = shadeExpanded;
}
+
+ public void setShelf(NotificationShelf shelf) {
+ mShelf = shelf;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
deleted file mode 100644
index ecdee4e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ /dev/null
@@ -1,82 +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.systemui.statusbar.stack;
-
-/**
-* A state of an expandable view
-*/
-public class StackViewState extends ViewState {
-
- // These are flags such that we can create masks for filtering.
-
- public static final int LOCATION_UNKNOWN = 0x00;
- public static final int LOCATION_FIRST_HUN = 0x01;
- public static final int LOCATION_HIDDEN_TOP = 0x02;
- public static final int LOCATION_MAIN_AREA = 0x04;
- public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x08;
- public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x10;
- /** The view isn't layouted at all. */
- public static final int LOCATION_GONE = 0x40;
-
- public int height;
- public boolean dimmed;
- public boolean dark;
- public boolean hideSensitive;
- public boolean belowSpeedBump;
- public float shadowAlpha;
-
- /**
- * How much the child overlaps with the previous child on top. This is used to
- * show the background properly when the child on top is translating away.
- */
- public int clipTopAmount;
-
- /**
- * The index of the view, only accounting for views not equal to GONE
- */
- public int notGoneIndex;
-
- /**
- * The location this view is currently rendered at.
- *
- * <p>See <code>LOCATION_</code> flags.</p>
- */
- public int location;
-
- /**
- * Whether a child in a group is being clipped at the bottom.
- */
- public boolean isBottomClipped;
-
- @Override
- public void copyFrom(ViewState viewState) {
- super.copyFrom(viewState);
- if (viewState instanceof StackViewState) {
- StackViewState svs = (StackViewState) viewState;
- height = svs.height;
- dimmed = svs.dimmed;
- shadowAlpha = svs.shadowAlpha;
- dark = svs.dark;
- hideSensitive = svs.hideSensitive;
- belowSpeedBump = svs.belowSpeedBump;
- clipTopAmount = svs.clipTopAmount;
- notGoneIndex = svs.notGoneIndex;
- location = svs.location;
- isBottomClipped = svs.isBottomClipped;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 5beaac3..8a5ddd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -16,7 +16,18 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
/**
* A state of a view. This can be used to apply a set of view properties to a view with
@@ -25,25 +36,519 @@
*/
public class ViewState {
+ /**
+ * Some animation properties that can be used to update running animations but not creating
+ * any new ones.
+ */
+ protected static final AnimationProperties NO_NEW_ANIMATIONS = new AnimationProperties() {
+ AnimationFilter mAnimationFilter = new AnimationFilter();
+ @Override
+ public AnimationFilter getAnimationFilter() {
+ return mAnimationFilter;
+ }
+ };
+ private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
+ private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+ private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
+ private static final int TAG_END_TRANSLATION_X = R.id.translation_x_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
+ private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+ private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
+ private static final int TAG_START_TRANSLATION_X = R.id.translation_x_animator_start_value_tag;
+ private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+ private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+ private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+
public float alpha;
+ public float xTranslation;
public float yTranslation;
public float zTranslation;
public boolean gone;
public boolean hidden;
+ public float scaleX = 1.0f;
+ public float scaleY = 1.0f;
public void copyFrom(ViewState viewState) {
alpha = viewState.alpha;
+ xTranslation = viewState.xTranslation;
yTranslation = viewState.yTranslation;
zTranslation = viewState.zTranslation;
gone = viewState.gone;
hidden = viewState.hidden;
+ scaleX = viewState.scaleX;
+ scaleY = viewState.scaleY;
}
public void initFrom(View view) {
alpha = view.getAlpha();
+ xTranslation = view.getTranslationX();
yTranslation = view.getTranslationY();
zTranslation = view.getTranslationZ();
gone = view.getVisibility() == View.GONE;
hidden = false;
+ scaleX = view.getScaleX();
+ scaleY = view.getScaleY();
+ }
+
+ /**
+ * Applies a {@link ViewState} to a normal view.
+ */
+ public void applyToView(View view) {
+ if (this.gone) {
+ // don't do anything with it
+ return;
+ }
+ boolean becomesInvisible = this.alpha == 0.0f || this.hidden;
+ boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
+ if (animatingAlpha) {
+ updateAlphaAnimation(view);
+ } else if (view.getAlpha() != this.alpha) {
+ // apply layer type
+ boolean becomesFullyVisible = this.alpha == 1.0f;
+ boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
+ && view.hasOverlappingRendering();
+ int layerType = view.getLayerType();
+ int newLayerType = newLayerTypeIsHardware
+ ? View.LAYER_TYPE_HARDWARE
+ : View.LAYER_TYPE_NONE;
+ if (layerType != newLayerType) {
+ view.setLayerType(newLayerType, null);
+ }
+
+ // apply alpha
+ view.setAlpha(this.alpha);
+ }
+
+ // apply visibility
+ int oldVisibility = view.getVisibility();
+ int newVisibility = becomesInvisible ? View.INVISIBLE : View.VISIBLE;
+ if (newVisibility != oldVisibility) {
+ if (!(view instanceof ExpandableView) || !((ExpandableView) view).willBeGone()) {
+ // We don't want views to change visibility when they are animating to GONE
+ view.setVisibility(newVisibility);
+ }
+ }
+
+ // apply xTranslation
+ boolean animatingX = isAnimating(view, TAG_ANIMATOR_TRANSLATION_X);
+ if (animatingX) {
+ updateAnimationX(view);
+ } else if (view.getTranslationX() != this.xTranslation){
+ view.setTranslationX(this.xTranslation);
+ }
+
+ // apply yTranslation
+ boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y);
+ if (animatingY) {
+ updateAnimationY(view);
+ } else if (view.getTranslationY() != this.yTranslation) {
+ view.setTranslationY(this.yTranslation);
+ }
+
+ // apply zTranslation
+ boolean animatingZ = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z);
+ if (animatingZ) {
+ updateAnimationZ(view);
+ } else if (view.getTranslationZ() != this.zTranslation) {
+ view.setTranslationZ(this.zTranslation);
+ }
+
+ // apply scaleX
+ if (view.getScaleX() != this.scaleX) {
+ view.setScaleX(this.scaleX);
+ }
+
+ // apply scaleY
+ if (view.getScaleY() != this.scaleY) {
+ view.setScaleY(this.scaleY);
+ }
+ }
+
+ private boolean isAnimating(View view, int tag) {
+ return getChildTag(view, tag) != null;
+ }
+
+ /**
+ * Start an animation to this viewstate
+ * @param child the view to animate
+ * @param animationProperties the properties of the animation
+ */
+ public void animateTo(View child, AnimationProperties animationProperties) {
+ boolean wasVisible = child.getVisibility() == View.VISIBLE;
+ final float alpha = this.alpha;
+ if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
+ && !this.gone && !this.hidden) {
+ child.setVisibility(View.VISIBLE);
+ }
+ float childAlpha = child.getAlpha();
+ boolean alphaChanging = this.alpha != childAlpha;
+ if (child instanceof ExpandableView) {
+ // We don't want views to change visibility when they are animating to GONE
+ alphaChanging &= !((ExpandableView) child).willBeGone();
+ }
+
+ // start translationX animation
+ if (child.getTranslationX() != this.xTranslation) {
+ startXTranslationAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_X);
+ }
+
+ // start translationY animation
+ if (child.getTranslationY() != this.yTranslation) {
+ startYTranslationAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
+ }
+
+ // start translationZ animation
+ if (child.getTranslationZ() != this.zTranslation) {
+ startZTranslationAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
+ }
+
+ // start alpha animation
+ if (alphaChanging) {
+ startAlphaAnimation(child, animationProperties);
+ } else {
+ abortAnimation(child, TAG_ANIMATOR_ALPHA);
+ }
+ }
+
+ private void updateAlphaAnimation(View view) {
+ startAlphaAnimation(view, NO_NEW_ANIMATIONS);
+ }
+
+ private void startAlphaAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
+ Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
+ final float newEndValue = this.alpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_ALPHA, newStartValue);
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setAlpha(newEndValue);
+ if (newEndValue == 0) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
+ child.getAlpha(), newEndValue);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ // Handle layer type
+ child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mWasCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setLayerType(View.LAYER_TYPE_NONE, null);
+ if (newEndValue == 0 && !mWasCancelled) {
+ child.setVisibility(View.INVISIBLE);
+ }
+ // remove the tag when the animation is finished
+ child.setTag(TAG_ANIMATOR_ALPHA, null);
+ child.setTag(TAG_START_ALPHA, null);
+ child.setTag(TAG_END_ALPHA, null);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCancelled = true;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCancelled = false;
+ }
+ });
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_ALPHA, animator);
+ child.setTag(TAG_START_ALPHA, child.getAlpha());
+ child.setTag(TAG_END_ALPHA, newEndValue);
+ }
+
+ private void updateAnimationZ(View view) {
+ startZTranslationAnimation(view, NO_NEW_ANIMATIONS);
+ }
+
+ private void startZTranslationAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
+ float newEndValue = this.zTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateZ) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationZ(newEndValue);
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
+ child.getTranslationZ(), newEndValue);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+ child.setTag(TAG_START_TRANSLATION_Z, null);
+ child.setTag(TAG_END_TRANSLATION_Z, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
+ child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+ child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+ }
+
+ private void updateAnimationX(View view) {
+ startXTranslationAnimation(view, NO_NEW_ANIMATIONS);
+ }
+
+ private void startXTranslationAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_X);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_X);
+ float newEndValue = this.xTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_X);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateX) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_X, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_X, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationX(newEndValue);
+ return;
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_X,
+ child.getTranslationX(), newEndValue);
+ Interpolator customInterpolator = properties.getCustomInterpolator(child,
+ View.TRANSLATION_X);
+ Interpolator interpolator = customInterpolator != null ? customInterpolator
+ : Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_TRANSLATION_X, null);
+ child.setTag(TAG_START_TRANSLATION_X, null);
+ child.setTag(TAG_END_TRANSLATION_X, null);
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_X, animator);
+ child.setTag(TAG_START_TRANSLATION_X, child.getTranslationX());
+ child.setTag(TAG_END_TRANSLATION_X, newEndValue);
+ }
+
+ private void updateAnimationY(View view) {
+ startYTranslationAnimation(view, NO_NEW_ANIMATIONS);
+ }
+
+ private void startYTranslationAnimation(final View child, AnimationProperties properties) {
+ Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
+ Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
+ float newEndValue = this.yTranslation;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
+ AnimationFilter filter = properties.getAnimationFilter();
+ if (!filter.animateY) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setTranslationY(newEndValue);
+ return;
+ }
+ }
+
+ ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
+ child.getTranslationY(), newEndValue);
+ Interpolator customInterpolator = properties.getCustomInterpolator(child,
+ View.TRANSLATION_Y);
+ Interpolator interpolator = customInterpolator != null ? customInterpolator
+ : Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (properties.delay > 0 && (previousAnimator == null
+ || previousAnimator.getAnimatedFraction() == 0)) {
+ animator.setStartDelay(properties.delay);
+ }
+ AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ HeadsUpManager.setIsClickedNotification(child, false);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+ child.setTag(TAG_START_TRANSLATION_Y, null);
+ child.setTag(TAG_END_TRANSLATION_Y, null);
+ onYTranslationAnimationFinished();
+ }
+ });
+ startAnimator(animator, listener);
+ child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
+ child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+ child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+ }
+
+ protected void onYTranslationAnimationFinished() {
+ }
+
+ protected void startAnimator(Animator animator, AnimatorListenerAdapter listener) {
+ if (listener != null) {
+ // Even if there's a delay we'd want to notify it of the start immediately.
+ listener.onAnimationStart(animator);
+ }
+ animator.start();
+ }
+
+ public static <T> T getChildTag(View child, int tag) {
+ return (T) child.getTag(tag);
+ }
+
+ protected void abortAnimation(View child, int animatorTag) {
+ Animator previousAnimator = getChildTag(child, animatorTag);
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
+ }
+ }
+
+ /**
+ * Cancel the previous animator and get the duration of the new animation.
+ *
+ * @param duration the new duration
+ * @param previousAnimator the animator which was running before
+ * @return the new duration
+ */
+ protected long cancelAnimatorAndGetNewDuration(long duration, ValueAnimator previousAnimator) {
+ long newDuration = duration;
+ if (previousAnimator != null) {
+ // We take either the desired length of the new animation or the remaining time of
+ // the previous animator, whichever is longer.
+ newDuration = Math.max(previousAnimator.getDuration()
+ - previousAnimator.getCurrentPlayTime(), newDuration);
+ previousAnimator.cancel();
+ }
+ return newDuration;
+ }
+
+ /**
+ * Get the end value of the yTranslation animation running on a view or the yTranslation
+ * if no animation is running.
+ */
+ public static float getFinalTranslationY(View view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
+ if (yAnimator == null) {
+ return view.getTranslationY();
+ } else {
+ return getChildTag(view, TAG_END_TRANSLATION_Y);
+ }
+ }
+
+ public static boolean isAnimatingY(ExpandableView child) {
+ return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index c20cc84..ec0e4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -562,6 +562,22 @@
.sendToTarget();
mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
}
+
+ @Override
+ public void setA11yMode(int mode) {
+ if (D.BUG) Log.d(TAG, "setA11yMode to " + mode);
+ if (mDestroyed) return;
+ switch (mode) {
+ case VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME:
+ // "legacy" mode
+ break;
+ case VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME:
+ break;
+ default:
+ Log.e(TAG, "Invalid accessibility mode " + mode);
+ break;
+ }
+ }
}
private final class W extends Handler {
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 6e17cf4..b03189c 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
+ <uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
new file mode 100644
index 0000000..131a70b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.systemui.keyguard;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * runtest systemui -c com.android.systemui.keyguard.DismissCallbackRegistryTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DismissCallbackRegistryTest {
+
+ private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
+ private @Mock IKeyguardDismissCallback mMockCallback;
+ private @Mock IKeyguardDismissCallback mMockCallback2;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testCancelled() throws Exception {
+ mDismissCallbackRegistry.addCallback(mMockCallback);
+ mDismissCallbackRegistry.notifyDismissCancelled();
+ verify(mMockCallback).onDismissCancelled();
+ }
+
+ @Test
+ public void testCancelled_multiple() throws Exception {
+ mDismissCallbackRegistry.addCallback(mMockCallback);
+ mDismissCallbackRegistry.addCallback(mMockCallback2);
+ mDismissCallbackRegistry.notifyDismissCancelled();
+ verify(mMockCallback).onDismissCancelled();
+ verify(mMockCallback2).onDismissCancelled();
+ }
+
+ @Test
+ public void testSucceeded() throws Exception {
+ mDismissCallbackRegistry.addCallback(mMockCallback);
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+ verify(mMockCallback).onDismissSucceeded();
+ }
+
+ @Test
+ public void testSucceeded_multiple() throws Exception {
+ mDismissCallbackRegistry.addCallback(mMockCallback);
+ mDismissCallbackRegistry.addCallback(mMockCallback2);
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+ verify(mMockCallback).onDismissSucceeded();
+ verify(mMockCallback2).onDismissSucceeded();
+ }
+
+ @Test
+ public void testOnlyOnce() throws Exception {
+ mDismissCallbackRegistry.addCallback(mMockCallback);
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+ mDismissCallbackRegistry.notifyDismissSucceeded();
+ verify(mMockCallback, times(1)).onDismissSucceeded();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
new file mode 100644
index 0000000..639c8da
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.systemui.statusbar;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Looper;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.SubscriptionManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyguardIndicationControllerTest extends SysuiTestCase {
+
+ private final String ORGANIZATION_NAME = "organization";
+ private final String DISCLOSURE_WITH_ORGANIZATION_NAME = "managed by organization";
+
+ private Context mContext = mock(Context.class);
+ private DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
+ private ViewGroup mIndicationArea = mock(ViewGroup.class);
+ private KeyguardIndicationTextView mDisclosure = mock(KeyguardIndicationTextView.class);
+
+ private KeyguardIndicationController mController;
+
+ @Before
+ public void setUp() throws Exception {
+ final Resources resources = mock(Resources.class);
+ when(mContext.getResources()).thenReturn(resources);
+ when(mContext.getContentResolver()).thenReturn(mock(ContentResolver.class));
+ when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
+ when(mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn(
+ mock(SubscriptionManager.class));
+ when(mContext.getSystemService(Context.TRUST_SERVICE)).thenReturn(
+ mock(TrustManager.class));
+ when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mDevicePolicyManager);
+
+ when(resources.getString(R.string.do_disclosure_with_name, ORGANIZATION_NAME))
+ .thenReturn(DISCLOSURE_WITH_ORGANIZATION_NAME);
+
+ when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
+ .thenReturn(mDisclosure);
+ }
+
+ private void createController() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mController = new KeyguardIndicationController(mContext, mIndicationArea, null);
+ }
+
+ @Test
+ public void unmanaged() {
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+ createController();
+
+ verify(mDisclosure).setVisibility(View.GONE);
+ verifyNoMoreInteractions(mDisclosure);
+ }
+
+ @Test
+ public void managedNoOwnerName() {
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+ when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+ createController();
+
+ verify(mDisclosure).setVisibility(View.VISIBLE);
+ verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+ verifyNoMoreInteractions(mDisclosure);
+ }
+
+ @Test
+ public void managedOwnerName() {
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+ when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+ createController();
+
+ verify(mDisclosure).setVisibility(View.VISIBLE);
+ verify(mDisclosure).switchIndication(DISCLOSURE_WITH_ORGANIZATION_NAME);
+ verifyNoMoreInteractions(mDisclosure);
+ }
+
+ @Test
+ public void updateOnTheFly() {
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+ createController();
+
+ final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ reset(mDisclosure);
+
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+ when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
+ monitor.onKeyguardVisibilityChanged(true);
+
+ verify(mDisclosure).setVisibility(View.VISIBLE);
+ verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
+ verifyNoMoreInteractions(mDisclosure);
+ reset(mDisclosure);
+
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
+ when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
+ monitor.onKeyguardVisibilityChanged(false);
+ monitor.onKeyguardVisibilityChanged(true);
+
+ verify(mDisclosure).setVisibility(View.VISIBLE);
+ verify(mDisclosure).switchIndication(DISCLOSURE_WITH_ORGANIZATION_NAME);
+ verifyNoMoreInteractions(mDisclosure);
+ reset(mDisclosure);
+
+ when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
+ monitor.onKeyguardVisibilityChanged(false);
+ monitor.onKeyguardVisibilityChanged(true);
+
+ verify(mDisclosure).setVisibility(View.GONE);
+ verifyNoMoreInteractions(mDisclosure);
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 45f2ec7..f08408b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2232,6 +2232,14 @@
// ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
+ // ACTION: The lockscreen gets shown because the SIM card was removed
+ // SUBTYPE: false: device was previously unlocked, true: device was previously locked
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: N-MR2
+ ACTION_LOCK_BECAUSE_SIM_REMOVED = 496;
+
+ // ---- End N-MR2 Constants, all N-MR2 constants go above this line ----
+
// ------- Begin N Keyboard Shortcuts Helper -----
// Keyboard Shortcuts Helper is opened/closed.
KEYBOARD_SHORTCUTS_HELPER = 500;
@@ -2659,6 +2667,422 @@
// OS: O
TEXT_LONGPRESS = 629;
+ // ACTION: An app requested an unknown permission
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
+
+ // ACTION: An app was granted an unknown permission
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_UNKNOWN = 631;
+
+ // ACTION: An app requested an unknown permission and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_UNKNOWN = 632;
+
+ // ACTION: An unknown permission was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
+
+ // ACTION: An app requested the permission READ_CALENDAR
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
+
+ // ACTION: An app was granted the permission READ_CALENDAR
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
+
+ // ACTION: An app requested the permission READ_CALENDAR and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
+
+ // ACTION: The permission READ_CALENDAR was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
+
+ // ACTION: An app requested the permission WRITE_CALENDAR
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
+
+ // ACTION: An app was granted the permission WRITE_CALENDAR
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
+
+ // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
+
+ // ACTION: The permission WRITE_CALENDAR was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
+
+ // ACTION: An app requested the permission CAMERA
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_CAMERA = 642;
+
+ // ACTION: An app was granted the permission CAMERA
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_CAMERA = 643;
+
+ // ACTION: An app requested the permission CAMERA and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_CAMERA = 644;
+
+ // ACTION: The permission CAMERA was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_CAMERA = 645;
+
+ // ACTION: An app requested the permission READ_CONTACTS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
+
+ // ACTION: An app was granted the permission READ_CONTACTS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
+
+ // ACTION: An app requested the permission READ_CONTACTS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
+
+ // ACTION: The permission READ_CONTACTS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
+
+ // ACTION: An app requested the permission WRITE_CONTACTS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
+
+ // ACTION: An app was granted the permission WRITE_CONTACTS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
+
+ // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
+
+ // ACTION: The permission WRITE_CONTACTS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
+
+ // ACTION: An app requested the permission GET_ACCOUNTS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
+
+ // ACTION: An app was granted the permission GET_ACCOUNTS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
+
+ // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
+
+ // ACTION: The permission GET_ACCOUNTS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
+
+ // ACTION: An app requested the permission ACCESS_FINE_LOCATION
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
+
+ // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
+
+ // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
+
+ // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
+
+ // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
+
+ // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
+
+ // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
+
+ // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
+
+ // ACTION: An app requested the permission RECORD_AUDIO
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
+
+ // ACTION: An app was granted the permission RECORD_AUDIO
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
+
+ // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
+
+ // ACTION: The permission RECORD_AUDIO was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
+
+ // ACTION: An app requested the permission READ_PHONE_STATE
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
+
+ // ACTION: An app was granted the permission READ_PHONE_STATE
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
+
+ // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
+
+ // ACTION: The permission READ_PHONE_STATE was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
+
+ // ACTION: An app requested the permission CALL_PHONE
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
+
+ // ACTION: An app was granted the permission CALL_PHONE
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
+
+ // ACTION: An app requested the permission CALL_PHONE and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
+
+ // ACTION: The permission CALL_PHONE was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
+
+ // ACTION: An app requested the permission READ_CALL_LOG
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
+
+ // ACTION: An app was granted the permission READ_CALL_LOG
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
+
+ // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
+
+ // ACTION: The permission READ_CALL_LOG was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
+
+ // ACTION: An app requested the permission WRITE_CALL_LOG
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
+
+ // ACTION: An app was granted the permission WRITE_CALL_LOG
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
+
+ // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
+
+ // ACTION: The permission WRITE_CALL_LOG was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
+
+ // ACTION: An app requested the permission ADD_VOICEMAIL
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
+
+ // ACTION: An app was granted the permission ADD_VOICEMAIL
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
+
+ // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
+
+ // ACTION: The permission ADD_VOICEMAIL was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
+
+ // ACTION: An app requested the permission USE_SIP
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_USE_SIP = 690;
+
+ // ACTION: An app was granted the permission USE_SIP
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_USE_SIP = 691;
+
+ // ACTION: An app requested the permission USE_SIP and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_USE_SIP = 692;
+
+ // ACTION: The permission USE_SIP was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_USE_SIP = 693;
+
+ // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
+
+ // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
+
+ // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
+
+ // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
+
+ // ACTION: An app requested the permission READ_CELL_BROADCASTS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
+
+ // ACTION: An app was granted the permission READ_CELL_BROADCASTS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
+
+ // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
+
+ // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
+
+ // ACTION: An app requested the permission BODY_SENSORS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
+
+ // ACTION: An app was granted the permission BODY_SENSORS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
+
+ // ACTION: An app requested the permission BODY_SENSORS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
+
+ // ACTION: The permission BODY_SENSORS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
+
+ // ACTION: An app requested the permission SEND_SMS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
+
+ // ACTION: An app was granted the permission SEND_SMS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_SEND_SMS = 707;
+
+ // ACTION: An app requested the permission SEND_SMS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_SEND_SMS = 708;
+
+ // ACTION: The permission SEND_SMS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
+
+ // ACTION: An app requested the permission RECEIVE_SMS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
+
+ // ACTION: An app was granted the permission RECEIVE_SMS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
+
+ // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
+
+ // ACTION: The permission RECEIVE_SMS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
+
+ // ACTION: An app requested the permission READ_SMS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_SMS = 714;
+
+ // ACTION: An app was granted the permission READ_SMS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_SMS = 715;
+
+ // ACTION: An app requested the permission READ_SMS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_SMS = 716;
+
+ // ACTION: The permission READ_SMS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_SMS = 717;
+
+ // ACTION: An app requested the permission RECEIVE_WAP_PUSH
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
+
+ // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
+
+ // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
+
+ // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
+
+ // ACTION: An app requested the permission RECEIVE_MMS
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
+
+ // ACTION: An app was granted the permission RECEIVE_MMS
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
+
+ // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
+
+ // ACTION: The permission RECEIVE_MMS was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
+
+ // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
+
+ // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
+
+ // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
+
+ // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
+
+ // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
+
+ // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
+ // PACKAGE: The package name of the app that was granted the permission
+ ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
+
+ // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
+ // PACKAGE: The package name of the app requesting the permission
+ ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
+
+ // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
+ // PACKAGE: The package name of the app the permission was revoked for
+ ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 07322fc..8092b4a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1430,7 +1430,7 @@
synchronized (this) {
try {
ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name,
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
reportPowerSaveWhitelistChangedLocked();
updateWhitelistAppIdsLocked();
@@ -2396,7 +2396,7 @@
if (name != null) {
try {
ApplicationInfo ai = pm.getApplicationInfo(name,
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
mPowerSaveWhitelistUserApps.put(ai.packageName,
UserHandle.getAppId(ai.uid));
} catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 0414b47..8402087 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.Manifest;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -499,13 +500,21 @@
*/
private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
int permission) {
+ final Intent grantIntent = new Intent();
+ grantIntent.setData(contentUri);
+ grantIntent.setFlags(permission);
+
+ final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getCallingUserId();
if (callingUserId != UserHandle.USER_SYSTEM) {
contentUri = ContentProvider.maybeAddUserId(contentUri, callingUserId);
}
+
long token = Binder.clearCallingIdentity();
try {
- mContext.grantUriPermission(PHONE_PACKAGE_NAME, contentUri, permission);
+ LocalServices.getService(ActivityManagerInternal.class)
+ .grantUriPermissionFromIntent(callingUid, PHONE_PACKAGE_NAME,
+ grantIntent, UserHandle.USER_SYSTEM);
// Grant permission for the carrier app.
Intent intent = new Intent(action);
@@ -514,7 +523,9 @@
List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
intent);
if (carrierPackages != null && carrierPackages.size() == 1) {
- mContext.grantUriPermission(carrierPackages.get(0), contentUri, permission);
+ LocalServices.getService(ActivityManagerInternal.class)
+ .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
+ grantIntent, UserHandle.USER_SYSTEM);
}
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index f5cda0a..72fa1e3 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -41,6 +41,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.TransferPipe;
@@ -63,6 +64,7 @@
private static final boolean DBG = false;
private final Context mContext;
+ private final NetworkScorerAppManager mNetworkScorerAppManager;
private final Map<Integer, INetworkScoreCache> mScoreCaches;
/** Lock used to update mPackageMonitor when scorer package changes occur. */
private final Object mPackageMonitorLock = new Object[0];
@@ -133,7 +135,7 @@
+ ", forceUnbind=" + forceUnbind);
}
final NetworkScorerAppData activeScorer =
- NetworkScorerAppManager.getActiveScorer(mContext);
+ mNetworkScorerAppManager.getActiveScorer();
if (activeScorer == null) {
// Package change has invalidated a scorer, this will also unbind any service
// connection.
@@ -154,7 +156,13 @@
}
public NetworkScoreService(Context context) {
+ this(context, new NetworkScorerAppManager(context));
+ }
+
+ @VisibleForTesting
+ NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
mContext = context;
+ mNetworkScorerAppManager = networkScoreAppManager;
mScoreCaches = new HashMap<>();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
// TODO: Need to update when we support per-user scorers. http://b/23422763
@@ -173,7 +181,7 @@
String defaultPackage = mContext.getResources().getString(
R.string.config_defaultNetworkScorerPackageName);
if (!TextUtils.isEmpty(defaultPackage)) {
- NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
+ mNetworkScorerAppManager.setActiveScorer(defaultPackage);
}
Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1);
}
@@ -194,7 +202,7 @@
private void registerPackageMonitorIfNeeded() {
if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
- NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext);
+ NetworkScorerAppData scorer = mNetworkScorerAppManager.getActiveScorer();
synchronized (mPackageMonitorLock) {
// Unregister the current monitor if needed.
if (mPackageMonitor != null) {
@@ -222,7 +230,7 @@
private void bindToScoringServiceIfNeeded() {
if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded");
- NetworkScorerAppData scorerData = NetworkScorerAppManager.getActiveScorer(mContext);
+ NetworkScorerAppData scorerData = mNetworkScorerAppManager.getActiveScorer();
bindToScoringServiceIfNeeded(scorerData);
}
@@ -259,7 +267,7 @@
@Override
public boolean updateScores(ScoredNetwork[] networks) {
- if (!NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid())) {
+ if (!mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid())) {
throw new SecurityException("Caller with UID " + getCallingUid() +
" is not the active scorer.");
}
@@ -298,7 +306,7 @@
public boolean clearScores() {
// Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
// should be allowed to flush all scores.
- if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+ if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
PackageManager.PERMISSION_GRANTED) {
clearInternal();
@@ -328,7 +336,7 @@
public void disableScoring() {
// Only the active scorer or the system (who can broadcast BROADCAST_NETWORK_PRIVILEGED)
// should be allowed to disable scoring.
- if (NetworkScorerAppManager.isCallerActiveScorer(mContext, getCallingUid()) ||
+ if (mNetworkScorerAppManager.isCallerActiveScorer(getCallingUid()) ||
mContext.checkCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED) ==
PackageManager.PERMISSION_GRANTED) {
// The return value is discarded here because at this point, the call should always
@@ -352,8 +360,8 @@
// only be allowing valid apps to be set as scorers, so failure here should be rare.
clearInternal();
// Get the scorer that is about to be replaced, if any, so we can notify it directly.
- NetworkScorerAppData prevScorer = NetworkScorerAppManager.getActiveScorer(mContext);
- boolean result = NetworkScorerAppManager.setActiveScorer(mContext, packageName);
+ NetworkScorerAppData prevScorer = mNetworkScorerAppManager.getActiveScorer();
+ boolean result = mNetworkScorerAppManager.setActiveScorer(packageName);
// Unconditionally attempt to bind to the current scorer. If setActiveScorer() failed
// then we'll attempt to restore the previous binding (if any), otherwise an attempt
// will be made to bind to the new scorer.
@@ -411,7 +419,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
- NetworkScorerAppData currentScorer = NetworkScorerAppManager.getActiveScorer(mContext);
+ NetworkScorerAppData currentScorer = mNetworkScorerAppManager.getActiveScorer();
if (currentScorer == null) {
writer.println("Scoring is disabled.");
return;
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 080b46c..698f1eb 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -26,7 +26,6 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.service.persistentdata.IPersistentDataBlockService;
import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Slog;
@@ -53,15 +52,14 @@
* This data will live across factory resets not initiated via the Settings UI.
* When a device is factory reset through Settings this data is wiped.
*
- * Allows writing one block at a time. Namely, each time
- * {@link android.service.persistentdata.IPersistentDataBlockService}.write(byte[] data)
- * is called, it will overwite the data that was previously written on the block.
+ * Allows writing one block at a time. Namely, each time {@link IPersistentDataBlockService#write}
+ * is called, it will overwrite the data that was previously written on the block.
*
* Clients can query the size of the currently written block via
- * {@link android.service.persistentdata.IPersistentDataBlockService}.getTotalDataSize().
+ * {@link IPersistentDataBlockService#getDataBlockSize}
*
- * Clients can any number of bytes from the currently written block up to its total size by invoking
- * {@link android.service.persistentdata.IPersistentDataBlockService}.read(byte[] data)
+ * Clients can read any number of bytes from the currently written block up to its total size by
+ * invoking {@link IPersistentDataBlockService#read}
*/
public class PersistentDataBlockService extends SystemService {
private static final String TAG = PersistentDataBlockService.class.getSimpleName();
@@ -84,6 +82,7 @@
private int mAllowedUid = -1;
private long mBlockDeviceSize;
+ private boolean mIsWritable = true;
public PersistentDataBlockService(Context context) {
super(context);
@@ -377,6 +376,11 @@
headerAndData.put(data);
synchronized (mLock) {
+ if (!mIsWritable) {
+ IoUtils.closeQuietly(outputStream);
+ return -1;
+ }
+
try {
byte[] checksum = new byte[DIGEST_SIZE_BYTES];
outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
@@ -451,6 +455,9 @@
if (ret < 0) {
Slog.e(TAG, "failed to wipe persistent partition");
+ } else {
+ mIsWritable = false;
+ Slog.i(TAG, "persistent partition now wiped and unwritable");
}
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 11fabb4..55d31c3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -644,14 +644,8 @@
Slog.e(TAG, "Unable to record last fstrim!");
}
- final boolean shouldBenchmark = shouldBenchmark();
- try {
- // This method must be run on the main (handler) thread,
- // so it is safe to directly call into vold.
- mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
- } catch (NativeDaemonConnectorException ndce) {
- Slog.e(TAG, "Failed to run fstrim!");
- }
+ final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
+ fstrim(flags);
// invoke the completion callback, if any
// TODO: fstrim is non-blocking, so remove this useless callback
@@ -1956,6 +1950,28 @@
}
}
+ @Override
+ public void fstrim(int flags) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+ waitForReady();
+
+ String cmd;
+ if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
+ cmd = "dodtrim";
+ } else {
+ cmd = "dotrim";
+ }
+ if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
+ cmd += "bench";
+ }
+
+ try {
+ mConnector.execute("fstrim", cmd);
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to run fstrim: " + e);
+ }
+ }
+
private void remountUidExternalStorage(int uid, int mode) {
waitForReady();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 2932a1a..62f4f19 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1381,7 +1381,6 @@
}
Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
Bundle data = new Bundle();
signalStrength.fillInNotifierBundle(data);
intent.putExtras(data);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c8ed872..229a68b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,8 +21,9 @@
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.app.WaitResult;
-import android.graphics.PointF;
import android.os.IDeviceIdentifiersPolicyService;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.telephony.TelephonyIntents;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -199,6 +200,7 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageManager;
+import android.provider.Downloads;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
@@ -274,6 +276,7 @@
import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.GET_PROVIDERS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -2879,9 +2882,11 @@
@Override
public void batterySendBroadcast(Intent intent) {
- broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
- AppOpsManager.OP_NONE, null, false, false,
- -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ synchronized (this) {
+ broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
+ AppOpsManager.OP_NONE, null, false, false,
+ -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ }
}
/**
@@ -8509,6 +8514,12 @@
// Only inspect grants matching package
if (packageName == null || perm.sourcePkg.equals(packageName)
|| perm.targetPkg.equals(packageName)) {
+ // Hacky solution as part of fixing a security bug; ignore
+ // grants associated with DownloadManager so we don't have
+ // to immediately launch it to regrant the permissions
+ if (Downloads.Impl.AUTHORITY.equals(perm.uri.uri.getAuthority())
+ && !persistable) continue;
+
persistChanged |= perm.revokeModes(persistable
? ~0 : ~Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
@@ -14427,7 +14438,7 @@
if (dumpPackage != null) {
IPackageManager pm = AppGlobals.getPackageManager();
try {
- dumpUid = pm.getPackageUid(dumpPackage, MATCH_UNINSTALLED_PACKAGES, 0);
+ dumpUid = pm.getPackageUid(dumpPackage, MATCH_ANY_USER, 0);
} catch (RemoteException e) {
}
}
@@ -15404,7 +15415,7 @@
if (dumpPackage != null) {
try {
dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage,
- MATCH_UNINSTALLED_PACKAGES, 0);
+ MATCH_ANY_USER, 0);
} catch (NameNotFoundException e) {
dumpUid = -1;
}
@@ -19112,6 +19123,16 @@
enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
synchronized (this) {
+ // Check if display is initialized in AM.
+ if (!mStackSupervisor.isDisplayAdded(displayId)) {
+ // Call might come when display is not yet added or has already been removed.
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Trying to update display configuration for non-existing displayId="
+ + displayId);
+ }
+ return false;
+ }
+
if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration(displayId);
@@ -22127,6 +22148,15 @@
private final class LocalService extends ActivityManagerInternal {
@Override
+ public void grantUriPermissionFromIntent(int callingUid, String targetPkg, Intent intent,
+ int targetUserId) {
+ synchronized (ActivityManagerService.this) {
+ ActivityManagerService.this.grantUriPermissionFromIntentLocked(callingUid,
+ targetPkg, intent, null, targetUserId);
+ }
+ }
+
+ @Override
public String checkContentProviderAccess(String authority, int userId) {
return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
}
@@ -22542,6 +22572,17 @@
return rInfo != null && rInfo.activityInfo != null;
}
+ @Override
+ public void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback)
+ throws RemoteException {
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ mKeyguardController.dismissKeyguard(token, callback);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
/**
* Attach an agent to the specified process (proces name or PID)
*/
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 90b46ed..214a357 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -207,6 +207,8 @@
boolean keysPaused; // has key dispatching been paused for it?
int launchMode; // the launch mode activity attribute.
boolean visible; // does this activity's window need to be shown?
+ boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
+ // might hide this activity?
boolean sleeping; // have we told the activity to sleep?
boolean nowVisible; // is this activity's window visible?
boolean idle; // has the activity gone idle?
@@ -1248,9 +1250,15 @@
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
- /** Return true if the input activity should be made visible */
- boolean shouldBeVisible(boolean behindTranslucentActivity, boolean stackVisibleBehind,
- ActivityRecord visibleBehind, boolean behindFullscreenActivity) {
+ /**
+ * @return true if the input activity should be made visible, ignoring any effect Keyguard
+ * might have on the visibility
+ *
+ * @see {@link ActivityStack#checkKeyguardVisibility}
+ */
+ boolean shouldBeVisibleIgnoringKeyguard(boolean behindTranslucentActivity,
+ boolean stackVisibleBehind, ActivityRecord visibleBehind,
+ boolean behindFullscreenActivity) {
if (!okToShowLocked()) {
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 473b1a3..005b8aa 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1660,13 +1660,15 @@
aboveTop = false;
// Check whether activity should be visible without Keyguard influence
- final boolean shouldBeVisible = r.shouldBeVisible(behindTranslucentActivity,
- stackVisibleBehind, visibleBehind, behindFullscreenActivity);
+ final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
+ behindTranslucentActivity, stackVisibleBehind, visibleBehind,
+ behindFullscreenActivity);
+ r.visibleIgnoringKeyguard = visibleIgnoringKeyguard;
// Now check whether it's really visible depending on Keyguard state.
- final boolean reallyVisible = checkKeyguardVisibility(r, shouldBeVisible,
- isTop);
- if (shouldBeVisible) {
+ final boolean reallyVisible = checkKeyguardVisibility(r,
+ visibleIgnoringKeyguard, isTop);
+ if (visibleIgnoringKeyguard) {
behindFullscreenActivity = updateBehindFullscreen(stackInvisible,
behindFullscreenActivity, task, r);
if (behindFullscreenActivity && !r.fullscreen) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5d8d79f..48108fe 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3561,6 +3561,11 @@
}
}
+ /** Check if display with specified id is added to the list. */
+ boolean isDisplayAdded(int displayId) {
+ return mActivityDisplays.get(displayId) != null;
+ }
+
private void calculateDefaultMinimalSizeOfResizeableTasks(ActivityDisplay display) {
mDefaultMinSizeOfResizeableTask =
mService.mContext.getResources().getDimensionPixelSize(
@@ -3779,6 +3784,7 @@
findTaskToMoveToFrontLocked(task, 0, null, reason,
lockTaskModeState != LOCK_TASK_MODE_NONE);
resumeFocusedStackTopActivityLocked();
+ mWindowManager.executeAppTransition();
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.getStackId(),
true /* forceNonResizable */);
@@ -4075,7 +4081,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED) != 0;
if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
mWindowManager.lockNow(null);
- mWindowManager.dismissKeyguard();
+ mWindowManager.dismissKeyguard(null /* callback */);
new LockPatternUtils(mService.mContext)
.requireCredentialEntry(UserHandle.USER_ALL);
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7a122e6..029b5dd 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -300,15 +300,19 @@
* @param crashInfo describing the failure
*/
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+ final int callingPid = Binder.getCallingPid();
+ final int callingUid = Binder.getCallingUid();
+
final long origId = Binder.clearCallingIdentity();
try {
- crashApplicationInner(r, crashInfo);
+ crashApplicationInner(r, crashInfo, callingPid, callingUid);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+ void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
+ int callingPid, int callingUid) {
long timeMillis = System.currentTimeMillis();
String shortMsg = crashInfo.exceptionClassName;
String longMsg = crashInfo.exceptionMessage;
@@ -327,7 +331,7 @@
* finish now and don't show the app error dialog.
*/
if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
- timeMillis)) {
+ timeMillis, callingPid, callingUid)) {
return;
}
@@ -429,15 +433,16 @@
private boolean handleAppCrashInActivityController(ProcessRecord r,
ApplicationErrorReport.CrashInfo crashInfo,
String shortMsg, String longMsg,
- String stackTrace, long timeMillis) {
+ String stackTrace, long timeMillis,
+ int callingPid, int callingUid) {
if (mService.mController == null) {
return false;
}
try {
String name = r != null ? r.processName : null;
- int pid = r != null ? r.pid : Binder.getCallingPid();
- int uid = r != null ? r.info.uid : Binder.getCallingUid();
+ int pid = r != null ? r.pid : callingPid;
+ int uid = r != null ? r.info.uid : callingUid;
if (!mService.mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 67cac47..0ea78b3 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1283,7 +1283,7 @@
if (useCheckinFormat) {
List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
+ PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
if (isRealCheckin) {
// For a real checkin, first we want to prefer to use the last complete checkin
// file if there is one.
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 9d8c383..5e02597 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -20,6 +20,8 @@
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
@@ -29,6 +31,11 @@
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.wm.WindowManagerService;
import java.io.PrintWriter;
@@ -42,6 +49,8 @@
*/
class KeyguardController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "KeyguardController" : TAG_AM;
+
private final ActivityManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
private WindowManagerService mWindowManager;
@@ -108,7 +117,6 @@
mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
- mWindowManager.keyguardGoingAway(flags);
mService.updateSleepIfNeededLocked();
// Some stack visibility might change (e.g. docked stack)
@@ -122,6 +130,23 @@
}
}
+ void dismissKeyguard(IBinder token, IKeyguardDismissCallback callback) {
+ final ActivityRecord activityRecord = ActivityRecord.forTokenLocked(token);
+ if (activityRecord == null || !activityRecord.visibleIgnoringKeyguard) {
+ failCallback(callback);
+ return;
+ }
+ mWindowManager.dismissKeyguard(callback);
+ }
+
+ private void failCallback(IKeyguardDismissCallback callback) {
+ try {
+ callback.onDismissError();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call callback", e);
+ }
+ }
+
private int convertTransitFlags(int keyguardGoingAwayFlags) {
int result = 0;
if ((keyguardGoingAwayFlags & KEYGUARD_GOING_AWAY_FLAG_TO_SHADE) != 0) {
@@ -215,7 +240,7 @@
*/
private void handleDismissKeyguard() {
if (mDismissingKeyguardActivity != null) {
- mWindowManager.dismissKeyguard();
+ mWindowManager.dismissKeyguard(null /* callback */);
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 86e3ccc..0bc12ee 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1417,8 +1417,8 @@
try {
ApplicationInfo ai = pm.getApplicationInfo(
checkIntent.getComponent().getPackageName(),
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
if (ai != null) {
effectiveUid = ai.uid;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ac9545c..67f3614 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -139,7 +139,9 @@
*
* @hide
*/
-public class AudioService extends IAudioService.Stub {
+public class AudioService extends IAudioService.Stub
+ implements AccessibilityManager.TouchExplorationStateChangeListener,
+ AccessibilityManager.AccessibilityStateChangeListener{
private static final String TAG = "AudioService";
@@ -775,7 +777,7 @@
TAG,
SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
- StreamOverride.init(mContext);
+ initA11yMonitoring(mContext);
mControllerService.init();
onIndicateSystemReady();
}
@@ -972,6 +974,8 @@
private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
int dtmfStreamAlias;
+ final int a11yStreamAlias = sIndependentA11yVolume ?
+ AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
if (mIsSingleVolume) {
mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
@@ -1000,9 +1004,13 @@
}
mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
+ mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
+
if (updateVolumes) {
mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
caller);
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
+ mStreamStates[a11yStreamAlias], caller);
// apply stream mute states according to new value of mRingerModeAffectedStreams
setRingerModeInt(getRingerModeInternal(), false);
sendMsg(mAudioHandler,
@@ -1011,6 +1019,12 @@
0,
0,
mStreamStates[AudioSystem.STREAM_DTMF], 0);
+ sendMsg(mAudioHandler,
+ MSG_SET_ALL_VOLUMES,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
}
}
@@ -1536,6 +1550,10 @@
private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
String caller, int uid) {
+ if (DEBUG_VOL) {
+ Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
+ + ", calling=" + callingPackage + ")");
+ }
if (mUseFixedVolume) {
return;
}
@@ -3639,7 +3657,7 @@
return AudioSystem.STREAM_VOICE_CALL;
}
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
- if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+ if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
if (DEBUG_VOL)
Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
return AudioSystem.STREAM_MUSIC;
@@ -3665,13 +3683,13 @@
return AudioSystem.STREAM_VOICE_CALL;
}
} else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
- StreamOverride.sDelayMs) ||
+ sStreamOverrideDelayMs) ||
AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
- StreamOverride.sDelayMs)) {
+ sStreamOverrideDelayMs)) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
return AudioSystem.STREAM_NOTIFICATION;
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
- if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
+ if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
return AudioSystem.STREAM_MUSIC;
} else {
@@ -5861,44 +5879,67 @@
}
//==========================================================================================
- // Accessibility: taking touch exploration into account for selecting the default
+ // Accessibility
+
+ private void initA11yMonitoring(Context ctxt) {
+ AccessibilityManager accessibilityManager =
+ (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
+ updateA11yVolumeAlias(accessibilityManager.isEnabled());
+ accessibilityManager.addTouchExplorationStateChangeListener(this);
+ accessibilityManager.addAccessibilityStateChangeListener(this);
+ }
+
+ //---------------------------------------------------------------------------------
+ // A11y: taking touch exploration into account for selecting the default
// stream override timeout when adjusting volume
- //==========================================================================================
- private static class StreamOverride
- implements AccessibilityManager.TouchExplorationStateChangeListener {
+ //---------------------------------------------------------------------------------
- // AudioService.getActiveStreamType() will return:
- // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
- // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
- // stopped
- private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
- private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
+ // AudioService.getActiveStreamType() will return:
+ // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
+ // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
+ // stopped
+ private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
+ private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
- static int sDelayMs;
+ private static int sStreamOverrideDelayMs;
- static void init(Context ctxt) {
- AccessibilityManager accessibilityManager =
- (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
- updateDefaultStreamOverrideDelay(
- accessibilityManager.isTouchExplorationEnabled());
- accessibilityManager.addTouchExplorationStateChangeListener(
- new StreamOverride());
+ @Override
+ public void onTouchExplorationStateChanged(boolean enabled) {
+ updateDefaultStreamOverrideDelay(enabled);
+ }
+
+ private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
+ if (touchExploreEnabled) {
+ sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
+ } else {
+ sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
}
+ if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
+ + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
+ }
- @Override
- public void onTouchExplorationStateChanged(boolean enabled) {
- updateDefaultStreamOverrideDelay(enabled);
- }
+ //---------------------------------------------------------------------------------
+ // A11y: taking a11y state into account for the handling of a11y prompts volume
+ //---------------------------------------------------------------------------------
- private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
- if (touchExploreEnabled) {
- sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
- } else {
- sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
- }
- if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
- + " stream override delay is now " + sDelayMs + " ms");
- }
+ private static boolean sIndependentA11yVolume = false;
+
+ @Override
+ public void onAccessibilityStateChanged(boolean enabled) {
+ updateA11yVolumeAlias(enabled);
+ }
+
+ private void updateA11yVolumeAlias(boolean a11Enabled) {
+ if (DEBUG_VOL) Log.d(TAG, "Accessibility mode changed to " + a11Enabled);
+ // a11y has its own volume stream when a11y service is enabled
+ sIndependentA11yVolume = a11Enabled;
+ // update the volume mapping scheme
+ updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
+ // update the volume controller behavior
+ mVolumeController.setA11yMode(sIndependentA11yVolume ?
+ VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
+ VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
}
//==========================================================================================
@@ -6178,6 +6219,16 @@
Log.w(TAG, "Error calling dismiss", e);
}
}
+
+ public void setA11yMode(int a11yMode) {
+ if (mController == null)
+ return;
+ try {
+ mController.setA11yMode(a11yMode);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error calling setA11Mode", e);
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 273bc64..132967c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -32,11 +32,14 @@
import android.content.pm.UserInfo;
import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
import android.os.Binder;
+import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.SELinux;
import android.os.ServiceManager;
@@ -625,17 +628,28 @@
private class FingerprintServiceLockoutResetMonitor {
+ private static final long WAKELOCK_TIMEOUT_MS = 2000;
private final IFingerprintServiceLockoutResetCallback mCallback;
+ private final WakeLock mWakeLock;
public FingerprintServiceLockoutResetMonitor(
IFingerprintServiceLockoutResetCallback callback) {
mCallback = callback;
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "lockout reset callback");
}
public void sendLockoutReset() {
if (mCallback != null) {
try {
- mCallback.onLockoutReset(mHalDeviceId);
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ mCallback.onLockoutReset(mHalDeviceId, new IRemoteCallback.Stub() {
+
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ mWakeLock.release();
+ }
+ });
} catch (DeadObjectException e) {
Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
mHandler.post(mRemoveCallbackRunnable);
@@ -648,6 +662,9 @@
private final Runnable mRemoveCallbackRunnable = new Runnable() {
@Override
public void run() {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
}
};
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
index 91c9671..2184245 100644
--- a/services/core/java/com/android/server/firewall/SenderPackageFilter.java
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -47,7 +47,7 @@
try {
// USER_SYSTEM here is not important. Only app id is used and getPackageUid() will
// return a uid whether the app is installed for a user or not.
- packageUid = pm.getPackageUid(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ packageUid = pm.getPackageUid(mPackageName, PackageManager.MATCH_ANY_USER,
UserHandle.USER_SYSTEM);
} catch (RemoteException ex) {
// handled below
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c99d8be..f42c5be 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1820,7 +1820,7 @@
String pkg = args[opti];
try {
filterUid = getContext().getPackageManager().getPackageUid(pkg,
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
} catch (NameNotFoundException ignored) {
pw.println("Invalid package: " + pkg);
return;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c1506b9..533307e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2720,7 +2720,7 @@
// update rules for all installed applications
final List<UserInfo> users = mUserManager.getUsers();
final List<ApplicationInfo> apps = pm.getInstalledApplications(
- PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_DISABLED_COMPONENTS
+ PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4658c046..8ca6086 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1212,7 +1212,8 @@
// Build list of UIDs that we should clean up
int[] uids = new int[0];
final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+ PackageManager.MATCH_ANY_USER
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
for (ApplicationInfo app : apps) {
final int uid = UserHandle.getUid(userId, app.uid);
uids = ArrayUtils.appendInt(uids, uid);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 84c298b..c78a0f5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -53,16 +53,17 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AutomaticZenRule;
+import android.app.backup.BackupManager;
import android.app.IActivityManager;
+import android.app.IOnNotificationChannelCreatedListener;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationChannel;
-import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
-import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
@@ -224,6 +225,7 @@
private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
private IActivityManager mAm;
+ private IPackageManager mPackageManager;
AudioManager mAudioManager;
AudioManagerInternal mAudioManagerInternal;
@Nullable StatusBarManagerInternal mStatusBar;
@@ -718,10 +720,10 @@
if (packageChanged) {
// We cancel notifications for packages which have just been disabled
try {
- final IPackageManager pm = AppGlobals.getPackageManager();
- final int enabled = pm.getApplicationEnabledSetting(pkgName,
+ final int enabled = mPackageManager.getApplicationEnabledSetting(
+ pkgName,
changeUserId != UserHandle.USER_ALL ? changeUserId :
- UserHandle.USER_SYSTEM);
+ UserHandle.USER_SYSTEM);
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
cancelNotifications = false;
@@ -884,6 +886,7 @@
super(context);
}
+ // TODO - replace these methods with a single VisibleForTesting constructor
@VisibleForTesting
void setAudioManager(AudioManager audioMananger) {
mAudioManager = audioMananger;
@@ -931,6 +934,17 @@
mFallbackVibrationPattern = vibrationPattern;
}
+ @VisibleForTesting
+ void setPackageManager(IPackageManager packageManager) {
+ mPackageManager = packageManager;
+ }
+
+ // TODO: This probably should not be mocked, it's an implementation detail.
+ @VisibleForTesting
+ void setRankingHelper(RankingHelper rankingHelper) {
+ mRankingHelper = rankingHelper;
+ }
+
@Override
public void onStart() {
Resources resources = getContext().getResources();
@@ -940,6 +954,7 @@
DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
mAm = ActivityManager.getService();
+ mPackageManager = AppGlobals.getPackageManager();
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
@@ -1312,6 +1327,11 @@
scheduleInterruptionFilterChanged(interruptionFilter);
}
+ @VisibleForTesting
+ INotificationManager getBinderService() {
+ return INotificationManager.Stub.asInterface(mService);
+ }
+
private final IBinder mService = new INotificationManager.Stub() {
// Toasts
// ============================================================================
@@ -1529,13 +1549,15 @@
}
@Override
- public void createNotificationChannel(String pkg, NotificationChannel channel) {
+ public void createNotificationChannel(String pkg, NotificationChannel channel,
+ IOnNotificationChannelCreatedListener listener) throws RemoteException {
Preconditions.checkNotNull(channel);
Preconditions.checkNotNull(channel.getId());
Preconditions.checkNotNull(channel.getName());
checkCallerIsSystemOrSameApp(pkg);
mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel);
savePolicyFile();
+ listener.onNotificationChannelCreated(channel);
}
@Override
@@ -3906,23 +3928,23 @@
throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
}
- private static void checkCallerIsSystemOrSameApp(String pkg) {
+ private void checkCallerIsSystemOrSameApp(String pkg) {
if (isCallerSystem()) {
return;
}
checkCallerIsSameApp(pkg);
}
- private static void checkCallerIsSameApp(String pkg) {
+ private void checkCallerIsSameApp(String pkg) {
final int uid = Binder.getCallingUid();
try {
- ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ ApplicationInfo ai = mPackageManager.getApplicationInfo(
pkg, 0, UserHandle.getCallingUserId());
if (ai == null) {
throw new SecurityException("Unknown package " + pkg);
}
if (!UserHandle.isSameApp(ai.uid, uid)) {
- throw new SecurityException("Calling uid " + uid + " gave package"
+ throw new SecurityException("Calling uid " + uid + " gave package "
+ pkg + " which is owned by uid " + ai.uid);
}
} catch (RemoteException re) {
@@ -4009,7 +4031,7 @@
private boolean isPackageSuspendedForUser(String pkg, int uid) {
int userId = UserHandle.getUserId(uid);
try {
- return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
+ return mPackageManager.isPackageSuspendedForUser(pkg, userId);
} catch (RemoteException re) {
throw new SecurityException("Could not talk to package manager service");
} catch (IllegalArgumentException ex) {
@@ -4510,7 +4532,7 @@
}
public String[] getRequestingPackages() throws RemoteException {
- final ParceledListSlice list = AppGlobals.getPackageManager()
+ final ParceledListSlice list = mPackageManager
.getPackagesHoldingPermissions(PERM, 0 /*flags*/,
ActivityManager.getCurrentUser());
final List<PackageInfo> pkgs = list.getList();
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 984fc38..0213258 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -169,7 +169,8 @@
NotificationManagerService.VIBRATE_PATTERN_MAXLEN,
NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
if (getChannel().shouldVibrate()) {
- vibration = defaultVibration;
+ vibration = getChannel().getVibrationPattern() == null
+ ? defaultVibration : getChannel().getVibrationPattern();
} else {
vibration = null;
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 90b3715..a41231d 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+
import com.android.internal.R;
import android.app.Notification;
@@ -450,6 +452,9 @@
@Override
public void createNotificationChannel(String pkg, int uid, NotificationChannel channel) {
Record r = getOrCreateRecord(pkg, uid);
+ if (IMPORTANCE_NONE == r.importance) {
+ throw new IllegalArgumentException("Package blocked");
+ }
if (r.channels.containsKey(channel.getId()) || channel.getName().equals(
mContext.getString(R.string.default_notification_channel_label))) {
throw new IllegalArgumentException("Channel already exists");
@@ -501,7 +506,8 @@
channel.setSound(updatedChannel.getSound());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
- channel.setVibration(updatedChannel.shouldVibrate());
+ channel.enableVibration(updatedChannel.shouldVibrate());
+ channel.setVibrationPattern(updatedChannel.getVibrationPattern());
}
if ((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_VISIBILITY) == 0) {
if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 29fa754..66fb976 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -595,7 +595,7 @@
if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
try {
mPm.getPackageInfo(rule.component.getPackageName(),
- PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ PackageManager.MATCH_ANY_USER);
} catch (PackageManager.NameNotFoundException e) {
newConfig.automaticRules.removeAt(i);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bc28142..dc25ce4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -59,11 +59,13 @@
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
+import static android.content.pm.PackageManager.MATCH_KNOWN_PACKAGES;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -100,7 +102,9 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
+import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
@@ -231,6 +235,7 @@
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IParcelFileDescriptorFactory;
import com.android.internal.os.InstallerConnection.InstallerException;
import com.android.internal.os.RoSystemProperties;
@@ -402,8 +407,8 @@
static final int SCAN_CHECK_ONLY = 1<<13;
static final int SCAN_DONT_KILL_APP = 1<<14;
static final int SCAN_IGNORE_FROZEN = 1<<15;
-
static final int REMOVE_CHATTY = 1<<16;
+ static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1<<17;
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -527,6 +532,34 @@
/** Special library name that skips shared libraries check during compilation. */
private static final String SKIP_SHARED_LIBRARY_CHECK = "&";
+ /** All dangerous permission names in the same order as the events in MetricsEvent */
+ private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
+ Manifest.permission.READ_CALENDAR,
+ Manifest.permission.WRITE_CALENDAR,
+ Manifest.permission.CAMERA,
+ Manifest.permission.READ_CONTACTS,
+ Manifest.permission.WRITE_CONTACTS,
+ Manifest.permission.GET_ACCOUNTS,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION,
+ Manifest.permission.RECORD_AUDIO,
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.CALL_PHONE,
+ Manifest.permission.READ_CALL_LOG,
+ Manifest.permission.WRITE_CALL_LOG,
+ Manifest.permission.ADD_VOICEMAIL,
+ Manifest.permission.USE_SIP,
+ Manifest.permission.PROCESS_OUTGOING_CALLS,
+ Manifest.permission.READ_CELL_BROADCASTS,
+ Manifest.permission.BODY_SENSORS,
+ Manifest.permission.SEND_SMS,
+ Manifest.permission.RECEIVE_SMS,
+ Manifest.permission.READ_SMS,
+ Manifest.permission.RECEIVE_WAP_PUSH,
+ Manifest.permission.RECEIVE_MMS,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
final ServiceThread mHandlerThread;
final PackageHandler mHandler;
@@ -744,13 +777,11 @@
private int mIntentFilterVerificationToken = 0;
- /** Component that knows whether or not an ephemeral application exists */
- final ComponentName mEphemeralResolverComponent;
/** The service connection to the ephemeral resolver */
final EphemeralResolverConnection mEphemeralResolverConnection;
/** Component used to install ephemeral applications */
- final ComponentName mEphemeralInstallerComponent;
+ ComponentName mEphemeralInstallerComponent;
final ActivityInfo mEphemeralInstallerActivity = new ActivityInfo();
final ResolveInfo mEphemeralInstallerInfo = new ResolveInfo();
@@ -2215,10 +2246,6 @@
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
- // Set flag to monitor and not change apk file paths when
- // scanning install directories.
- final int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
-
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
@@ -2303,6 +2330,14 @@
}
}
+ // Set flag to monitor and not change apk file paths when
+ // scanning install directories.
+ int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
+
+ if (mIsUpgrade || mFirstBoot) {
+ scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
+ }
+
// Collect vendor overlay packages. (Do this before scanning any apps.)
// For security and version matching reason, only consider
// overlay packages if they reside in the right directory.
@@ -2706,32 +2741,22 @@
mInstallerService = new PackageInstallerService(context, this);
final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
- final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
- // both the installer and resolver must be present to enable ephemeral
- if (ephemeralInstallerComponent != null && ephemeralResolverComponent != null) {
+ if (ephemeralResolverComponent != null) {
if (DEBUG_EPHEMERAL) {
- Slog.i(TAG, "Ephemeral activated; resolver: " + ephemeralResolverComponent
- + " installer:" + ephemeralInstallerComponent);
+ Slog.i(TAG, "Ephemeral resolver: " + ephemeralResolverComponent);
}
- mEphemeralResolverComponent = ephemeralResolverComponent;
- mEphemeralInstallerComponent = ephemeralInstallerComponent;
- setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
mEphemeralResolverConnection =
- new EphemeralResolverConnection(mContext, mEphemeralResolverComponent);
+ new EphemeralResolverConnection(mContext, ephemeralResolverComponent);
} else {
- if (DEBUG_EPHEMERAL) {
- final String missingComponent =
- (ephemeralResolverComponent == null)
- ? (ephemeralInstallerComponent == null)
- ? "resolver and installer"
- : "resolver"
- : "installer";
- Slog.i(TAG, "Ephemeral deactivated; missing " + missingComponent);
- }
- mEphemeralResolverComponent = null;
- mEphemeralInstallerComponent = null;
mEphemeralResolverConnection = null;
}
+ mEphemeralInstallerComponent = getEphemeralInstallerLPr();
+ if (mEphemeralInstallerComponent != null) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.i(TAG, "Ephemeral installer: " + mEphemeralInstallerComponent);
+ }
+ setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
+ }
mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
} // synchronized (mPackages)
@@ -2923,6 +2948,18 @@
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
resolveFlags, UserHandle.USER_SYSTEM);
+ Iterator<ResolveInfo> iter = matches.iterator();
+ while (iter.hasNext()) {
+ final ResolveInfo rInfo = iter.next();
+ final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
+ if (ps != null) {
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ if (permissionsState.hasPermission(Manifest.permission.INSTALL_PACKAGES, 0)) {
+ continue;
+ }
+ }
+ iter.remove();
+ }
if (matches.size() == 0) {
return null;
} else if (matches.size() == 1) {
@@ -3106,6 +3143,11 @@
? Collections.<String>emptySet() : permissionsState.getPermissions(userId);
final PackageUserState state = ps.readUserState(userId);
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0
+ && ps.isSystem()) {
+ flags |= MATCH_ANY_USER;
+ }
+
return PackageParser.generatePackageInfo(p, gids, flags,
ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId);
}
@@ -3187,7 +3229,7 @@
if (p != null) {
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
- if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return generatePackageInfo(ps, flags, userId);
}
@@ -3234,7 +3276,7 @@
if (p != null && p.isMatch(flags)) {
return UserHandle.getUid(userId, p.applicationInfo.uid);
}
- if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)) {
return UserHandle.getUid(userId, ps.appId);
@@ -3258,9 +3300,11 @@
final PackageParser.Package p = mPackages.get(packageName);
if (p != null && p.isMatch(flags)) {
PackageSetting ps = (PackageSetting) p.mExtras;
+ // TODO: Shouldn't this be checking for package installed state for userId and
+ // return null?
return ps.getPermissionsState().computeGids(userId);
}
- if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)) {
return ps.getPermissionsState().computeGids(userId);
@@ -3384,7 +3428,7 @@
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
}
- if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -3493,6 +3537,7 @@
* Update given flags when being used to request {@link PackageInfo}.
*/
private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+ final boolean isCallerSystemUser = UserHandle.getCallingUserId() == UserHandle.USER_SYSTEM;
boolean triaged = true;
if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
| PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) {
@@ -3509,6 +3554,18 @@
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
triaged = false;
}
+ if ((flags & PackageManager.MATCH_ANY_USER) != 0) {
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+ "MATCH_ANY_USER flag requires INTERACT_ACROSS_USERS permission at "
+ + Debug.getCallers(5));
+ } else if ((flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0 && isCallerSystemUser
+ && sUserManager.hasManagedProfile(UserHandle.USER_SYSTEM)) {
+ // If the caller wants all packages and has a restricted profile associated with it,
+ // then match all users. This is to make sure that launchers that need to access work
+ // profile apps don't start breaking. TODO: Remove this hack when launchers stop using
+ // MATCH_UNINSTALLED_PACKAGES to query apps in other profiles. b/31000380
+ flags |= PackageManager.MATCH_ANY_USER;
+ }
if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie
+ " with flags 0x" + Integer.toHexString(flags), new Throwable());
@@ -4132,6 +4189,10 @@
break;
}
+ if (bp.isRuntime()) {
+ logPermissionGranted(mContext, name, packageName);
+ }
+
mOnPermissionChangeListeners.onPermissionsChanged(uid);
// Not critical if that is lost - app has to request again.
@@ -4233,6 +4294,10 @@
return;
}
+ if (bp.isRuntime()) {
+ logPermissionRevoked(mContext, name, packageName);
+ }
+
mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
// Critical, after this call app should never have the permission.
@@ -4244,6 +4309,66 @@
killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
}
+ /**
+ * Get the first event id for the permission.
+ *
+ * <p>There are four events for each permission: <ul>
+ * <li>Request permission: first id + 0</li>
+ * <li>Grant permission: first id + 1</li>
+ * <li>Request for permission denied: first id + 2</li>
+ * <li>Revoke permission: first id + 3</li>
+ * </ul></p>
+ *
+ * @param name name of the permission
+ *
+ * @return The first event id for the permission
+ */
+ private static int getBaseEventId(@NonNull String name) {
+ int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
+
+ if (eventIdIndex == -1) {
+ if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
+ || "user".equals(Build.TYPE)) {
+ Log.i(TAG, "Unknown permission " + name);
+
+ return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
+ } else {
+ // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
+ //
+ // Also update
+ // - EventLogger#ALL_DANGEROUS_PERMISSIONS
+ // - metrics_constants.proto
+ throw new IllegalStateException("Unknown permission " + name);
+ }
+ }
+
+ return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
+ }
+
+ /**
+ * Log that a permission was revoked.
+ *
+ * @param context Context of the caller
+ * @param name name of the permission
+ * @param packageName package permission if for
+ */
+ private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
+ @NonNull String packageName) {
+ MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
+ }
+
+ /**
+ * Log that a permission request was granted.
+ *
+ * @param context Context of the caller
+ * @param name name of the permission
+ * @param packageName package permission if for
+ */
+ private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
+ @NonNull String packageName) {
+ MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+ }
+
@Override
public void resetRuntimePermissions() {
mContext.enforceCallingOrSelfPermission(
@@ -4917,6 +5042,9 @@
if (mEphemeralResolverConnection == null) {
return false;
}
+ if (mEphemeralInstallerComponent == null) {
+ return false;
+ }
if (intent.getComponent() != null) {
return false;
}
@@ -6194,7 +6322,7 @@
public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, null);
- final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+ final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"get installed packages");
@@ -6278,7 +6406,10 @@
String[] permissions, int flags, int userId) {
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, permissions);
- final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+ enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ true /* requireFullPermission */, false /* checkShell */,
+ "get packages holding permissions");
+ final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -6286,7 +6417,8 @@
boolean[] tmpBools = new boolean[permissions.length];
if (listUninstalled) {
for (PackageSetting ps : mSettings.mPackages.values()) {
- addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId);
+ addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags,
+ userId);
}
} else {
for (PackageParser.Package pkg : mPackages.values()) {
@@ -6306,7 +6438,7 @@
public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForApplication(flags, userId, null);
- final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
+ final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -6315,11 +6447,16 @@
list = new ArrayList<ApplicationInfo>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
ApplicationInfo ai;
+ int effectiveFlags = flags;
+ if (ps.isSystem()) {
+ effectiveFlags |= PackageManager.MATCH_ANY_USER;
+ }
if (ps.pkg != null) {
- ai = PackageParser.generateApplicationInfo(ps.pkg, flags,
+ ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags,
ps.readUserState(userId), userId);
} else {
- ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId);
+ ai = generateApplicationInfoFromSettingsLPw(ps.name, effectiveFlags,
+ userId);
}
if (ai != null) {
list.add(ai);
@@ -6670,7 +6807,7 @@
}
}
- private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
+ private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
@@ -6681,7 +6818,11 @@
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
+ ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
+ mSeparateProcesses, mOnlyCore, mMetrics);
+ // Submit files for parsing in parallel
+ int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
@@ -6689,20 +6830,43 @@
// Ignore entries which are not packages
continue;
}
- try {
- scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
- scanFlags, currentTime, null);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
+ parallelPackageParser.submit(file, parseFlags);
+ fileCount++;
+ }
- // Delete invalid userdata apps
- if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
- e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
- logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
- removeCodePathLI(file);
+ // Process results one by one
+ for (; fileCount > 0; fileCount--) {
+ ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+ Throwable throwable = parseResult.throwable;
+ int errorCode = PackageManager.INSTALL_SUCCEEDED;
+
+ if (throwable == null) {
+ try {
+ scanPackageLI(parseResult.pkg, parseResult.scanFile, parseFlags, scanFlags,
+ currentTime, null);
+ } catch (PackageManagerException e) {
+ errorCode = e.error;
+ Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
+ } else if (throwable instanceof PackageParser.PackageParserException) {
+ PackageParser.PackageParserException e = (PackageParser.PackageParserException)
+ throwable;
+ errorCode = e.error;
+ Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
+ } else {
+ throw new IllegalStateException("Unexpected exception occurred while parsing "
+ + parseResult.scanFile, throwable);
+ }
+
+ // Delete invalid userdata apps
+ if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
+ errorCode == PackageManager.INSTALL_FAILED_INVALID_APK) {
+ logCriticalInfo(Log.WARN,
+ "Deleting invalid package at " + parseResult.scanFile);
+ removeCodePathLI(parseResult.scanFile);
}
}
+ parallelPackageParser.close();
}
private static File getSettingsProblemFile() {
@@ -8055,6 +8219,11 @@
// old setting to restore at the end.
PackageSetting nonMutatedPs = null;
+ // We keep references to the derived CPU Abis from settings in oder to reuse
+ // them in the case where we're not upgrading or booting for the first time.
+ String primaryCpuAbiFromSettings = null;
+ String secondaryCpuAbiFromSettings = null;
+
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
@@ -8131,6 +8300,14 @@
}
}
+ if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {
+ PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
+ if (foundPs != null) {
+ primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
+ secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
+ }
+ }
+
pkgSetting = mSettings.getPackageLPr(pkg.packageName);
if (pkgSetting != null && pkgSetting.sharedUser != suid) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -8163,7 +8340,11 @@
}
mSettings.addUserToSettingLPw(pkgSetting);
} else {
- // REMOVE SharedUserSetting from method; update in a separate call
+ // REMOVE SharedUserSetting from method; update in a separate call.
+ //
+ // TODO(narayan): This update is bogus. nativeLibraryDir & primaryCpuAbi,
+ // secondaryCpuAbi are not known at this point so we always update them
+ // to null here, only to reset them at a later point.
Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
@@ -8302,18 +8483,34 @@
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
- derivePackageAbi(
- pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
+ derivePackageAbi(
+ pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- // Some system apps still use directory structure for native libraries
- // in which case we might end up not detecting abi solely based on apk
- // structure. Try to detect abi based on directory structure.
- if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
- pkg.applicationInfo.primaryCpuAbi == null) {
- setBundledAppAbisAndRoots(pkg, pkgSetting);
+ // Some system apps still use directory structure for native libraries
+ // in which case we might end up not detecting abi solely based on apk
+ // structure. Try to detect abi based on directory structure.
+ if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
+ pkg.applicationInfo.primaryCpuAbi == null) {
+ setBundledAppAbisAndRoots(pkg, pkgSetting);
+ setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+ }
+ } else {
+ // This is not a first boot or an upgrade, don't bother deriving the
+ // ABI during the scan. Instead, trust the value that was stored in the
+ // package setting.
+ pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
+ pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
+
setNativeLibraryPaths(pkg, mAppLib32InstallDir);
+
+ if (DEBUG_ABI_SELECTION) {
+ Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
+ pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " +
+ pkg.applicationInfo.secondaryCpuAbi);
+ }
}
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
@@ -9168,11 +9365,6 @@
String cpuAbiOverride, boolean extractLibs,
File appLib32InstallDir)
throws PackageManagerException {
- // TODO: We can probably be smarter about this stuff. For installed apps,
- // we can calculate this information at install time once and for all. For
- // system apps, we can probably assume that this information doesn't change
- // after the first boot scan. As things stand, we do lots of unnecessary work.
-
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
setNativeLibraryPaths(pkg, appLib32InstallDir);
@@ -9431,11 +9623,21 @@
}
private void setUpEphemeralInstallerActivityLP(ComponentName installerComponent) {
- final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
+ if (installerComponent == null) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.d(TAG, "Clear ephemeral installer activity");
+ }
+ mEphemeralInstallerActivity.applicationInfo = null;
+ return;
+ }
+ if (DEBUG_EPHEMERAL) {
+ Slog.d(TAG, "Set ephemeral installer activity: " + installerComponent);
+ }
+ final PackageParser.Package pkg = mPackages.get(installerComponent.getPackageName());
// Set up information for ephemeral installer activity
mEphemeralInstallerActivity.applicationInfo = pkg.applicationInfo;
- mEphemeralInstallerActivity.name = mEphemeralInstallerComponent.getClassName();
+ mEphemeralInstallerActivity.name = installerComponent.getClassName();
mEphemeralInstallerActivity.packageName = pkg.applicationInfo.packageName;
mEphemeralInstallerActivity.processName = pkg.applicationInfo.packageName;
mEphemeralInstallerActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
@@ -9450,10 +9652,6 @@
mEphemeralInstallerInfo.isDefault = true;
mEphemeralInstallerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
| IntentFilter.MATCH_ADJUSTMENT_NORMAL;
-
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Set ephemeral installer activity: " + mEphemeralInstallerComponent);
- }
}
private static String calculateBundledApkRoot(final String codePathString) {
@@ -10365,18 +10563,21 @@
BasePermission bp, PermissionsState origPermissions) {
boolean privilegedPermission = (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0;
- boolean controlPrivappPermissions = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS;
+ boolean privappPermissionsDisable =
+ RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE;
boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage);
boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName);
- if (controlPrivappPermissions && privilegedPermission && pkg.isPrivilegedApp()
+ if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp()
&& !platformPackage && platformPermission) {
ArraySet<String> wlPermissions = SystemConfig.getInstance()
.getPrivAppPermissions(pkg.packageName);
boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
if (!whitelisted) {
- // Log for now. TODO Enforce permissions
Slog.w(TAG, "Privileged permission " + perm + " for package "
+ pkg.packageName + " - not in privapp-permissions whitelist");
+ if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
+ return false;
+ }
}
}
boolean allowed = (compareSignatures(
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 834d343..fd2b504 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -610,7 +610,7 @@
showUid = true;
break;
case "-u":
- getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
+ getFlags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
break;
case "-3":
listThirdParty = true;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 3ad2ae1..6089d2e 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -76,14 +76,12 @@
String legacyNativeLibraryPathString;
/**
- * The primary CPU abi for this package. This value is regenerated at every
- * boot scan.
+ * The primary CPU abi for this package.
*/
String primaryCpuAbiString;
/**
- * The secondary CPU abi for this package. This value is regenerated at every
- * boot scan.
+ * The secondary CPU abi for this package.
*/
String secondaryCpuAbiString;
diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java
new file mode 100644
index 0000000..158cfc94
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java
@@ -0,0 +1,158 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.PackageParser;
+import android.os.Process;
+import android.os.Trace;
+import android.util.DisplayMetrics;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+/**
+ * Helper class for parallel parsing of packages using {@link PackageParser}.
+ * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}.
+ * At any time, at most {@link #QUEUE_CAPACITY} results are kept in RAM</p>
+ */
+class ParallelPackageParser implements AutoCloseable {
+
+ private static final int QUEUE_CAPACITY = 10;
+ private static final int MAX_THREADS = 4;
+
+ private final String[] mSeparateProcesses;
+ private final boolean mOnlyCore;
+ private final DisplayMetrics mMetrics;
+ private volatile String mInterruptedInThread;
+
+ private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
+
+ private final ExecutorService mService = Executors.newFixedThreadPool(MAX_THREADS,
+ new ThreadFactory() {
+ private final AtomicInteger threadNum = new AtomicInteger(0);
+
+ @Override
+ public Thread newThread(final Runnable r) {
+ return new Thread("package-parsing-thread" + threadNum.incrementAndGet()) {
+ @Override
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+ r.run();
+ }
+ };
+ }
+ });
+
+ ParallelPackageParser(String[] separateProcesses, boolean onlyCoreApps,
+ DisplayMetrics metrics) {
+ mSeparateProcesses = separateProcesses;
+ mOnlyCore = onlyCoreApps;
+ mMetrics = metrics;
+ }
+
+ static class ParseResult {
+
+ PackageParser.Package pkg; // Parsed package
+ File scanFile; // File that was parsed
+ Throwable throwable; // Set if an error occurs during parsing
+
+ @Override
+ public String toString() {
+ return "ParseResult{" +
+ "pkg=" + pkg +
+ ", scanFile=" + scanFile +
+ ", throwable=" + throwable +
+ '}';
+ }
+ }
+
+ /**
+ * Take the parsed package from the parsing queue, waiting if necessary until the element
+ * appears in the queue.
+ * @return parsed package
+ */
+ public ParseResult take() {
+ try {
+ if (mInterruptedInThread != null) {
+ throw new InterruptedException("Interrupted in " + mInterruptedInThread);
+ }
+ return mQueue.take();
+ } catch (InterruptedException e) {
+ // We cannot recover from interrupt here
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Submits the file for parsing
+ * @param scanFile file to scan
+ * @param parseFlags parse falgs
+ */
+ public void submit(File scanFile, int parseFlags) {
+ mService.submit(() -> {
+ ParseResult pr = new ParseResult();
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
+ try {
+ PackageParser pp = new PackageParser();
+ pp.setSeparateProcesses(mSeparateProcesses);
+ pp.setOnlyCoreApps(mOnlyCore);
+ pp.setDisplayMetrics(mMetrics);
+ pr.scanFile = scanFile;
+ pr.pkg = parsePackage(pp, scanFile, parseFlags);
+ } catch (Throwable e) {
+ pr.throwable = e;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ try {
+ mQueue.put(pr);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ // Propagate result to callers of take().
+ // This is helpful to prevent main thread from getting stuck waiting on
+ // ParallelPackageParser to finish in case of interruption
+ mInterruptedInThread = Thread.currentThread().getName();
+ }
+ });
+ }
+
+ @VisibleForTesting
+ protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+ int parseFlags) throws PackageParser.PackageParserException {
+ return packageParser.parsePackage(scanFile, parseFlags);
+ }
+
+ @Override
+ public void close() {
+ List<Runnable> unfinishedTasks = mService.shutdownNow();
+ if (!unfinishedTasks.isEmpty()) {
+ throw new IllegalStateException("Not all tasks finished before calling close: "
+ + unfinishedTasks);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 1f195a7..e59d69f 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -106,27 +106,31 @@
}
return; // Not installed, no need to restore yet.
}
+ boolean blockRestore = false;
if (!mPackageInfo.hasSignatures()) {
s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
+ " but signatures not found in the restore data.");
+ blockRestore = true;
+ }
+ if (!blockRestore) {
+ final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
+ if (!mPackageInfo.canRestoreTo(s, pi)) {
+ // Package is now installed, but can't restore. Let the subclass do the cleanup.
+ blockRestore = true;
+ }
+ }
+ if (blockRestore) {
onRestoreBlocked();
- return;
+ } else {
+ if (ShortcutService.DEBUG) {
+ Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
+ mPackageUserId, getOwnerUserId()));
+ }
+
+ onRestored();
}
- final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
- if (!mPackageInfo.canRestoreTo(s, pi)) {
- // Package is now installed, but can't restore. Let the subclass do the cleanup.
- onRestoreBlocked();
- return;
- }
- if (ShortcutService.DEBUG) {
- Slog.d(TAG, String.format("Restored package: %s/%d on user %d", mPackageName,
- mPackageUserId, getOwnerUserId()));
- }
-
- onRestored();
-
- // Now the package is not shadow.
+ // Either way, it's no longer a shadow.
mPackageInfo.setShadow(false);
s.scheduleSaveUser(mPackageUserId);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 87b10dd..c5c1c0c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3739,6 +3739,16 @@
}
}
+ @VisibleForTesting
+ ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) {
+ synchronized (mLock) {
+ final ShortcutUser user = mUsers.get(userId);
+ if (user == null) return null;
+
+ return user.getAllLaunchersForTest().get(PackageWithUser.of(userId, packageName));
+ }
+ }
+
/**
* Control whether {@link #verifyStates} should be performed. We always perform it during unit
* tests.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5b47b6f..c4241e7 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -63,6 +63,7 @@
import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -110,6 +111,8 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
@@ -149,6 +152,7 @@
private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
+ private static final String ATTR_PROFILE_BADGE = "profileBadge";
private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
private static final String ATTR_SEED_ACCOUNT_NAME = "seedAccountName";
private static final String ATTR_SEED_ACCOUNT_TYPE = "seedAccountType";
@@ -203,7 +207,8 @@
// Maximum number of managed profiles permitted per user is 1. This cannot be increased
// without first making sure that the rest of the framework is prepared for it.
- private static final int MAX_MANAGED_PROFILES = 1;
+ @VisibleForTesting
+ static final int MAX_MANAGED_PROFILES = 1;
static final int WRITE_USER_MSG = 1;
static final int WRITE_USER_DELAY = 2*1000; // 2 seconds
@@ -232,7 +237,8 @@
* User-related information that is used for persisting to flash. Only UserInfo is
* directly exposed to other system apps.
*/
- private static class UserData {
+ @VisibleForTesting
+ static class UserData {
// Basic user information and properties
UserInfo info;
// Account name used when there is a strong association between a user and an account
@@ -874,6 +880,22 @@
}
@Override
+ public int getManagedProfileBadge(@UserIdInt int userId) {
+ int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId && !hasManageUsersPermission()) {
+ if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
+ throw new SecurityException(
+ "You need MANAGE_USERS permission to: check if specified user a " +
+ "managed profile outside your profile group");
+ }
+ }
+ synchronized (mUsersLock) {
+ UserInfo userInfo = getUserInfoLU(userId);
+ return userInfo != null ? userInfo.profileBadge : 0;
+ }
+ }
+
+ @Override
public boolean isManagedProfile(int userId) {
int callingUserId = UserHandle.getCallingUserId();
if (callingUserId != userId && !hasManageUsersPermission()) {
@@ -1464,7 +1486,7 @@
// Limit number of managed profiles that can be created
final int managedProfilesCount = getProfiles(userId, true).size() - 1;
final int profilesRemovedCount = managedProfilesCount > 0 && allowedToRemoveOne ? 1 : 0;
- if (managedProfilesCount - profilesRemovedCount >= MAX_MANAGED_PROFILES) {
+ if (managedProfilesCount - profilesRemovedCount >= getMaxManagedProfiles()) {
return false;
}
synchronized(mUsersLock) {
@@ -1859,13 +1881,6 @@
}
}
- /*
- * Writes the user file in this format:
- *
- * <user flags="20039023" id="0">
- * <name>Primary</name>
- * </user>
- */
private void writeUserLP(UserData userData) {
if (DBG) {
debug("writeUserLP " + userData);
@@ -1875,78 +1890,7 @@
try {
fos = userFile.startWrite();
final BufferedOutputStream bos = new BufferedOutputStream(fos);
-
- // XmlSerializer serializer = XmlUtils.serializerInstance();
- final XmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(bos, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
- final UserInfo userInfo = userData.info;
- serializer.startTag(null, TAG_USER);
- serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
- serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
- serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
- serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
- serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
- Long.toString(userInfo.lastLoggedInTime));
- if (userInfo.lastLoggedInFingerprint != null) {
- serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
- userInfo.lastLoggedInFingerprint);
- }
- if (userInfo.iconPath != null) {
- serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
- }
- if (userInfo.partial) {
- serializer.attribute(null, ATTR_PARTIAL, "true");
- }
- if (userInfo.guestToRemove) {
- serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
- }
- if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
- serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
- Integer.toString(userInfo.profileGroupId));
- }
- if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
- serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
- Integer.toString(userInfo.restrictedProfileParentId));
- }
- // Write seed data
- if (userData.persistSeedData) {
- if (userData.seedAccountName != null) {
- serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
- }
- if (userData.seedAccountType != null) {
- serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
- }
- }
- if (userInfo.name != null) {
- serializer.startTag(null, TAG_NAME);
- serializer.text(userInfo.name);
- serializer.endTag(null, TAG_NAME);
- }
- synchronized (mRestrictionsLock) {
- UserRestrictionsUtils.writeRestrictions(serializer,
- mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
- UserRestrictionsUtils.writeRestrictions(serializer,
- mDevicePolicyLocalUserRestrictions.get(userInfo.id),
- TAG_DEVICE_POLICY_RESTRICTIONS);
- }
-
- if (userData.account != null) {
- serializer.startTag(null, TAG_ACCOUNT);
- serializer.text(userData.account);
- serializer.endTag(null, TAG_ACCOUNT);
- }
-
- if (userData.persistSeedData && userData.seedAccountOptions != null) {
- serializer.startTag(null, TAG_SEED_ACCOUNT_OPTIONS);
- userData.seedAccountOptions.saveToXml(serializer);
- serializer.endTag(null, TAG_SEED_ACCOUNT_OPTIONS);
- }
- serializer.endTag(null, TAG_USER);
-
- serializer.endDocument();
+ writeUserLP(userData, bos);
userFile.finishWrite(fos);
} catch (Exception ioe) {
Slog.e(LOG_TAG, "Error writing user info " + userData.info.id, ioe);
@@ -1955,6 +1899,92 @@
}
/*
+ * Writes the user file in this format:
+ *
+ * <user flags="20039023" id="0">
+ * <name>Primary</name>
+ * </user>
+ */
+ @VisibleForTesting
+ void writeUserLP(UserData userData, OutputStream os)
+ throws IOException, XmlPullParserException {
+ // XmlSerializer serializer = XmlUtils.serializerInstance();
+ final XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(os, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ final UserInfo userInfo = userData.info;
+ serializer.startTag(null, TAG_USER);
+ serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
+ serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
+ serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
+ serializer.attribute(null, ATTR_CREATION_TIME, Long.toString(userInfo.creationTime));
+ serializer.attribute(null, ATTR_LAST_LOGGED_IN_TIME,
+ Long.toString(userInfo.lastLoggedInTime));
+ if (userInfo.lastLoggedInFingerprint != null) {
+ serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
+ userInfo.lastLoggedInFingerprint);
+ }
+ if (userInfo.iconPath != null) {
+ serializer.attribute(null, ATTR_ICON_PATH, userInfo.iconPath);
+ }
+ if (userInfo.partial) {
+ serializer.attribute(null, ATTR_PARTIAL, "true");
+ }
+ if (userInfo.guestToRemove) {
+ serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+ }
+ if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+ serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
+ Integer.toString(userInfo.profileGroupId));
+ }
+ serializer.attribute(null, ATTR_PROFILE_BADGE,
+ Integer.toString(userInfo.profileBadge));
+ if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
+ serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
+ Integer.toString(userInfo.restrictedProfileParentId));
+ }
+ // Write seed data
+ if (userData.persistSeedData) {
+ if (userData.seedAccountName != null) {
+ serializer.attribute(null, ATTR_SEED_ACCOUNT_NAME, userData.seedAccountName);
+ }
+ if (userData.seedAccountType != null) {
+ serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType);
+ }
+ }
+ if (userInfo.name != null) {
+ serializer.startTag(null, TAG_NAME);
+ serializer.text(userInfo.name);
+ serializer.endTag(null, TAG_NAME);
+ }
+ synchronized (mRestrictionsLock) {
+ UserRestrictionsUtils.writeRestrictions(serializer,
+ mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS);
+ UserRestrictionsUtils.writeRestrictions(serializer,
+ mDevicePolicyLocalUserRestrictions.get(userInfo.id),
+ TAG_DEVICE_POLICY_RESTRICTIONS);
+ }
+
+ if (userData.account != null) {
+ serializer.startTag(null, TAG_ACCOUNT);
+ serializer.text(userData.account);
+ serializer.endTag(null, TAG_ACCOUNT);
+ }
+
+ if (userData.persistSeedData && userData.seedAccountOptions != null) {
+ serializer.startTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+ userData.seedAccountOptions.saveToXml(serializer);
+ serializer.endTag(null, TAG_SEED_ACCOUNT_OPTIONS);
+ }
+
+ serializer.endTag(null, TAG_USER);
+
+ serializer.endDocument();
+ }
+
+ /*
* Writes the user list file in this format:
*
* <users nextSerialNumber="3">
@@ -2020,6 +2050,25 @@
}
private UserData readUserLP(int id) {
+ FileInputStream fis = null;
+ try {
+ AtomicFile userFile =
+ new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX));
+ fis = userFile.openRead();
+ return readUserLP(id, fis);
+ } catch (IOException ioe) {
+ Slog.e(LOG_TAG, "Error reading user list");
+ } catch (XmlPullParserException pe) {
+ Slog.e(LOG_TAG, "Error reading user list");
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ UserData readUserLP(int id, InputStream is) throws IOException,
+ XmlPullParserException {
int flags = 0;
int serialNumber = id;
String name = null;
@@ -2029,6 +2078,7 @@
long lastLoggedInTime = 0L;
String lastLoggedInFingerprint = null;
int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+ int profileBadge = 0;
int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
boolean partial = false;
boolean guestToRemove = false;
@@ -2039,120 +2089,106 @@
Bundle baseRestrictions = new Bundle();
Bundle localRestrictions = new Bundle();
- FileInputStream fis = null;
- try {
- AtomicFile userFile =
- new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX));
- fis = userFile.openRead();
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, StandardCharsets.UTF_8.name());
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Skip
- }
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(is, StandardCharsets.UTF_8.name());
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Skip
+ }
- if (type != XmlPullParser.START_TAG) {
- Slog.e(LOG_TAG, "Unable to read user " + id);
+ if (type != XmlPullParser.START_TAG) {
+ Slog.e(LOG_TAG, "Unable to read user " + id);
+ return null;
+ }
+
+ if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
+ int storedId = readIntAttribute(parser, ATTR_ID, -1);
+ if (storedId != id) {
+ Slog.e(LOG_TAG, "User id does not match the file name");
return null;
}
+ serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);
+ flags = readIntAttribute(parser, ATTR_FLAGS, 0);
+ iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
+ creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
+ lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
+ lastLoggedInFingerprint = parser.getAttributeValue(null,
+ ATTR_LAST_LOGGED_IN_FINGERPRINT);
+ profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
+ UserInfo.NO_PROFILE_GROUP_ID);
+ profileBadge = readIntAttribute(parser, ATTR_PROFILE_BADGE, 0);
+ restrictedProfileParentId = readIntAttribute(parser,
+ ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
+ String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
+ if ("true".equals(valueString)) {
+ partial = true;
+ }
+ valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
+ if ("true".equals(valueString)) {
+ guestToRemove = true;
+ }
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
- int storedId = readIntAttribute(parser, ATTR_ID, -1);
- if (storedId != id) {
- Slog.e(LOG_TAG, "User id does not match the file name");
- return null;
- }
- serialNumber = readIntAttribute(parser, ATTR_SERIAL_NO, id);
- flags = readIntAttribute(parser, ATTR_FLAGS, 0);
- iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
- creationTime = readLongAttribute(parser, ATTR_CREATION_TIME, 0);
- lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
- lastLoggedInFingerprint = parser.getAttributeValue(null,
- ATTR_LAST_LOGGED_IN_FINGERPRINT);
- profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
- UserInfo.NO_PROFILE_GROUP_ID);
- restrictedProfileParentId = readIntAttribute(parser,
- ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
- String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
- if ("true".equals(valueString)) {
- partial = true;
- }
- valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
- if ("true".equals(valueString)) {
- guestToRemove = true;
- }
+ seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
+ seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
+ if (seedAccountName != null || seedAccountType != null) {
+ persistSeedData = true;
+ }
- seedAccountName = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_NAME);
- seedAccountType = parser.getAttributeValue(null, ATTR_SEED_ACCOUNT_TYPE);
- if (seedAccountName != null || seedAccountType != null) {
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tag = parser.getName();
+ if (TAG_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ name = parser.getText();
+ }
+ } else if (TAG_RESTRICTIONS.equals(tag)) {
+ UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
+ } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
+ UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+ } else if (TAG_ACCOUNT.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ account = parser.getText();
+ }
+ } else if (TAG_SEED_ACCOUNT_OPTIONS.equals(tag)) {
+ seedAccountOptions = PersistableBundle.restoreFromXml(parser);
persistSeedData = true;
}
-
- int outerDepth = parser.getDepth();
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
- String tag = parser.getName();
- if (TAG_NAME.equals(tag)) {
- type = parser.next();
- if (type == XmlPullParser.TEXT) {
- name = parser.getText();
- }
- } else if (TAG_RESTRICTIONS.equals(tag)) {
- UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
- } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
- UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
- } else if (TAG_ACCOUNT.equals(tag)) {
- type = parser.next();
- if (type == XmlPullParser.TEXT) {
- account = parser.getText();
- }
- } else if (TAG_SEED_ACCOUNT_OPTIONS.equals(tag)) {
- seedAccountOptions = PersistableBundle.restoreFromXml(parser);
- persistSeedData = true;
- }
- }
- }
-
- // Create the UserInfo object that gets passed around
- UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
- userInfo.serialNumber = serialNumber;
- userInfo.creationTime = creationTime;
- userInfo.lastLoggedInTime = lastLoggedInTime;
- userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
- userInfo.partial = partial;
- userInfo.guestToRemove = guestToRemove;
- userInfo.profileGroupId = profileGroupId;
- userInfo.restrictedProfileParentId = restrictedProfileParentId;
-
- // Create the UserData object that's internal to this class
- UserData userData = new UserData();
- userData.info = userInfo;
- userData.account = account;
- userData.seedAccountName = seedAccountName;
- userData.seedAccountType = seedAccountType;
- userData.persistSeedData = persistSeedData;
- userData.seedAccountOptions = seedAccountOptions;
-
- synchronized (mRestrictionsLock) {
- mBaseUserRestrictions.put(id, baseRestrictions);
- mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
- }
- return userData;
- } catch (IOException ioe) {
- } catch (XmlPullParserException pe) {
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- }
}
}
- return null;
+
+ // Create the UserInfo object that gets passed around
+ UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
+ userInfo.serialNumber = serialNumber;
+ userInfo.creationTime = creationTime;
+ userInfo.lastLoggedInTime = lastLoggedInTime;
+ userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
+ userInfo.partial = partial;
+ userInfo.guestToRemove = guestToRemove;
+ userInfo.profileGroupId = profileGroupId;
+ userInfo.profileBadge = profileBadge;
+ userInfo.restrictedProfileParentId = restrictedProfileParentId;
+
+ // Create the UserData object that's internal to this class
+ UserData userData = new UserData();
+ userData.info = userInfo;
+ userData.account = account;
+ userData.seedAccountName = seedAccountName;
+ userData.seedAccountType = seedAccountType;
+ userData.persistSeedData = persistSeedData;
+ userData.seedAccountOptions = seedAccountOptions;
+
+ synchronized (mRestrictionsLock) {
+ mBaseUserRestrictions.put(id, baseRestrictions);
+ mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+ }
+ return userData;
}
private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
@@ -2316,6 +2352,9 @@
userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
userInfo.partial = true;
userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
+ if (isManagedProfile && parentId != UserHandle.USER_NULL) {
+ userInfo.profileBadge = getFreeProfileBadgeLU(parentId);
+ }
userData = new UserData();
userData.info = userInfo;
mUsers.put(userId, userData);
@@ -2677,7 +2716,7 @@
public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkSystemOrRoot("get application restrictions for other users/apps");
+ checkSystemOrRoot("get application restrictions for other user/app " + packageName);
}
synchronized (mPackagesLock) {
// Read the restrictions from XML
@@ -2712,7 +2751,7 @@
long ident = Binder.clearCallingIdentity();
try {
return mContext.getPackageManager().getApplicationInfo(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES).uid;
+ PackageManager.MATCH_ANY_USER).uid;
} catch (NameNotFoundException nnfe) {
return -1;
} finally {
@@ -3643,4 +3682,58 @@
Log.d(LOG_TAG, message +
(DBG_WITH_STACKTRACE ? " called at\n" + Debug.getCallers(10, " ") : ""));
}
+
+ @VisibleForTesting
+ static int getMaxManagedProfiles() {
+ // Allow overriding max managed profiles on debuggable builds for testing
+ // of multiple profiles.
+ if (!Build.IS_DEBUGGABLE) {
+ return MAX_MANAGED_PROFILES;
+ } else {
+ return SystemProperties.getInt("persist.sys.max_profiles",
+ MAX_MANAGED_PROFILES);
+ }
+ }
+
+ @VisibleForTesting
+ int getFreeProfileBadgeLU(int parentUserId) {
+ int maxManagedProfiles = getMaxManagedProfiles();
+ boolean[] usedBadges = new boolean[maxManagedProfiles];
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo ui = mUsers.valueAt(i).info;
+ // Check which badge indexes are already used by this profile group.
+ if (ui.isManagedProfile()
+ && ui.profileGroupId == parentUserId
+ && !mRemovingUserIds.get(ui.id)
+ && ui.profileBadge < maxManagedProfiles) {
+ usedBadges[ui.profileBadge] = true;
+ }
+ }
+ for (int i = 0; i < maxManagedProfiles; i++) {
+ if (!usedBadges[i]) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Checks if the given user has a managed profile associated with it.
+ * @param userId The parent user
+ * @return
+ */
+ boolean hasManagedProfile(int userId) {
+ synchronized (mUsersLock) {
+ UserInfo userInfo = getUserInfoLU(userId);
+ final int userSize = mUsers.size();
+ for (int i = 0; i < userSize; i++) {
+ UserInfo profile = mUsers.valueAt(i).info;
+ if (userId != profile.id && isProfileOf(userInfo, profile)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ccdda13..a1cce2b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -216,6 +216,7 @@
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.statusbar.IStatusBarService;
@@ -264,6 +265,7 @@
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
static final int SHORT_PRESS_POWER_GO_HOME = 4;
+ static final int SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME = 5;
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
@@ -1344,6 +1346,14 @@
case SHORT_PRESS_POWER_GO_HOME:
launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
break;
+ case SHORT_PRESS_POWER_CLOSE_IME_OR_GO_HOME:
+ if (mWindowManagerFuncs.isInputMethodWindowVisible()) {
+ mWindowManagerFuncs.hideCurrentInputMethod();
+ } else {
+ launchHomeFromHotKey(true /* awakenFromDreams */,
+ false /*respectKeyguard*/);
+ }
+ break;
}
}
}
@@ -6631,12 +6641,18 @@
}
@Override
- public void dismissKeyguardLw() {
+ public void dismissKeyguardLw(IKeyguardDismissCallback callback) {
if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
// ask the keyguard to prompt the user to authenticate if necessary
- mKeyguardDelegate.dismiss(true /* allowWhileOccluded */);
+ mKeyguardDelegate.dismiss(callback);
+ } else if (callback != null) {
+ try {
+ callback.onDismissError();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call callback", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index f37f987..1b4eaf5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -15,6 +15,7 @@
import android.util.Slog;
import android.view.WindowManagerPolicy.OnKeyguardExitResult;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
@@ -244,9 +245,9 @@
mKeyguardState.occluded = isOccluded;
}
- public void dismiss(boolean allowWhileOccluded) {
+ public void dismiss(IKeyguardDismissCallback callback) {
if (mKeyguardService != null) {
- mKeyguardService.dismiss(allowWhileOccluded);
+ mKeyguardService.dismiss(callback);
}
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index c4a0dd3..0b839b8 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -22,6 +22,7 @@
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
@@ -73,9 +74,9 @@
}
@Override // Binder interface
- public void dismiss(boolean allowWhileOccluded) {
+ public void dismiss(IKeyguardDismissCallback callback) {
try {
- mService.dismiss(allowWhileOccluded);
+ mService.dismiss(callback);
} catch (RemoteException e) {
Slog.w(TAG , "Remote Exception", e);
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 61319cf..7ba95a4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -291,5 +291,5 @@
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
| PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ | PackageManager.MATCH_ANY_USER;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 5d739d1..5838a37 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1103,6 +1103,11 @@
return mOrientation;
}
+ /** Returns the app's preferred orientation regardless of its currently visibility state. */
+ int getOrientationIgnoreVisibility() {
+ return mOrientation;
+ }
+
@Override
void checkAppWindowsReadyToShow() {
if (allDrawn == mAppAnimator.allDrawn) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b089ec..51e8a56 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.Manifest;
+import android.Manifest.permission;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -125,6 +126,7 @@
import com.android.internal.R;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.view.IInputContext;
@@ -212,6 +214,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -1412,7 +1415,8 @@
winAnimator.mEnterAnimationPending = true;
winAnimator.mEnteringAnimation = true;
// Check if we need to prepare a transition for replacing window first.
- if (atoken != null && !prepareWindowReplacementTransition(atoken)) {
+ if (atoken != null && atoken.isVisible()
+ && !prepareWindowReplacementTransition(atoken)) {
// If not, check if need to set up a dummy transition during display freeze
// so that the unfreeze wait for the apps to draw. This might be needed if
// the app is relaunching.
@@ -2713,7 +2717,7 @@
return SCREEN_ORIENTATION_UNSPECIFIED;
}
- return wtoken.getOrientation();
+ return wtoken.getOrientationIgnoreVisibility();
}
}
@@ -3935,20 +3939,13 @@
}
@Override
- public void dismissKeyguard() {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Requires DISABLE_KEYGUARD permission");
- }
+ public void dismissKeyguard(IKeyguardDismissCallback callback) {
+ checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard");
synchronized(mWindowMap) {
- mPolicy.dismissKeyguardLw();
+ mPolicy.dismissKeyguardLw(callback);
}
}
- @Override
- public void keyguardGoingAway(int flags) {
- }
-
public void onKeyguardOccludedChanged(boolean occluded) {
synchronized (mWindowMap) {
mPolicy.onKeyguardOccludedChangedLw(occluded);
@@ -4093,6 +4090,24 @@
}
}
+ // Called by window manager policy. Not exposed externally.
+ @Override
+ public boolean isInputMethodWindowVisible() {
+ synchronized (mWindowMap) {
+ return mInputMethodWindow != null && mInputMethodWindow.isVisibleLw();
+ }
+ }
+
+ // Called by window manager policy. Not exposed externally.
+ @Override
+ public void hideCurrentInputMethod() {
+ final InputMethodManagerInternal inputMethodManagerInternal =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ if (inputMethodManagerInternal != null) {
+ inputMethodManagerInternal.hideCurrentInputMethod();
+ }
+ }
+
// Called by window manager policy. Not exposed externally.
@Override
public void lockDeviceNow() {
@@ -6475,7 +6490,15 @@
case SEND_NEW_CONFIGURATION: {
removeMessages(SEND_NEW_CONFIGURATION, msg.obj);
final int displayId = (Integer) msg.obj;
- sendNewConfiguration(displayId);
+ if (mRoot.getDisplayContent(displayId) != null) {
+ sendNewConfiguration(displayId);
+ } else {
+ // Message could come after display has already been removed.
+ if (DEBUG_CONFIGURATION) {
+ Slog.w(TAG, "Trying to send configuration to non-existing displayId="
+ + displayId);
+ }
+ }
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 59c9102..572581e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3190,7 +3190,8 @@
}
boolean isDockedResizing() {
- return mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
+ return (mDragResizing && getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER)
+ || (isChildWindow() && getParentWindow().isDockedResizing());
}
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
@@ -4144,6 +4145,105 @@
}
}
+ /**
+ * Calculate the window crop according to system decor policy. In general this is
+ * the system decor rect (see #calculateSystemDecorRect), but we also have some
+ * special cases. This rectangle is in screen space.
+ */
+ void calculatePolicyCrop(Rect policyCrop) {
+ final DisplayContent displayContent = getDisplayContent();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+
+ if (!isDefaultDisplay()) {
+ // On a different display there is no system decor. Crop the window
+ // by the screen boundaries.
+ // TODO(multi-display)
+ policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+ policyCrop.intersect(-mCompatFrame.left, -mCompatFrame.top,
+ displayInfo.logicalWidth - mCompatFrame.left,
+ displayInfo.logicalHeight - mCompatFrame.top);
+ } else if (mLayer >= mService.mSystemDecorLayer) {
+ // Above the decor layer is easy, just use the entire window
+ policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+ } else if (mDecorFrame.isEmpty()) {
+ // Windows without policy decor aren't cropped.
+ policyCrop.set(0, 0, mCompatFrame.width(), mCompatFrame.height());
+ } else {
+ // Crop to the system decor specified by policy.
+ calculateSystemDecorRect(policyCrop);
+ }
+ }
+
+ /**
+ * The system decor rect is the region of the window which is not covered
+ * by system decorations.
+ */
+ private void calculateSystemDecorRect(Rect systemDecorRect) {
+ final Rect decorRect = mDecorFrame;
+ final int width = mFrame.width();
+ final int height = mFrame.height();
+
+ // Compute the offset of the window in relation to the decor rect.
+ final int left = mXOffset + mFrame.left;
+ final int top = mYOffset + mFrame.top;
+
+ // Initialize the decor rect to the entire frame.
+ if (isDockedResizing()) {
+ // If we are resizing with the divider, the task bounds might be smaller than the
+ // stack bounds. The system decor is used to clip to the task bounds, which we don't
+ // want in this case in order to avoid holes.
+ //
+ // We take care to not shrink the width, for surfaces which are larger than
+ // the display region. Of course this area will not eventually be visible
+ // but if we truncate the width now, we will calculate incorrectly
+ // when adjusting to the stack bounds.
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ systemDecorRect.set(0, 0,
+ Math.max(width, displayInfo.logicalWidth),
+ Math.max(height, displayInfo.logicalHeight));
+ } else {
+ systemDecorRect.set(0, 0, width, height);
+ }
+
+ // If a freeform window is animating from a position where it would be cutoff, it would be
+ // cutoff during the animation. We don't want that, so for the duration of the animation
+ // we ignore the decor cropping and depend on layering to position windows correctly.
+ final boolean cropToDecor = !(inFreeformWorkspace() && isAnimatingLw());
+ if (cropToDecor) {
+ // Intersect with the decor rect, offsetted by window position.
+ systemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
+ decorRect.right - left, decorRect.bottom - top);
+ }
+
+ // If size compatibility is being applied to the window, the
+ // surface is scaled relative to the screen. Also apply this
+ // scaling to the crop rect. We aren't using the standard rect
+ // scale function because we want to round things to make the crop
+ // always round to a larger rect to ensure we don't crop too
+ // much and hide part of the window that should be seen.
+ if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) {
+ final float scale = mInvGlobalScale;
+ systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
+ systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
+ systemDecorRect.right = (int) ((systemDecorRect.right + 1) * scale - 0.5f);
+ systemDecorRect.bottom = (int) ((systemDecorRect.bottom + 1) * scale - 0.5f);
+ }
+
+ }
+
+ /**
+ * Expand the given rectangle by this windows surface insets. This
+ * takes you from the 'window size' to the 'surface size'.
+ * The surface insets are positive in each direction, so we inset by
+ * the inverse.
+ */
+ void expandForSurfaceInsets(Rect r) {
+ r.inset(-mAttrs.surfaceInsets.left,
+ -mAttrs.surfaceInsets.top,
+ -mAttrs.surfaceInsets.right,
+ -mAttrs.surfaceInsets.bottom);
+ }
+
// TODO: Hack to work around the number of states AppWindowToken needs to access without having
// access to its windows children. Need to investigate re-writing
// {@link AppWindowToken#updateReportedVisibilityLocked} so this can be removed.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a428cce..04db499 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -22,6 +22,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.AppWindowAnimator.sDummyAnimation;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
@@ -1068,99 +1069,75 @@
}
}
- private void calculateSystemDecorRect() {
- final WindowState w = mWin;
- final Rect decorRect = w.mDecorFrame;
- final int width = w.mFrame.width();
- final int height = w.mFrame.height();
-
- // Compute the offset of the window in relation to the decor rect.
- final int left = w.mXOffset + w.mFrame.left;
- final int top = w.mYOffset + w.mFrame.top;
-
- // Initialize the decor rect to the entire frame.
- if (w.isDockedResizing() ||
- (w.isChildWindow() && w.getParentWindow().isDockedResizing())) {
-
- // If we are resizing with the divider, the task bounds might be smaller than the
- // stack bounds. The system decor is used to clip to the task bounds, which we don't
- // want in this case in order to avoid holes.
- //
- // We take care to not shrink the width, for surfaces which are larger than
- // the display region. Of course this area will not eventually be visible
- // but if we truncate the width now, we will calculate incorrectly
- // when adjusting to the stack bounds.
- final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
- mSystemDecorRect.set(0, 0,
- Math.max(width, displayInfo.logicalWidth),
- Math.max(height, displayInfo.logicalHeight));
- } else {
- mSystemDecorRect.set(0, 0, width, height);
- }
-
- // If a freeform window is animating from a position where it would be cutoff, it would be
- // cutoff during the animation. We don't want that, so for the duration of the animation
- // we ignore the decor cropping and depend on layering to position windows correctly.
- final boolean cropToDecor = !(w.inFreeformWorkspace() && w.isAnimatingLw());
- if (cropToDecor) {
- // Intersect with the decor rect, offsetted by window position.
- mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top,
- decorRect.right - left, decorRect.bottom - top);
- }
-
- // If size compatibility is being applied to the window, the
- // surface is scaled relative to the screen. Also apply this
- // scaling to the crop rect. We aren't using the standard rect
- // scale function because we want to round things to make the crop
- // always round to a larger rect to ensure we don't crop too
- // much and hide part of the window that should be seen.
- if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) {
- final float scale = w.mInvGlobalScale;
- mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
- mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
- mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
- mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
- }
+ /**
+ * In some scenarios we use a screen space clip rect (so called, final clip rect)
+ * to crop to stack bounds. Generally because it's easier to deal with while
+ * animating.
+ *
+ * @return True in scenarios where we use the final clip rect for stack clipping.
+ */
+ private boolean useFinalClipRect() {
+ return (isAnimationSet() && resolveStackClip() == STACK_CLIP_AFTER_ANIM)
+ || mDestroyPreservedSurfaceUponRedraw || mWin.inPinnedWorkspace();
}
- void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
+ /**
+ * Calculate the screen-space crop rect and fill finalClipRect.
+ * @return true if finalClipRect has been filled, otherwise,
+ * no screen space crop should be applied.
+ */
+ private boolean calculateFinalCrop(Rect finalClipRect) {
final WindowState w = mWin;
final DisplayContent displayContent = w.getDisplayContent();
+ finalClipRect.setEmpty();
+
if (displayContent == null) {
- clipRect.setEmpty();
- finalClipRect.setEmpty();
- return;
+ return false;
}
+
+ if (!shouldCropToStackBounds() || !useFinalClipRect()) {
+ return false;
+ }
+
+ // Task is non-null per shouldCropToStackBounds
+ final TaskStack stack = w.getTask().mStack;
+ stack.getDimBounds(finalClipRect);
+ w.expandForSurfaceInsets(finalClipRect);
+ return true;
+ }
+
+ /**
+ * Calculate the window-space crop rect and fill clipRect.
+ * @return true if clipRect has been filled otherwise, no window space
+ * crop should be applied.
+ */
+ boolean calculateCrop(Rect clipRect) {
+ final WindowState w = mWin;
+ final DisplayContent displayContent = w.getDisplayContent();
+ clipRect.setEmpty();
+
+ if (displayContent == null) {
+ return false;
+ }
+
+ if (w.inPinnedWorkspace()) {
+ return false;
+ }
+
+ // If we're animating, the wallpaper should only
+ // be updated at the end of the animation.
+ if (w.mAttrs.type == TYPE_WALLPAPER) {
+ return false;
+ }
+
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (DEBUG_WINDOW_CROP) Slog.d(TAG,
"Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
- // Need to recompute a new system decor rect each time.
- if (!w.isDefaultDisplay()) {
- // On a different display there is no system decor. Crop the window
- // by the screen boundaries.
- mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
- mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top,
- displayInfo.logicalWidth - w.mCompatFrame.left,
- displayInfo.logicalHeight - w.mCompatFrame.top);
- } else if (w.mLayer >= mService.mSystemDecorLayer) {
- // Above the decor layer is easy, just use the entire window.
- mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
- } else if (w.mDecorFrame.isEmpty()) {
- // Windows without policy decor aren't cropped.
- mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
- } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.isAnimating()) {
- // If we're animating, the wallpaper crop should only be updated at the end of the
- // animation.
- mTmpClipRect.set(mSystemDecorRect);
- calculateSystemDecorRect();
- mSystemDecorRect.union(mTmpClipRect);
- } else {
- // Crop to the system decor specified by policy.
- calculateSystemDecorRect();
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
- + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
- }
+ w.calculatePolicyCrop(mSystemDecorRect);
+
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+ + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
final boolean fullscreen = w.isFrameFullscreen(displayInfo);
final boolean isFreeformResizing =
@@ -1178,12 +1155,7 @@
clipRect.offset(w.mShownPosition.x, w.mShownPosition.y);
}
- // Expand the clip rect for surface insets.
- final WindowManager.LayoutParams attrs = w.mAttrs;
- clipRect.left -= attrs.surfaceInsets.left;
- clipRect.top -= attrs.surfaceInsets.top;
- clipRect.right += attrs.surfaceInsets.right;
- clipRect.bottom += attrs.surfaceInsets.bottom;
+ w.expandForSurfaceInsets(clipRect);
if (mHasClipRect && fullscreen) {
// We intersect the clip rect specified by the transformation with the expanded system
@@ -1193,10 +1165,11 @@
}
// The clip rect was generated assuming (0,0) as the window origin,
// so we need to translate to match the actual surface coordinates.
- clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
+ clipRect.offset(w.mAttrs.surfaceInsets.left, w.mAttrs.surfaceInsets.top);
- finalClipRect.setEmpty();
- adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
+ if (!useFinalClipRect()) {
+ adjustCropToStackBounds(clipRect, isFreeformResizing);
+ }
if (DEBUG_WINDOW_CROP) Slog.d(TAG,
"win=" + w + " Clip rect after stack adjustment=" + clipRect);
@@ -1206,10 +1179,11 @@
if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
clipRect.setEmpty();
}
+ return true;
}
- void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+ private void applyCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "applyCrop: win=" + mWin
+ " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
if (clipRect != null) {
if (!clipRect.equals(mLastClipRect)) {
@@ -1219,6 +1193,11 @@
} else {
mSurfaceController.clearCropInTransaction(recoveringMemory);
}
+
+ if (finalClipRect == null) {
+ finalClipRect = mService.mTmpRect;
+ finalClipRect.setEmpty();
+ }
if (!finalClipRect.equals(mLastFinalClipRect)) {
mLastFinalClipRect.set(finalClipRect);
mSurfaceController.setFinalCropInTransaction(finalClipRect);
@@ -1236,9 +1215,9 @@
return mStackClip;
}
}
- private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
- boolean isFreeformResizing) {
+ private boolean shouldCropToStackBounds() {
+ final WindowState w = mWin;
final DisplayContent displayContent = w.getDisplayContent();
if (displayContent != null && !displayContent.isDefaultDisplay) {
// There are some windows that live on other displays while their app and main window
@@ -1246,22 +1225,32 @@
// to the stack bounds which is only currently supported on the default display.
// TODO(multi-display): Need to support cropping to stack bounds on other displays
// when we have stacks on other displays.
- return;
+ return false;
}
final Task task = w.getTask();
if (task == null || !task.cropWindowsToStackBounds()) {
- return;
+ return false;
}
final int stackClip = resolveStackClip();
// It's animating and we don't want to clip it to stack bounds during animation - abort.
if (isAnimationSet() && stackClip == STACK_CLIP_NONE) {
+ return false;
+ }
+ return true;
+ }
+
+ private void adjustCropToStackBounds(Rect clipRect,
+ boolean isFreeformResizing) {
+ final WindowState w = mWin;
+
+ if (!shouldCropToStackBounds()) {
return;
}
- final TaskStack stack = task.mStack;
+ final TaskStack stack = w.getTask().mStack;
stack.getDimBounds(mTmpStackBounds);
final Rect surfaceInsets = w.getAttrs().surfaceInsets;
// When we resize we use the big surface approach, which means we can't trust the
@@ -1272,34 +1261,25 @@
final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
- // If we are animating, we either apply the clip before applying all the animation
- // transformation or after all the transformation.
- final boolean useFinalClipRect = isAnimationSet() && stackClip == STACK_CLIP_AFTER_ANIM
- || mDestroyPreservedSurfaceUponRedraw;
-
// We need to do some acrobatics with surface position, because their clip region is
// relative to the inside of the surface, but the stack bounds aren't.
- if (useFinalClipRect) {
- finalClipRect.set(mTmpStackBounds);
- } else {
- if (StackId.hasWindowShadow(stack.mStackId)
- && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+ if (StackId.hasWindowShadow(stack.mStackId)
+ && !StackId.isTaskResizeAllowed(stack.mStackId)) {
// The windows in this stack display drop shadows and the fill the entire stack
// area. Adjust the stack bounds we will use to cropping take into account the
// offsets we use to display the drop shadow so it doesn't get cropped.
mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
-surfaceInsets.right, -surfaceInsets.bottom);
- }
-
- clipRect.left = Math.max(0,
- Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
- clipRect.top = Math.max(0,
- Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
- clipRect.right = Math.max(0,
- Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
- clipRect.bottom = Math.max(0,
- Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
}
+
+ clipRect.left = Math.max(0,
+ Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
+ clipRect.top = Math.max(0,
+ Math.max(mTmpStackBounds.top, frameY + clipRect.top) - frameY);
+ clipRect.right = Math.max(0,
+ Math.min(mTmpStackBounds.right, frameX + clipRect.right) - frameX);
+ clipRect.bottom = Math.max(0,
+ Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
}
void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
@@ -1339,7 +1319,13 @@
// updates until a resize occurs.
mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
- calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
+ Rect clipRect = null, finalClipRect = null;
+ if (calculateCrop(mTmpClipRect)) {
+ clipRect = mTmpClipRect;
+ }
+ if (calculateFinalCrop(mTmpFinalClipRect)) {
+ finalClipRect = mTmpFinalClipRect;
+ }
float surfaceWidth = mSurfaceController.getWidth();
float surfaceHeight = mSurfaceController.getHeight();
@@ -1404,16 +1390,8 @@
mSurfaceController.forceScaleableInTransaction(false);
}
- Rect clipRect = mTmpClipRect;
- if (w.inPinnedWorkspace()) {
- clipRect = null;
- task.mStack.getDimBounds(mTmpFinalClipRect);
- mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
- -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
- }
-
if (!w.mSeamlesslyRotated) {
- updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
+ applyCrop(clipRect, finalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
mDtDx * w.mVScale * mExtraVScale,
mDsDy * w.mHScale * mExtraHScale,
@@ -1571,8 +1549,7 @@
mService.openSurfaceTransaction();
mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
mWin.mFrame.top + top, false);
- calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
+ applyCrop(null, null, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + left + "," + top + ")", e);
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 4d43e8e..ac0e622 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -46,6 +46,7 @@
LOCAL_SHARED_LIBRARIES += \
libandroid_runtime \
libandroidfw \
+ libbase \
libappfuse \
libbinder \
libcutils \
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index c7d6b95..e46490b 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -22,15 +22,22 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/misc.h>
+#include <utils/AndroidThreads.h>
namespace android {
+static int start_sensor_service(void* /*unused*/) {
+ SensorService::instantiate();
+ return 0;
+}
+
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
- // Start the sensor service
- SensorService::instantiate();
+ // Start the sensor service in a new thread
+ createThreadEtc(start_sensor_service, nullptr,
+ "StartSensorThread", PRIORITY_FOREGROUND);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 895497c..a2af40c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -20,7 +20,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
-import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -213,6 +213,8 @@
private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending";
+ private static final String ATTR_ID = "id";
+
private static final String ATTR_VALUE = "value";
private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";
@@ -2380,7 +2382,7 @@
for (String id : policy.mAffiliationIds) {
out.startTag(null, TAG_AFFILIATION_ID);
- out.attribute(null, "id", id);
+ out.attribute(null, ATTR_ID, id);
out.endTag(null, TAG_AFFILIATION_ID);
}
@@ -2560,7 +2562,7 @@
} else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) {
policy.doNotAskCredentialsOnBoot = true;
} else if (TAG_AFFILIATION_ID.equals(tag)) {
- policy.mAffiliationIds.add(parser.getAttributeValue(null, "id"));
+ policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID));
} else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) {
policy.mLastSecurityLogRetrievalTime = Long.parseLong(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -5977,6 +5979,12 @@
}
}
+ @Override
+ public boolean hasDeviceOwner() {
+ enforceDeviceOwnerOrManageUsers();
+ return mOwners.hasDeviceOwner();
+ }
+
boolean isDeviceOwner(ActiveAdmin admin) {
return isDeviceOwner(admin.info.getComponent(), admin.getUserHandle().getIdentifier());
}
@@ -7024,7 +7032,8 @@
boolean systemService = false;
try {
ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
- enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
+ enabledPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ userIdToCheck);
systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
} catch (RemoteException e) {
Log.i(LOG_TAG, "Can't talk to package managed", e);
@@ -7779,7 +7788,7 @@
private boolean isSystemApp(IPackageManager pm, String packageName, int userId)
throws RemoteException {
- ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES,
+ ApplicationInfo appInfo = pm.getApplicationInfo(packageName, MATCH_UNINSTALLED_PACKAGES,
userId);
if (appInfo == null) {
throw new IllegalArgumentException("The application " + packageName +
@@ -8064,13 +8073,11 @@
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
Preconditions.checkNotNull(who, "ComponentName is null");
+
synchronized (this) {
- ActiveAdmin deviceOwner = getActiveAdminWithPolicyForUidLocked(
- who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER, mInjector.binderGetCallingUid());
- ActiveAdmin profileOwner = getActiveAdminWithPolicyForUidLocked(
- who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid());
- if (deviceOwner != null || (profileOwner != null && isAffiliatedUser())) {
- int userHandle = mInjector.userHandleGetCallingUserId();
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ if (isUserAffiliatedWithDevice(userHandle)) {
setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
} else {
throw new SecurityException("Admin " + who +
@@ -9120,7 +9127,7 @@
}
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
- enforceManagedProfile(userHandle, "set organization name");
+
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -9147,6 +9154,18 @@
}
@Override
+ public CharSequence getDeviceOwnerOrganizationName() {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceDeviceOwnerOrManageUsers();
+ synchronized(this) {
+ final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
+ return deviceOwnerAdmin == null ? null : deviceOwnerAdmin.organizationName;
+ }
+ }
+
+ @Override
public CharSequence getOrganizationNameForUser(int userHandle) {
if (!mHasFeature) {
return null;
@@ -9163,9 +9182,18 @@
@Override
public void setAffiliationIds(ComponentName admin, List<String> ids) {
- final Set<String> affiliationIds = new ArraySet<String>(ids);
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(admin);
+ Preconditions.checkCollectionElementsNotNull(ids, "ids");
+
+ final Set<String> affiliationIds = new ArraySet<String>(ids);
+ Preconditions.checkArgument(
+ !affiliationIds.contains(""), "ids must not contain empty strings");
+
+ final int callingUserId = mInjector.userHandleGetCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
getUserData(callingUserId).mAffiliationIds = affiliationIds;
@@ -9180,20 +9208,44 @@
}
@Override
- public boolean isAffiliatedUser() {
- final int callingUserId = mInjector.userHandleGetCallingUserId();
+ public List<String> getAffiliationIds(ComponentName admin) {
+ if (!mHasFeature) {
+ return Collections.emptyList();
+ }
+ Preconditions.checkNotNull(admin);
synchronized (this) {
- if (mOwners.getDeviceOwnerUserId() == callingUserId) {
- // The user that the DO is installed on is always affiliated.
- return true;
- }
- final ComponentName profileOwner = getProfileOwner(callingUserId);
- if (profileOwner == null
- || !profileOwner.getPackageName().equals(mOwners.getDeviceOwnerPackageName())) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ return new ArrayList<String>(
+ getUserData(mInjector.userHandleGetCallingUserId()).mAffiliationIds);
+ }
+ }
+
+ @Override
+ public boolean isAffiliatedUser() {
+ return isUserAffiliatedWithDevice(mInjector.userHandleGetCallingUserId());
+ }
+
+ private boolean isUserAffiliatedWithDevice(int userId) {
+ synchronized (this) {
+ if (!mOwners.hasDeviceOwner()) {
return false;
}
- final Set<String> userAffiliationIds = getUserData(callingUserId).mAffiliationIds;
+ if (userId == mOwners.getDeviceOwnerUserId()) {
+ // The user that the DO is installed on is always affiliated with the device.
+ return true;
+ }
+ if (userId == UserHandle.USER_SYSTEM) {
+ // The system user is always affiliated in a DO device, even if the DO is set on a
+ // different user. This could be the case if the DO is set in the primary user
+ // of a split user device.
+ return true;
+ }
+ final ComponentName profileOwner = getProfileOwner(userId);
+ if (profileOwner == null) {
+ return false;
+ }
+ final Set<String> userAffiliationIds = getUserData(userId).mAffiliationIds;
final Set<String> deviceAffiliationIds =
getUserData(UserHandle.USER_SYSTEM).mAffiliationIds;
for (String id : userAffiliationIds) {
@@ -9557,6 +9609,10 @@
Preconditions.checkNotNull(admin);
Preconditions.checkNotNull(caller);
Preconditions.checkNotNull(serviceIntent);
+ Preconditions.checkArgument(
+ serviceIntent.getComponent() != null || serviceIntent.getPackage() != null,
+ "Service intent must be explicit (with a package name or component): "
+ + serviceIntent);
Preconditions.checkNotNull(connection);
Preconditions.checkArgument(mInjector.userHandleGetCallingUserId() != targetUserId,
"target user id must be different from the calling user id");
@@ -9577,9 +9633,8 @@
createCrossUserServiceIntent(serviceIntent, targetPackage, targetUserId);
if (sanitizedIntent == null) {
// Fail, cannot lookup the target service.
- throw new SecurityException("Invalid intent or failed to look up the service");
+ return false;
}
-
// Ask ActivityManager to bind it. Notice that we are binding the service with the
// caller app instead of DevicePolicyManagerService.
return mInjector.getIActivityManager().bindService(
@@ -9621,8 +9676,7 @@
final long callingIdentity = mInjector.binderClearCallingIdentity();
try {
String callingOwnerPackage = callingOwner.info.getComponent().getPackageName();
- for (int userId : mUserManager.getProfileIds(
- callingUserId, /* enabledOnly= */ false)) {
+ for (int userId : mUserManager.getProfileIdsWithDisabled(callingUserId)) {
if (userId == callingUserId) {
continue;
}
@@ -9835,35 +9889,30 @@
}
/**
- * @param rawIntent Original service intent specified by caller.
- * @param expectedPackageName The expected package name in the incoming intent.
- * @return Intent that have component explicitly set. {@code null} if the incoming intent
- * or target service is invalid.
+ * @param rawIntent Original service intent specified by caller. It must be explicit.
+ * @param expectedPackageName The expected package name of the resolved service.
+ * @return Intent that have component explicitly set. {@code null} if no service is resolved
+ * with the given intent.
+ * @throws SecurityException if the intent is resolved to an invalid service.
*/
private Intent createCrossUserServiceIntent(
@NonNull Intent rawIntent, @NonNull String expectedPackageName,
- @UserIdInt int targetUserId) throws RemoteException {
- if (rawIntent.getComponent() == null && rawIntent.getPackage() == null) {
- Log.e(LOG_TAG, "Service intent must be explicit (with a package name or component): "
- + rawIntent);
- return null;
- }
+ @UserIdInt int targetUserId) throws RemoteException, SecurityException {
ResolveInfo info = mIPackageManager.resolveService(
rawIntent,
rawIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
0, // flags
targetUserId);
if (info == null || info.serviceInfo == null) {
- Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent);
+ Log.e(LOG_TAG, "Fail to look up the service: " + rawIntent
+ + " or user " + targetUserId + " is not running");
return null;
}
if (!expectedPackageName.equals(info.serviceInfo.packageName)) {
- Log.e(LOG_TAG, "Only allow to bind service in " + expectedPackageName);
- return null;
+ throw new SecurityException("Only allow to bind service in " + expectedPackageName);
}
if (info.serviceInfo.exported) {
- Log.e(LOG_TAG, "The service must be unexported.");
- return null;
+ throw new SecurityException("The service must be unexported");
}
// It is the system server to bind the service, it would be extremely dangerous if it
// can be exploited to bind any service. Set the component explicitly to make sure we
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 39c5238..ad436724a 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -211,8 +211,9 @@
defaults |= Notification.DEFAULT_VIBRATE;
} else {
builder.setVibrate(CUSTOM_VIBRATION);
+ channel.setVibrationPattern(CUSTOM_VIBRATION);
}
- channel.setVibration(true);
+ channel.enableVibration(true);
}
if (lights) {
if (defaultLights) {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
new file mode 100644
index 0000000..e4a355f
--- /dev/null
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.server.notification;
+
+import static junit.framework.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.app.IOnNotificationChannelCreatedListener;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import java.util.concurrent.CountDownLatch;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationManagerServiceTest {
+ private NotificationManagerService mNotificationManagerService;
+ private INotificationManager mBinderService;
+
+ @Before
+ public void setUp() throws Exception {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ mNotificationManagerService = new NotificationManagerService(context);
+
+ // MockPackageManager - default returns ApplicationInfo with matching calling UID
+ final IPackageManager mockPackageManager = mock(IPackageManager.class);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = Binder.getCallingUid();
+ when(mockPackageManager.getApplicationInfo(any(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
+ mNotificationManagerService.setPackageManager(mockPackageManager);
+
+ mNotificationManagerService.setRankingHelper(mock(RankingHelper.class));
+ mNotificationManagerService.setHandler(new Handler(context.getMainLooper()));
+
+ // Tests call directly into the Binder.
+ mBinderService = mNotificationManagerService.getBinderService();
+ }
+
+ @Test
+ public void testCreateNotificationChannel_SuccessCallsListener() throws Exception {
+ final NotificationChannel channel =
+ new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
+ final CountDownLatch latch = new CountDownLatch(1);
+ mBinderService.createNotificationChannel("test_pkg", channel,
+ new IOnNotificationChannelCreatedListener.Stub() {
+ @Override public void onNotificationChannelCreated(
+ NotificationChannel channel) {
+ latch.countDown();
+ }});
+ latch.await();
+ }
+
+ @Test
+ public void testCreateNotificationChannel_FailureDoesNotCallListener() throws Exception {
+ try {
+ mBinderService.createNotificationChannel("test_pkg", null,
+ new IOnNotificationChannelCreatedListener.Stub() {
+ @Override public void onNotificationChannelCreated(
+ NotificationChannel channel) {
+ fail("Listener was triggered from failure.");
+ }});
+ fail("Exception should be thrown immediately.");
+ } catch (NullPointerException e) {
+ // pass
+ }
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index b8f3832..a7d2c04 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -81,6 +81,7 @@
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+ private static final long[] CUSTOM_CHANNEL_VIBRATION = new long[] {300, 400, 300, 400 };
private static final Uri CUSTOM_SOUND = Settings.System.DEFAULT_ALARM_ALERT_URI;
private static final AudioAttributes CUSTOM_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -124,6 +125,7 @@
defaults |= Notification.DEFAULT_VIBRATE;
} else {
builder.setVibrate(CUSTOM_VIBRATION);
+ channel.setVibrationPattern(CUSTOM_CHANNEL_VIBRATION);
}
}
builder.setDefaults(defaults);
@@ -193,7 +195,7 @@
@Test
public void testVibration_default_preUpgradeUsesNotification() throws Exception {
- defaultChannel.setVibration(false);
+ defaultChannel.enableVibration(false);
// pre upgrade, default vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */);
@@ -204,7 +206,7 @@
@Test
public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
- defaultChannel.setVibration(false);
+ defaultChannel.enableVibration(false);
// pre upgrade, custom vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
@@ -215,7 +217,7 @@
@Test
public void testVibration_custom_userLocked_preUpgrade() throws Exception {
- defaultChannel.setVibration(true);
+ defaultChannel.enableVibration(true);
defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
// pre upgrade, custom vibration.
StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
@@ -227,13 +229,13 @@
@Test
public void testVibration_custom_upgradeUsesChannel() throws Exception {
- channel.setVibration(true);
+ channel.enableVibration(true);
// post upgrade, custom vibration.
StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */);
NotificationRecord record = new NotificationRecord(mMockContext, sbn);
- assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
+ assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
}
@Test
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 3df0d66..16d0a75 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -15,6 +15,8 @@
*/
package com.android.server.notification;
+import static junit.framework.Assert.fail;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,6 +48,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -168,6 +171,18 @@
return baos;
}
+ private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
+ assertEquals(expected.getId(), actual.getId());
+ assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
+ assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
+ assertEquals(expected.getImportance(), actual.getImportance());
+ assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
+ assertEquals(expected.getSound(), actual.getSound());
+ assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
+ assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
+ }
+
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -228,6 +243,8 @@
channel2.setLights(true);
channel2.setBypassDnd(true);
channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
+ channel2.enableVibration(true);
+ channel2.setVibrationPattern(new long[] {100, 67, 145, 156});
mHelper.createNotificationChannel(pkg, uid, channel1);
mHelper.createNotificationChannel(pkg, uid, channel2);
@@ -246,7 +263,7 @@
mHelper.readXml(parser, false);
assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId()));
- assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
+ compareChannels(channel2, mHelper.getNotificationChannel(pkg, uid, channel2.getId()));
assertNotNull(
mHelper.getNotificationChannel(pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID));
}
@@ -333,6 +350,19 @@
}
@Test
+ public void testCreateChannel_blocked() throws Exception {
+ mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_NONE);
+
+ try {
+ mHelper.createNotificationChannel(pkg, uid,
+ new NotificationChannel(pkg, "", NotificationManager.IMPORTANCE_LOW));
+ fail("Channel creation should fail");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ }
+
+ @Test
public void testUpdate_userLockedImportance() throws Exception {
// all fields locked by user
final NotificationChannel channel =
@@ -385,7 +415,8 @@
// same id, try to update
final NotificationChannel channel2 =
new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
- channel2.setVibration(true);
+ channel2.enableVibration(true);
+ channel2.setVibrationPattern(new long[] {100});
mHelper.updateNotificationChannelFromRanker(pkg, uid, channel2);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index cff5b41..3ad40758 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,15 +22,20 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.IIpConnectivityMetrics;
+import android.content.pm.UserInfo;
import android.net.wifi.WifiInfo;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -50,6 +55,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1643,6 +1649,7 @@
/**
* Test for:
* {@link DevicePolicyManager#setAffiliationIds}
+ * {@link DevicePolicyManager#getAffiliationIds}
* {@link DevicePolicyManager#isAffiliatedUser}
*/
public void testUserAffiliation() throws Exception {
@@ -1659,30 +1666,34 @@
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
assertTrue(dpm.isAffiliatedUser());
+ assertTrue(dpm.getAffiliationIds(admin1).isEmpty());
- // Install a profile owner whose package name matches the device owner on a test user. Check
- // that the test user is unaffiliated.
+ // Install a profile owner. Check that the test user is unaffiliated.
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setAsProfileOwner(admin2);
assertFalse(dpm.isAffiliatedUser());
+ assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
// Have the profile owner specify a set of affiliation ids. Check that the test user remains
// unaffiliated.
- final Set<String> userAffiliationIds = new ArraySet<>();
+ final List<String> userAffiliationIds = new ArrayList<>();
userAffiliationIds.add("red");
userAffiliationIds.add("green");
userAffiliationIds.add("blue");
dpm.setAffiliationIds(admin2, userAffiliationIds);
+ MoreAsserts.assertContentsInAnyOrder(dpm.getAffiliationIds(admin2), "red", "green", "blue");
assertFalse(dpm.isAffiliatedUser());
// Have the device owner specify a set of affiliation ids that do not intersect with those
// specified by the profile owner. Check that the test user remains unaffiliated.
- final Set<String> deviceAffiliationIds = new ArraySet<>();
+ final List<String> deviceAffiliationIds = new ArrayList<>();
deviceAffiliationIds.add("cyan");
deviceAffiliationIds.add("yellow");
deviceAffiliationIds.add("magenta");
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
dpm.setAffiliationIds(admin1, deviceAffiliationIds);
+ MoreAsserts.assertContentsInAnyOrder(
+ dpm.getAffiliationIds(admin1), "cyan", "yellow", "magenta");
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
assertFalse(dpm.isAffiliatedUser());
@@ -1690,19 +1701,13 @@
// specified by the device owner. Check that the test user becomes affiliated.
userAffiliationIds.add("yellow");
dpm.setAffiliationIds(admin2, userAffiliationIds);
+ MoreAsserts.assertContentsInAnyOrder(
+ dpm.getAffiliationIds(admin2), "red", "green", "blue", "yellow");
assertTrue(dpm.isAffiliatedUser());
- // Change the profile owner to one whose package name does not match the device owner. Check
- // that the test user is not affiliated anymore.
- dpm.clearProfileOwner(admin2);
- final ComponentName admin = new ComponentName("test", "test");
-
- setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
- /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- /* appTargetSdk = */ null, admin2);
-
- dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
- assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+ // Clear affiliation ids for the profile owner. The user becomes unaffiliated.
+ dpm.setAffiliationIds(admin2, Collections.emptyList());
+ assertTrue(dpm.getAffiliationIds(admin2).isEmpty());
assertFalse(dpm.isAffiliatedUser());
// Check that the system user remains affiliated.
@@ -2447,6 +2452,110 @@
assertEquals(-1, dpm.getLastNetworkLogRetrievalTime());
}
+ public void testGetBindDeviceAdminTargetUsers() throws Exception {
+ // Setup device owner.
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+
+ // Only device owner is setup, the result list should be empty.
+ List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+ MoreAsserts.assertEmpty(targetUsers);
+
+ // Setup a managed profile managed by the same admin.
+ final int MANAGED_PROFILE_USER_ID = 15;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
+ addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);
+
+ // Add a secondary user, it should never talk with.
+ final int ANOTHER_USER_ID = 36;
+ mContext.addUser(ANOTHER_USER_ID, 0);
+
+ // Calling from device owner admin, the result list should just contain the managed
+ // profile user id.
+ targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+ MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.of(MANAGED_PROFILE_USER_ID));
+
+ // Calling from managed profile admin, the result list should just contain the system
+ // user id.
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+ MoreAsserts.assertContentsInAnyOrder(targetUsers, UserHandle.SYSTEM);
+ }
+
+ public void testGetBindDeviceAdminTargetUsers_differentPackage() throws Exception {
+ // Setup a device owner.
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+
+ // Set up a managed profile managed by different package.
+ final int MANAGED_PROFILE_USER_ID = 15;
+ final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 20456);
+ final ComponentName adminDifferentPackage =
+ new ComponentName("another.package", "whatever.class");
+ addManagedProfile(adminDifferentPackage, MANAGED_PROFILE_ADMIN_UID, admin2);
+
+ // Calling from device owner admin, we should get zero bind device admin target users as
+ // their packages are different.
+ List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(admin1);
+ MoreAsserts.assertEmpty(targetUsers);
+
+ // Calling from managed profile admin, we should still get zero target users for the same
+ // reason.
+ mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
+ targetUsers = dpm.getBindDeviceAdminTargetUsers(adminDifferentPackage);
+ MoreAsserts.assertEmpty(targetUsers);
+ }
+
+ public void testIsDeviceManaged() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+
+ // The device owner itself, any uid holding MANAGE_USERS permission and the system can
+ // find out that the device has a device owner.
+ assertTrue(dpm.isDeviceManaged());
+ mContext.binder.callingUid = 1234567;
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
+ assertTrue(dpm.isDeviceManaged());
+ mContext.callerPermissions.remove(permission.MANAGE_USERS);
+ mContext.binder.clearCallingIdentity();
+ assertTrue(dpm.isDeviceManaged());
+
+ clearDeviceOwner();
+
+ // Any uid holding MANAGE_USERS permission and the system can find out that the device does
+ // not have a device owner.
+ mContext.binder.callingUid = 1234567;
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
+ assertFalse(dpm.isDeviceManaged());
+ mContext.callerPermissions.remove(permission.MANAGE_USERS);
+ mContext.binder.clearCallingIdentity();
+ assertFalse(dpm.isDeviceManaged());
+ }
+
+ public void testDeviceOwnerOrganizationName() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+
+ dpm.setOrganizationName(admin1, "organization");
+
+ // Device owner can retrieve organization managing the device.
+ assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+
+ // Any uid holding MANAGE_USERS permission can retrieve organization managing the device.
+ mContext.binder.callingUid = 1234567;
+ mContext.callerPermissions.add(permission.MANAGE_USERS);
+ assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+ mContext.callerPermissions.remove(permission.MANAGE_USERS);
+
+ // System can retrieve organization managing the device.
+ mContext.binder.clearCallingIdentity();
+ assertEquals("organization", dpm.getDeviceOwnerOrganizationName());
+
+ // Removing the device owner clears the organization managing the device.
+ clearDeviceOwner();
+ assertNull(dpm.getDeviceOwnerOrganizationName());
+ }
+
private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
@@ -2458,4 +2567,22 @@
assertEquals("isProvisioningAllowed(" + action + ") returning unexpected result", expected,
dpm.isProvisioningAllowed(action));
}
+
+ /**
+ * Setup a managed profile with the specified admin and its uid.
+ * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
+ * @param adminUid uid of the admin package.
+ * @param copyFromAdmin package information for {@code admin} will be built based on this
+ * component's information.
+ */
+ private void addManagedProfile(
+ ComponentName admin, int adminUid, ComponentName copyFromAdmin) throws Exception {
+ final int userId = UserHandle.getUserId(adminUid);
+ mContext.addUser(userId, UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_SYSTEM);
+ mContext.callerPermissions.addAll(OWNER_SETUP_PERMISSIONS);
+ setUpPackageManagerForFakeAdmin(admin, adminUid, copyFromAdmin);
+ dpm.setActiveAdmin(admin, false, userId);
+ assertTrue(dpm.setProfileOwner(admin, null, userId));
+ mContext.callerPermissions.removeAll(OWNER_SETUP_PERMISSIONS);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index d74c6dc..1247b2d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -16,8 +16,6 @@
package com.android.server.devicepolicy;
-import com.android.internal.widget.LockPatternUtils;
-
import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
@@ -47,6 +45,8 @@
import android.test.mock.MockContext;
import android.view.IWindowManager;
+import com.android.internal.widget.LockPatternUtils;
+
import org.junit.Assert;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -324,16 +324,21 @@
contentResolver = new MockContentResolver();
// Add the system user
- systemUserDataDir = addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY);
+ systemUserDataDir =
+ addUser(UserHandle.USER_SYSTEM, UserInfo.FLAG_PRIMARY, UserHandle.USER_SYSTEM);
// System user is always running.
setUserRunning(UserHandle.USER_SYSTEM, true);
}
public File addUser(int userId, int flags) {
+ return addUser(userId, flags, UserInfo.NO_PROFILE_GROUP_ID);
+ }
+ public File addUser(int userId, int flags, int profileGroupId) {
// Set up (default) UserInfo for CALLER_USER_HANDLE.
final UserInfo uh = new UserInfo(userId, "user" + userId, flags);
+ uh.profileGroupId = profileGroupId;
when(userManager.getUserInfo(eq(userId))).thenReturn(uh);
mUserInfos.add(uh);
@@ -345,12 +350,7 @@
@Override
public UserInfo answer(InvocationOnMock invocation) throws Throwable {
final int userId = (int) invocation.getArguments()[0];
- for (UserInfo ui : mUserInfos) {
- if (ui.id == userId) {
- return ui;
- }
- }
- return null;
+ return getUserInfo(userId);
}
}
);
@@ -369,16 +369,13 @@
public int[] answer(InvocationOnMock invocation) throws Throwable {
final int userId = (int) invocation.getArguments()[0];
List<UserInfo> profiles = getProfiles(userId);
- int[] results = new int[profiles.size()];
- for (int i = 0; i < results.length; i++) {
- results[i] = profiles.get(i).id;
- }
- return results;
+ return profiles.stream()
+ .mapToInt(profile -> profile.id)
+ .toArray();
}
}
);
-
// Create a data directory.
final File dir = new File(dataDir, "user" + userId);
DpmTestUtils.clearDir(dir);
@@ -387,6 +384,15 @@
return dir;
}
+ private UserInfo getUserInfo(int userId) {
+ for (UserInfo ui : mUserInfos) {
+ if (ui.id == userId) {
+ return ui;
+ }
+ }
+ return null;
+ }
+
private List<UserInfo> getProfiles(int userId) {
final ArrayList<UserInfo> ret = new ArrayList<UserInfo>();
UserInfo parent = null;
@@ -401,9 +407,6 @@
}
ret.add(parent);
for (UserInfo ui : mUserInfos) {
- if (ui.id == userId) {
- continue;
- }
if (ui.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
&& ui.profileGroupId == parent.profileGroupId) {
ret.add(ui);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index b4b74b3..db27f72 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -101,6 +101,13 @@
admin);
}
+ protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+ ComponentName copyFromAdmin)
+ throws Exception {
+ setUpPackageManagerForFakeAdmin(admin, packageUid,
+ /* enabledSetting =*/ null, /* appTargetSdk = */ null, copyFromAdmin);
+ }
+
/**
* Set up a component in the mock package manager to be an active admin.
*
@@ -118,7 +125,6 @@
mRealTestContext.getPackageManager().getApplicationInfo(
copyFromAdmin.getPackageName(),
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
-
ai.enabledSetting = enabledSetting == null
? PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
: enabledSetting;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
index 379d4fe..f773c15 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerPresubmitTest.java
@@ -90,9 +90,9 @@
boolean granted = (packageInfo.requestedPermissionsFlags[i]
& PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
assertTrue("Permission " + pName + " should be granted to " + testPackage, granted);
- // if CONTROL_PRIVAPP_PERMISSIONS enabled, platform permissions must be whitelisted
+ // if privapp permissions are enforced, platform permissions must be whitelisted
// in SystemConfig
- if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS) {
+ if (platformPermission && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
assertTrue("Permission " + pName
+ " should be declared in the xml file for package "
+ testPackage,
diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
new file mode 100644
index 0000000..d165b8b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.PackageParser;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests for {@link ParallelPackageParser}
+ */
+@RunWith(AndroidJUnit4.class)
+public class ParallelPackageParserTest {
+ private static final String TAG = ParallelPackageParserTest.class.getSimpleName();
+
+ private ParallelPackageParser mParser;
+
+ @Before
+ public void setUp() {
+ mParser = new TestParallelPackageParser();
+ }
+
+ @Test(timeout = 1000)
+ public void test() {
+ Set<File> submittedFiles = new HashSet<>();
+ int fileCount = 15;
+ for (int i = 0; i < fileCount; i++) {
+ File file = new File("f" + i);
+ mParser.submit(file, 0);
+ submittedFiles.add(file);
+ Log.d(TAG, "submitting " + file);
+ }
+ for (int i = 0; i < fileCount; i++) {
+ ParallelPackageParser.ParseResult result = mParser.take();
+ Assert.assertNotNull(result);
+ File parsedFile = result.scanFile;
+ Log.d(TAG, "took " + parsedFile);
+ Assert.assertNotNull(parsedFile);
+ boolean removeSuccessful = submittedFiles.remove(parsedFile);
+ Assert.assertTrue("Unexpected file " + parsedFile + ". Expected submitted files: "
+ + submittedFiles, removeSuccessful);
+ }
+ }
+
+ class TestParallelPackageParser extends ParallelPackageParser {
+
+ TestParallelPackageParser() {
+ super(null, false, null);
+ }
+
+ @Override
+ protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile,
+ int parseFlags) throws PackageParser.PackageParserException {
+ // Do not actually parse the package for testing
+ return null;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 23d1018..97bcaf0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4957,6 +4957,9 @@
assertEquals(0, mManager.getDynamicShortcuts().size());
assertEquals(0, mManager.getPinnedShortcuts().size());
});
+ assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
+ .getPackageInfo().isShadow());
+
installPackage(USER_0, CALLING_PACKAGE_2);
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -4965,6 +4968,8 @@
mManager.getPinnedShortcuts()),
"s1", "s2", "s3");
});
+ assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, USER_0)
+ .getPackageInfo().isShadow());
installPackage(USER_0, LAUNCHER_1);
runWithCaller(LAUNCHER_1, USER_0, () -> {
@@ -5088,6 +5093,8 @@
mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
/* empty */);
});
+ assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_1, USER_0)
+ .getPackageInfo().isShadow());
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5110,6 +5117,8 @@
mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
/* empty */);
});
+ assertFalse(mService.getLauncherShortcutForTest(LAUNCHER_2, USER_0)
+ .getPackageInfo().isShadow());
installPackage(USER_0, CALLING_PACKAGE_3);
runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
new file mode 100644
index 0000000..ad514cf
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.server.pm;
+
+import android.app.ApplicationPackageManager;
+import android.content.pm.UserInfo;
+import android.os.Looper;
+import android.os.UserManagerInternal;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.MediumTest;
+
+import com.android.server.LocalServices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * <p>Run with:<pre>
+ * runtest -c com.android.server.pm.UserManagerServiceCreateProfileTest frameworks-services
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UserManagerServiceCreateProfileTest {
+ private UserManagerService mUserManagerService;
+
+ @Before
+ public void setup() {
+ // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+ // TODO: Remove once UMS supports proper dependency injection
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+
+ // The tests assume that the device has one user and its the system user.
+ List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+ assertEquals("Multiple users so this test can't run.", 1, users.size());
+ assertEquals("Only user present isn't the system user.",
+ UserHandle.USER_SYSTEM, users.get(0).id);
+ }
+
+ @Test
+ public void testGetProfiles() {
+ try {
+ // Pretend we have a secondary user with a profile.
+ UserInfo secondaryUser = addUser();
+ UserInfo profile = addProfile(secondaryUser);
+
+ // System user should still have no profile so getProfiles should just return 1 user.
+ List<UserInfo> users =
+ mUserManagerService.getProfiles(UserHandle.USER_SYSTEM, /*excludeDying*/ false);
+ assertEquals("Profiles returned where none should exist", 1, users.size());
+ assertEquals("Missing system user from profile list of system user",
+ UserHandle.USER_SYSTEM, users.get(0).id);
+
+ // Secondary user should have 1 profile, so return that and itself.
+ users = mUserManagerService.getProfiles(secondaryUser.id, /*excludeDying*/ false);
+ assertEquals("Profiles returned where none should exist", 2, users.size());
+ assertTrue("Missing secondary user id", users.get(0).id == secondaryUser.id
+ || users.get(1).id == secondaryUser.id);
+ assertTrue("Missing profile user id", users.get(0).id == profile.id
+ || users.get(1).id == profile.id);
+ } finally {
+ removeUsers();
+ }
+ }
+
+ @Test
+ public void testProfileBadge() {
+ try {
+ // First profile for system user should get badge 0
+ assertEquals("First profile isn't given badge index 0", 0,
+ mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+
+ // Pretend we have a secondary user.
+ UserInfo secondaryUser = addUser();
+
+ // Check first profile badge for secondary user is also 0.
+ assertEquals("First profile for secondary user isn't given badge index 0", 0,
+ mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+
+ // Shouldn't impact the badge for profile in system user
+ assertEquals("First profile isn't given badge index 0 with secondary user", 0,
+ mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+
+ // Pretend a secondary user has a profile.
+ addProfile(secondaryUser);
+
+ // Shouldn't have impacted the badge for the system user
+ assertEquals("First profile isn't given badge index 0 in secondary user", 0,
+ mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+ } finally {
+ removeUsers();
+ }
+ }
+
+ @Test
+ public void testProfileBadgeUnique() {
+ try {
+ List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+ UserInfo system = users.get(0);
+ // Badges should get allocated 0 -> max
+ for (int i = 0; i < UserManagerService.getMaxManagedProfiles(); ++i) {
+ int nextBadge = mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM);
+ assertEquals("Wrong badge allocated", i, nextBadge);
+ UserInfo profile = addProfile(system);
+ profile.profileBadge = nextBadge;
+ }
+ } finally {
+ removeUsers();
+ }
+ }
+
+ @Test
+ public void testProfileBadgeReuse() {
+ try {
+ // Pretend we have a secondary user with a profile.
+ UserInfo secondaryUser = addUser();
+ UserInfo profile = addProfile(secondaryUser);
+ // Add the profile it to the users being removed.
+ mUserManagerService.addRemovingUserIdLocked(profile.id);
+ // We should reuse the badge from the profile being removed.
+ assertEquals("Badge index not reused while removing a user", 0,
+ mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+
+ // Edge case of reuse that only applies if we ever support 3 managed profiles
+ // We should prioritise using lower badge indexes
+ if (UserManagerService.getMaxManagedProfiles() > 2) {
+ UserInfo profileBadgeOne = addProfile(secondaryUser);
+ profileBadgeOne.profileBadge = 1;
+ // 0 and 2 are free, we should reuse 0 rather than 2.
+ assertEquals("Lower index not used", 0,
+ mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+ }
+ } finally {
+ removeUsers();
+ }
+ }
+
+ @Test
+ public void testNumberOfBadges() {
+ assertTrue("Max profiles greater than number of badges",
+ UserManagerService.MAX_MANAGED_PROFILES
+ <= ApplicationPackageManager.CORP_BADGE_COLORS.length);
+ assertEquals("Num colors doesn't match number of badge labels",
+ ApplicationPackageManager.CORP_BADGE_COLORS.length,
+ ApplicationPackageManager.CORP_BADGE_LABEL_RES_ID.length);
+ }
+
+ private void removeUsers() {
+ List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+ for (UserInfo user: users) {
+ if (user.id != UserHandle.USER_SYSTEM) {
+ mUserManagerService.removeUserInfo(user.id);
+ }
+ }
+ }
+
+ private UserInfo addProfile(UserInfo user) {
+ user.profileGroupId = user.id;
+ UserInfo profile = new UserInfo(
+ mUserManagerService.getNextAvailableId(), "profile",
+ UserInfo.FLAG_MANAGED_PROFILE);
+ profile.profileGroupId = user.id;
+ mUserManagerService.putUserInfo(profile);
+ return profile;
+ }
+
+ private UserInfo addUser() {
+ UserInfo secondaryUser = new UserInfo(
+ mUserManagerService.getNextAvailableId(), "secondary", /* flags */ 0);
+ mUserManagerService.putUserInfo(secondaryUser);
+ return secondaryUser;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
new file mode 100644
index 0000000..575d7a3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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.server.pm;
+
+import android.content.pm.UserInfo;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.UserManagerInternal;
+import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.MediumTest;
+
+import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * <p>Run with:<pre>
+ * runtest -c com.android.server.pm.UserManagerServiceUserInfoTest frameworks-services
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class UserManagerServiceUserInfoTest {
+ private UserManagerService mUserManagerService;
+
+ @Before
+ public void setup() {
+ // Currently UserManagerService cannot be instantiated twice inside a VM without a cleanup
+ // TODO: Remove once UMS supports proper dependency injection
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ mUserManagerService = new UserManagerService(InstrumentationRegistry.getContext());
+
+ // The tests assume that the device has one user and its the system user.
+ List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+ assertEquals("Multiple users so this test can't run.", 1, users.size());
+ assertEquals("Only user present isn't the system user.",
+ UserHandle.USER_SYSTEM, users.get(0).id);
+ }
+
+ @Test
+ public void testWriteReadUserInfo() throws Exception {
+ UserData data = new UserData();
+ data.info = createUser();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(baos);
+ mUserManagerService.writeUserLP(data, out);
+ byte[] bytes = baos.toByteArray();
+
+ UserData read = mUserManagerService.readUserLP(
+ data.info.id, new ByteArrayInputStream(bytes));
+
+ assertUserInfoEquals(data.info, read.info);
+ }
+
+ @Test
+ public void testParcelUnparcelUserInfo() throws Exception {
+ UserInfo info = createUser();
+
+ Parcel out = Parcel.obtain();
+ info.writeToParcel(out, 0);
+ byte[] data = out.marshall();
+ out.recycle();
+
+ Parcel in = Parcel.obtain();
+ in.unmarshall(data, 0, data.length);
+ in.setDataPosition(0);
+ UserInfo read = UserInfo.CREATOR.createFromParcel(in);
+ in.recycle();
+
+ assertUserInfoEquals(info, read);
+ }
+
+ private UserInfo createUser() {
+ UserInfo user = new UserInfo(/*id*/ 21, "A Name", "A path", /*flags*/ 0x0ff0ff);
+ user.serialNumber = 5;
+ user.creationTime = 4L << 32;
+ user.lastLoggedInTime = 5L << 32;
+ user.lastLoggedInFingerprint = "afingerprint";
+ user.profileGroupId = 45;
+ user.restrictedProfileParentId = 4;
+ user.profileBadge = 2;
+ user.partial = true;
+ user.guestToRemove = true;
+ return user;
+ }
+
+ private void assertUserInfoEquals(UserInfo one, UserInfo two) {
+ assertEquals("Id not preserved", one.id, two.id);
+ assertEquals("Name not preserved", one.name, two.name);
+ assertEquals("Icon path not preserved", one.iconPath, two.iconPath);
+ assertEquals("Flags not preserved", one.flags, two.flags);
+ assertEquals("profile group not preserved", one.profileGroupId,
+ two.profileGroupId);
+ assertEquals("restricted profile parent not preseved", one.restrictedProfileParentId,
+ two.restrictedProfileParentId);
+ assertEquals("profile badge not preseved", one.profileBadge, two.profileBadge);
+ assertEquals("partial not preseved", one.partial, two.partial);
+ assertEquals("guestToRemove not preseved", one.guestToRemove, two.guestToRemove);
+ }
+}
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 ed4c79f..1853a65 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,9 +16,11 @@
package com.android.server.wm;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.server.input.InputManagerService;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -528,8 +530,7 @@
}
@Override
- public void dismissKeyguardLw() {
-
+ public void dismissKeyguardLw(@Nullable IKeyguardDismissCallback callback) {
}
@Override
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 fd1c91a..b10c273 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -27,6 +27,7 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.IWindow;
import android.view.WindowManager;
@@ -53,6 +54,7 @@
class WindowStateWithTask extends WindowState {
final Task mTask;
+ boolean mDockedResizingForTest = false;
WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0);
mTask = t;
@@ -62,6 +64,11 @@
Task getTask() {
return mTask;
}
+
+ @Override
+ boolean isDockedResizing() {
+ return mDockedResizingForTest;
+ }
};
class TaskWithBounds extends Task {
@@ -92,6 +99,10 @@
public void setUp() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
+
+ // Just any non zero value.
+ sWm.mSystemDecorLayer = 10000;
+
mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
sWm.getDefaultDisplayContentLocked());
mStubStack = new TaskStack(sWm, 0);
@@ -274,7 +285,63 @@
assertRect(w.mContentInsets, 0, 0, 100, 100);
}
- private WindowState createWindow(Task task, int width, int height) {
+ @Test
+ public void testCalculatePolicyCrop() {
+ final WindowStateWithTask w = createWindow(
+ new TaskWithBounds(null), FILL_PARENT, FILL_PARENT);
+ w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+
+ final Rect pf = new Rect(0, 0, 1000, 1000);
+ final Rect df = pf;
+ final Rect of = df;
+ final Rect cf = new Rect(pf);
+ // Produce some insets
+ cf.top += 50;
+ cf.bottom -= 100;
+ final Rect vf = cf;
+ final Rect sf = vf;
+ // We use a decor content frame with insets to produce cropping.
+ Rect dcf = cf;
+
+ final Rect policyCrop = new Rect();
+
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.calculatePolicyCrop(policyCrop);
+ // If we were above system decor we wouldnt' get any cropping though
+ w.mLayer = sWm.mSystemDecorLayer + 1;
+ w.calculatePolicyCrop(policyCrop);
+ assertRect(policyCrop, 0, 0, 1000, 1000);
+ w.mLayer = 1;
+ dcf.setEmpty();
+ // Likewise with no decor frame we would get no crop
+ w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
+ w.calculatePolicyCrop(policyCrop);
+ assertRect(policyCrop, 0, 0, 1000, 1000);
+
+ // Now we set up a window which doesn't fill the entire decor frame.
+ // Normally it would be cropped to it's frame but in the case of docked resizing
+ // we need to account for the fact the windows surface will be made
+ // fullscreen and thus also make the crop fullscreen.
+ w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
+ w.mAttrs.width = 500;
+ w.mAttrs.height = 500;
+ w.mRequestedWidth = 500;
+ w.mRequestedHeight = 500;
+ w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
+
+ w.calculatePolicyCrop(policyCrop);
+ // Normally the crop is shrunk from the decor frame
+ // to the computed window frame.
+ assertRect(policyCrop, 0, 0, 500, 500);
+
+ w.mDockedResizingForTest = true;
+ w.calculatePolicyCrop(policyCrop);
+ // But if we are docked resizing it won't be.
+ final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+ assertRect(policyCrop, 0, 0, 1000, 1000);
+ }
+
+ private WindowStateWithTask createWindow(Task task, int width, int height) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
attrs.width = width;
attrs.height = height;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7217c3b..515370f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -791,7 +791,7 @@
int getAppId(String packageName) {
try {
ApplicationInfo ai = mPackageManager.getApplicationInfo(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES
+ PackageManager.MATCH_ANY_USER
| PackageManager.MATCH_DISABLED_COMPONENTS);
return ai.uid;
} catch (NameNotFoundException re) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 0544fae..b86a85b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -119,6 +119,7 @@
private static final int MSG_USER_SWITCHED = 5;
private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
private static final int MSG_UPDATE_HOST_STATE = 7;
+ private static final int MSG_ACCESSORY_MODE_ENTER_TIMEOUT = 8;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -127,9 +128,6 @@
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
- // Time we received a request to enter USB accessory mode
- private long mAccessoryModeRequestTime = 0;
-
// Timeout for entering USB request mode.
// Request is cancelled if host does not configure device within 10 seconds.
private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
@@ -297,7 +295,8 @@
}
if (functions != null) {
- mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_MODE_ENTER_TIMEOUT),
+ ACCESSORY_REQUEST_TIMEOUT);
setCurrentFunctions(functions, false);
}
}
@@ -586,14 +585,10 @@
private void updateCurrentAccessory() {
// We are entering accessory mode if we have received a request from the host
// and the request has not timed out yet.
- boolean enteringAccessoryMode =
- mAccessoryModeRequestTime > 0 &&
- SystemClock.elapsedRealtime() <
- mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
+ boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
if (mConfigured && enteringAccessoryMode) {
// successfully entered accessory mode
-
if (mAccessoryStrings != null) {
mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
@@ -604,19 +599,23 @@
} else {
Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
- } else if (!enteringAccessoryMode) {
- // make sure accessory mode is off
- // and restore default functions
- Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(null, false, false);
+ } else if (!mConnected && !enteringAccessoryMode) {
+ notifyAccessoryModeExit();
+ }
+ }
- if (mCurrentAccessory != null) {
- if (mBootCompleted) {
- mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
- }
- mCurrentAccessory = null;
- mAccessoryStrings = null;
+ private void notifyAccessoryModeExit() {
+ // make sure accessory mode is off
+ // and restore default functions
+ Slog.d(TAG, "exited USB accessory mode");
+ setEnabledFunctions(null, false, false);
+
+ if (mCurrentAccessory != null) {
+ if (mBootCompleted) {
+ mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
}
+ mCurrentAccessory = null;
+ mAccessoryStrings = null;
}
}
@@ -805,6 +804,12 @@
}
break;
}
+ case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+ if (!mConnected) {
+ notifyAccessoryModeExit();
+ }
+ break;
+ }
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c99e22a..c69b7c2 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -324,6 +324,7 @@
private final PhoneAccountHandle mAccountHandle;
private final int mCallCapabilities;
private final int mCallProperties;
+ private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
private final DisconnectCause mDisconnectCause;
private final long mConnectTimeMillis;
private final GatewayInfo mGatewayInfo;
@@ -536,6 +537,15 @@
}
/**
+ * @return a bitmask of the audio routes available for the call.
+ *
+ * @hide
+ */
+ public int getSupportedAudioRoutes() {
+ return mSupportedAudioRoutes;
+ }
+
+ /**
* @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
* by {@link android.telecom.DisconnectCause}.
*/
diff --git a/telecomm/java/android/telecom/CallAudioState.java b/telecomm/java/android/telecom/CallAudioState.java
index 2b16722..f601d8b 100644
--- a/telecomm/java/android/telecom/CallAudioState.java
+++ b/telecomm/java/android/telecom/CallAudioState.java
@@ -44,8 +44,12 @@
*/
public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
- /** Bit mask of all possible audio routes. */
- private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+ /**
+ * Bit mask of all possible audio routes.
+ *
+ * @hide
+ **/
+ public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
ROUTE_SPEAKER;
private final boolean isMuted;
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2b9a508..7d258a0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -723,6 +723,7 @@
public void onDestroyed(Connection c) {}
public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {}
public void onConnectionPropertiesChanged(Connection c, int properties) {}
+ public void onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes) {}
public void onVideoProviderChanged(
Connection c, VideoProvider videoProvider) {}
public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {}
@@ -1485,6 +1486,7 @@
private boolean mRingbackRequested = false;
private int mConnectionCapabilities;
private int mConnectionProperties;
+ private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
private VideoProvider mVideoProvider;
private boolean mAudioModeIsVoip;
private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED;
@@ -1765,6 +1767,15 @@
}
/**
+ * Returns the connection's supported audio routes.
+ *
+ * @hide
+ */
+ public final int getSupportedAudioRoutes() {
+ return mSupportedAudioRoutes;
+ }
+
+ /**
* Sets the value of the {@link #getAddress()} property.
*
* @param address The new address.
@@ -1986,6 +1997,28 @@
}
/**
+ * Sets the supported audio routes.
+ *
+ * @param supportedAudioRoutes the supported audio routes as a bitmask.
+ * See {@link CallAudioState}
+ * @hide
+ */
+ public final void setSupportedAudioRoutes(int supportedAudioRoutes) {
+ if ((supportedAudioRoutes
+ & (CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER)) == 0) {
+ throw new IllegalArgumentException(
+ "supported audio routes must include either speaker or earpiece");
+ }
+
+ if (mSupportedAudioRoutes != supportedAudioRoutes) {
+ mSupportedAudioRoutes = supportedAudioRoutes;
+ for (Listener l : mListeners) {
+ l.onSupportedAudioRoutesChanged(this, mSupportedAudioRoutes);
+ }
+ }
+ }
+
+ /**
* Tears down the Connection object.
*/
public final void destroy() {
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index c2a0ff1..b119e16 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1131,6 +1131,7 @@
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
+ connection.getSupportedAudioRoutes(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
@@ -1530,6 +1531,7 @@
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
+ connection.getSupportedAudioRoutes(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 1900cb9..a3fce9c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -39,6 +39,7 @@
private final List<String> mCannedSmsResponses;
private final int mCapabilities;
private final int mProperties;
+ private final int mSupportedAudioRoutes;
private final long mConnectTimeMillis;
private final Uri mHandle;
private final int mHandlePresentation;
@@ -64,6 +65,7 @@
List<String> cannedSmsResponses,
int capabilities,
int properties,
+ int supportedAudioRoutes,
long connectTimeMillis,
Uri handle,
int handlePresentation,
@@ -86,6 +88,7 @@
mCannedSmsResponses = cannedSmsResponses;
mCapabilities = capabilities;
mProperties = properties;
+ mSupportedAudioRoutes = supportedAudioRoutes;
mConnectTimeMillis = connectTimeMillis;
mHandle = handle;
mHandlePresentation = handlePresentation;
@@ -137,6 +140,11 @@
/** Bitmask of properties of the call. */
public int getProperties() { return mProperties; }
+ /** Bitmask of supported routes of the call */
+ public int getSupportedAudioRoutes() {
+ return mSupportedAudioRoutes;
+ }
+
/** The time that the call switched to the active state. */
public long getConnectTimeMillis() {
return mConnectTimeMillis;
@@ -292,6 +300,7 @@
source.readList(conferenceableCallIds, classLoader);
Bundle intentExtras = source.readBundle(classLoader);
Bundle extras = source.readBundle(classLoader);
+ int supportedAudioRoutes = source.readInt();
return new ParcelableCall(
id,
state,
@@ -299,6 +308,7 @@
cannedSmsResponses,
capabilities,
properties,
+ supportedAudioRoutes,
connectTimeMillis,
handle,
handlePresentation,
@@ -355,6 +365,7 @@
destination.writeList(mConferenceableCallIds);
destination.writeBundle(mIntentExtras);
destination.writeBundle(mExtras);
+ destination.writeInt(mSupportedAudioRoutes);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableConnection.java b/telecomm/java/android/telecom/ParcelableConnection.java
index 540f388..e9dba68 100644
--- a/telecomm/java/android/telecom/ParcelableConnection.java
+++ b/telecomm/java/android/telecom/ParcelableConnection.java
@@ -37,6 +37,7 @@
private final int mState;
private final int mConnectionCapabilities;
private final int mConnectionProperties;
+ private final int mSupportedAudioRoutes;
private final Uri mAddress;
private final int mAddressPresentation;
private final String mCallerDisplayName;
@@ -57,6 +58,7 @@
int state,
int capabilities,
int properties,
+ int supportedAudioRoutes,
Uri address,
int addressPresentation,
String callerDisplayName,
@@ -74,6 +76,7 @@
mState = state;
mConnectionCapabilities = capabilities;
mConnectionProperties = properties;
+ mSupportedAudioRoutes = supportedAudioRoutes;
mAddress = address;
mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName;
@@ -117,6 +120,10 @@
return mConnectionProperties;
}
+ public int getSupportedAudioRoutes() {
+ return mSupportedAudioRoutes;
+ }
+
public Uri getHandle() {
return mAddress;
}
@@ -210,12 +217,14 @@
source.readStringList(conferenceableConnectionIds);
Bundle extras = Bundle.setDefusable(source.readBundle(classLoader), true);
int properties = source.readInt();
+ int supportedAudioRoutes = source.readInt();
return new ParcelableConnection(
phoneAccount,
state,
capabilities,
properties,
+ supportedAudioRoutes,
address,
addressPresentation,
callerDisplayName,
@@ -264,5 +273,6 @@
destination.writeStringList(mConferenceableConnectionIds);
destination.writeBundle(mExtras);
destination.writeInt(mConnectionProperties);
+ destination.writeInt(mSupportedAudioRoutes);
}
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 0457d63..ca54486 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -17,15 +17,6 @@
package android.telecom;
import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
@@ -37,7 +28,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.MissingResourceException;
/**
* Represents a distinct method to place or receive a phone call. Apps which can place calls and
@@ -237,6 +227,7 @@
private final CharSequence mLabel;
private final CharSequence mShortDescription;
private final List<String> mSupportedUriSchemes;
+ private final int mSupportedAudioRoutes;
private final Icon mIcon;
private final Bundle mExtras;
private boolean mIsEnabled;
@@ -246,10 +237,12 @@
* Helper class for creating a {@link PhoneAccount}.
*/
public static class Builder {
+
private PhoneAccountHandle mAccountHandle;
private Uri mAddress;
private Uri mSubscriptionAddress;
private int mCapabilities;
+ private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
private int mHighlightColor = NO_HIGHLIGHT_COLOR;
private CharSequence mLabel;
private CharSequence mShortDescription;
@@ -286,6 +279,7 @@
mIsEnabled = phoneAccount.isEnabled();
mExtras = phoneAccount.getExtras();
mGroupId = phoneAccount.getGroupId();
+ mSupportedAudioRoutes = phoneAccount.getSupportedAudioRoutes();
}
/**
@@ -431,6 +425,18 @@
}
/**
+ * Sets the audio routes supported by this {@link PhoneAccount}.
+ *
+ * @param routes bit mask of available routes.
+ * @return The builder.
+ * @hide
+ */
+ public Builder setSupportedAudioRoutes(int routes) {
+ mSupportedAudioRoutes = routes;
+ return this;
+ }
+
+ /**
* Creates an instance of a {@link PhoneAccount} based on the current builder settings.
*
* @return The {@link PhoneAccount}.
@@ -452,6 +458,7 @@
mShortDescription,
mSupportedUriSchemes,
mExtras,
+ mSupportedAudioRoutes,
mIsEnabled,
mGroupId);
}
@@ -468,6 +475,7 @@
CharSequence shortDescription,
List<String> supportedUriSchemes,
Bundle extras,
+ int supportedAudioRoutes,
boolean isEnabled,
String groupId) {
mAccountHandle = account;
@@ -480,6 +488,7 @@
mShortDescription = shortDescription;
mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
mExtras = extras;
+ mSupportedAudioRoutes = supportedAudioRoutes;
mIsEnabled = isEnabled;
mGroupId = groupId;
}
@@ -553,6 +562,17 @@
}
/**
+ * Determines if this {@code PhoneAccount} has routes specified by the passed in bit mask.
+ *
+ * @param route The routes to check.
+ * @return {@code true} if the phone account has the routes.
+ * @hide
+ */
+ public boolean hasAudioRoutes(int routes) {
+ return (mSupportedAudioRoutes & routes) == routes;
+ }
+
+ /**
* A short label describing a {@code PhoneAccount}.
*
* @return A label for this {@code PhoneAccount}.
@@ -592,6 +612,15 @@
}
/**
+ * The audio routes supported by this {@code PhoneAccount}.
+ *
+ * @hide
+ */
+ public int getSupportedAudioRoutes() {
+ return mSupportedAudioRoutes;
+ }
+
+ /**
* The icon to represent this {@code PhoneAccount}.
*
* @return The icon.
@@ -707,6 +736,7 @@
out.writeByte((byte) (mIsEnabled ? 1 : 0));
out.writeBundle(mExtras);
out.writeString(mGroupId);
+ out.writeInt(mSupportedAudioRoutes);
}
public static final Creator<PhoneAccount> CREATOR
@@ -751,6 +781,7 @@
mIsEnabled = in.readByte() == 1;
mExtras = in.readBundle();
mGroupId = in.readString();
+ mSupportedAudioRoutes = in.readInt();
}
@Override
@@ -760,7 +791,9 @@
.append("] PhoneAccount: ")
.append(mAccountHandle)
.append(" Capabilities: ")
- .append(capabilitiesToString(mCapabilities))
+ .append(capabilitiesToString())
+ .append(" Audio Routes: ")
+ .append(audioRoutesToString())
.append(" Schemes: ");
for (String scheme : mSupportedUriSchemes) {
sb.append(scheme)
@@ -780,7 +813,7 @@
* @param capabilities The capabilities bitmask.
* @return String representation of the capabilities bitmask.
*/
- private String capabilitiesToString(int capabilities) {
+ private String capabilitiesToString() {
StringBuilder sb = new StringBuilder();
if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) {
sb.append("SuppVideo ");
@@ -817,4 +850,23 @@
}
return sb.toString();
}
+
+ private String audioRoutesToString() {
+ StringBuilder sb = new StringBuilder();
+
+ if (hasAudioRoutes(CallAudioState.ROUTE_BLUETOOTH)) {
+ sb.append("B");
+ }
+ if (hasAudioRoutes(CallAudioState.ROUTE_EARPIECE)) {
+ sb.append("E");
+ }
+ if (hasAudioRoutes(CallAudioState.ROUTE_SPEAKER)) {
+ sb.append("S");
+ }
+ if (hasAudioRoutes(CallAudioState.ROUTE_WIRED_HEADSET)) {
+ sb.append("W");
+ }
+
+ return sb.toString();
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1f06283..d7f96a9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1067,7 +1067,7 @@
* is returned.
* @hide
*/
- public static final String FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
+ public static final String KEY_FILTERED_CNAP_NAMES_STRING_ARRAY = "filtered_cnap_names_string_array";
/**
* The RCS configuration server URL. This URL is used to initiate RCS provisioning.
@@ -1097,6 +1097,11 @@
*/
public static final String KEY_PERSIST_LPP_MODE_BOOL = "persist_lpp_mode_bool";
+ /**
+ * Carrier specified WiFi networks.
+ * @hide
+ */
+ public static final String KEY_CARRIER_WIFI_STRING_ARRAY = "carrier_wifi_string_array";
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1291,10 +1296,11 @@
sDefaults.putStringArray(KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, false);
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
- sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
+ sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
sDefaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, false);
+ sDefaults.putStringArray(KEY_CARRIER_WIFI_STRING_ARRAY, null);
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index addf7ef..4137853 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -141,6 +141,16 @@
}
/**
+ * Get the GSM timing advance between 0..219 symbols (normally 0..63).
+ * Integer.MAX_VALUE is reported when there is no RR connection.
+ * Refer to 3GPP 45.010 Sec 5.8
+ * @return the current GSM timing advance, if available.
+ */
+ public int getTimingAdvance() {
+ return mTimingAdvance;
+ }
+
+ /**
* Get the signal strength as dBm
*/
@Override
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 434caad..0d07a40 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -220,8 +220,10 @@
}
/**
- * Get the timing advance value for LTE.
- * See 3GPP xxxx
+ * Get the timing advance value for LTE, as a value between 0..63.
+ * Integer.MAX_VALUE is reported when there is no active RRC
+ * connection. Refer to 3GPP 36.213 Sec 4.2.3
+ * @return the LTE timing advance, if available.
*/
public int getTimingAdvance() {
return mTimingAdvance;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 11d84c1..7a83979 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.Rlog;
+import android.text.TextUtils;
/**
* Contains phone state and service related information.
@@ -590,6 +591,24 @@
}
/**
+ * Get current registered operator name in long alphanumeric format if
+ * available or short otherwise.
+ *
+ * @see #getOperatorAlphaLong
+ * @see #getOperatorAlphaShort
+ *
+ * @return name of operator, null if unregistered or unknown
+ * @hide
+ */
+ public String getOperatorAlpha() {
+ if (TextUtils.isEmpty(mVoiceOperatorAlphaLong)) {
+ return mVoiceOperatorAlphaShort;
+ }
+
+ return mVoiceOperatorAlphaLong;
+ }
+
+ /**
* Get current registered operator numeric id.
*
* In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 457fd88..918ef5e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2275,6 +2275,8 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* OR
* {@link android.Manifest.permission#READ_SMS}
+ * OR
+ * {@link android.Manifest.permission#READ_PHONE_NUMBER}
* <p>
* The default SMS app can also use this.
*/
@@ -2290,6 +2292,8 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* OR
* {@link android.Manifest.permission#READ_SMS}
+ * OR
+ * {@link android.Manifest.permission#READ_PHONE_NUMBER}
* <p>
* The default SMS app can also use this.
*
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index fee3aa5..1bd5b1d 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -524,14 +524,6 @@
throw new UnsupportedOperationException();
}
- /** @hide */
- @Override
- public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
- int badgeDensity) {
- throw new UnsupportedOperationException();
- }
-
-
@Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
throw new UnsupportedOperationException();
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index ca2d2e7..6ca59b0 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -91,7 +91,7 @@
while r in raw: raw.remove(r)
self.split = list(raw)
- for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract"]:
+ for r in ["method", "public", "protected", "static", "final", "deprecated", "abstract", "default"]:
while r in raw: raw.remove(r)
self.typ = raw[0]
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index 4974a44..868d90a 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -79,6 +79,7 @@
string tabPattern;
// For build/install/test
+ bool noRestart;
bool reboot;
vector<Target*> targets;
@@ -89,6 +90,7 @@
Options::Options()
:runHelp(false),
runTab(false),
+ noRestart(false),
reboot(false),
targets()
{
@@ -285,6 +287,7 @@
fprintf(out, " -i Install the targets\n");
fprintf(out, " -t Run the tests\n");
fprintf(out, "\n");
+ fprintf(out, " -n Don't reboot or restart\n");
fprintf(out, " -r If the runtime needs to be restarted, do a full reboot\n");
fprintf(out, " instead\n");
fprintf(out, "\n");
@@ -431,6 +434,9 @@
flagTest = true;
anyPhases = true;
break;
+ case 'n':
+ options->noRestart = true;
+ break;
case 'r':
options->reboot = true;
break;
@@ -558,7 +564,7 @@
* Run the build, install, and test actions.
*/
void
-run_phases(vector<Target*> targets, bool reboot)
+run_phases(vector<Target*> targets, const Options& options)
{
int err = 0;
@@ -676,40 +682,44 @@
check_device_property("ro.build.id", buildId);
// Stop & Sync
- err = run_adb("shell", "stop", NULL);
- check_error(err);
+ if (!options.noRestart) {
+ err = run_adb("shell", "stop", NULL);
+ check_error(err);
+ }
err = run_adb("remount", NULL);
check_error(err);
err = run_adb("sync", "system", NULL);
check_error(err);
- if (reboot) {
- print_status("Rebooting");
+ if (!options.noRestart) {
+ if (options.reboot) {
+ print_status("Rebooting");
- err = run_adb("reboot", NULL);
- check_error(err);
- err = run_adb("wait-for-device", NULL);
- check_error(err);
- } else {
- print_status("Restarting the runtime");
+ err = run_adb("reboot", NULL);
+ check_error(err);
+ err = run_adb("wait-for-device", NULL);
+ check_error(err);
+ } else {
+ print_status("Restarting the runtime");
- err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
- check_error(err);
- err = run_adb("shell", "start", NULL);
- check_error(err);
- }
-
- while (true) {
- string completed = get_system_property("sys.boot_completed", &err);
- check_error(err);
- if (completed == "1") {
- break;
+ err = run_adb("shell", "setprop", "sys.boot_completed", "0", NULL);
+ check_error(err);
+ err = run_adb("shell", "start", NULL);
+ check_error(err);
}
- sleep(2);
+
+ while (true) {
+ string completed = get_system_property("sys.boot_completed", &err);
+ check_error(err);
+ if (completed == "1") {
+ break;
+ }
+ sleep(2);
+ }
+ sleep(1);
+ err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
+ check_error(err);
}
- sleep(1);
- err = run_adb("shell", "wm", "dismiss-keyguard", NULL);
- check_error(err);
}
}
@@ -976,7 +986,7 @@
exit(0);
} else {
// Normal run
- run_phases(options.targets, options.reboot);
+ run_phases(options.targets, options);
}
return 0;
diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
index c96d2ca..34c7845 100644
--- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java
+++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
@@ -34,7 +34,7 @@
* Is not supposed to return null, but that is fine for layoutlib.
*/
public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
- return null;
+ throw new ServiceNotFoundException(name);
}
/**
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 4596210..a0ded87 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -20,6 +20,7 @@
import android.graphics.Rect;
import com.android.internal.app.IAssistScreenshotReceiver;
import com.android.internal.os.IResultReceiver;
+import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethodClient;
@@ -516,11 +517,7 @@
}
@Override
- public void dismissKeyguard() {
- }
-
- @Override
- public void keyguardGoingAway(int flags) throws RemoteException {
+ public void dismissKeyguard(IKeyguardDismissCallback callback) throws RemoteException {
}
@Override
diff --git a/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java
new file mode 100644
index 0000000..06874bd
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/textservice/TextServicesManager.java
@@ -0,0 +1,342 @@
+/*
+ * 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 android.view.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
+
+import java.util.Locale;
+
+/**
+ * System API to the overall text services, which arbitrates interaction between applications
+ * and text services. You can retrieve an instance of this interface with
+ * {@link Context#getSystemService(String) Context.getSystemService()}.
+ *
+ * The user can change the current text services in Settings. And also applications can specify
+ * the target text services.
+ *
+ * <h3>Architecture Overview</h3>
+ *
+ * <p>There are three primary parties involved in the text services
+ * framework (TSF) architecture:</p>
+ *
+ * <ul>
+ * <li> The <strong>text services manager</strong> as expressed by this class
+ * is the central point of the system that manages interaction between all
+ * other parts. It is expressed as the client-side API here which exists
+ * in each application context and communicates with a global system service
+ * that manages the interaction across all processes.
+ * <li> A <strong>text service</strong> implements a particular
+ * interaction model allowing the client application to retrieve information of text.
+ * The system binds to the current text service that is in use, causing it to be created and run.
+ * <li> Multiple <strong>client applications</strong> arbitrate with the text service
+ * manager for connections to text services.
+ * </ul>
+ *
+ * <h3>Text services sessions</h3>
+ * <ul>
+ * <li>The <strong>spell checker session</strong> is one of the text services.
+ * {@link android.view.textservice.SpellCheckerSession}</li>
+ * </ul>
+ *
+ */
+public final class TextServicesManager {
+ private static final String TAG = TextServicesManager.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private static TextServicesManager sInstance;
+
+ private final ITextServicesManager mService;
+
+ private TextServicesManager() {
+ mService = new FakeTextServicesManager();
+ }
+
+ /**
+ * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
+ * @hide
+ */
+ public static TextServicesManager getInstance() {
+ synchronized (TextServicesManager.class) {
+ if (sInstance == null) {
+ sInstance = new TextServicesManager();
+ }
+ return sInstance;
+ }
+ }
+
+ /**
+ * Returns the language component of a given locale string.
+ */
+ private static String parseLanguageFromLocaleString(String locale) {
+ final int idx = locale.indexOf('_');
+ if (idx < 0) {
+ return locale;
+ } else {
+ return locale.substring(0, idx);
+ }
+ }
+
+ /**
+ * Get a spell checker session for the specified spell checker
+ * @param locale the locale for the spell checker. If {@code locale} is null and
+ * referToSpellCheckerLanguageSettings is true, the locale specified in Settings will be
+ * returned. If {@code locale} is not null and referToSpellCheckerLanguageSettings is true,
+ * the locale specified in Settings will be returned only when it is same as {@code locale}.
+ * Exceptionally, when referToSpellCheckerLanguageSettings is true and {@code locale} is
+ * only language (e.g. "en"), the specified locale in Settings (e.g. "en_US") will be
+ * selected.
+ * @param listener a spell checker session lister for getting results from a spell checker.
+ * @param referToSpellCheckerLanguageSettings if true, the session for one of enabled
+ * languages in settings will be returned.
+ * @return the spell checker session of the spell checker
+ */
+ public SpellCheckerSession newSpellCheckerSession(Bundle bundle, Locale locale,
+ SpellCheckerSessionListener listener, boolean referToSpellCheckerLanguageSettings) {
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ if (!referToSpellCheckerLanguageSettings && locale == null) {
+ throw new IllegalArgumentException("Locale should not be null if you don't refer"
+ + " settings.");
+ }
+
+ if (referToSpellCheckerLanguageSettings && !isSpellCheckerEnabled()) {
+ return null;
+ }
+
+ final SpellCheckerInfo sci;
+ try {
+ sci = mService.getCurrentSpellChecker(null);
+ } catch (RemoteException e) {
+ return null;
+ }
+ if (sci == null) {
+ return null;
+ }
+ SpellCheckerSubtype subtypeInUse = null;
+ if (referToSpellCheckerLanguageSettings) {
+ subtypeInUse = getCurrentSpellCheckerSubtype(true);
+ if (subtypeInUse == null) {
+ return null;
+ }
+ if (locale != null) {
+ final String subtypeLocale = subtypeInUse.getLocale();
+ final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale);
+ if (subtypeLanguage.length() < 2 || !locale.getLanguage().equals(subtypeLanguage)) {
+ return null;
+ }
+ }
+ } else {
+ final String localeStr = locale.toString();
+ for (int i = 0; i < sci.getSubtypeCount(); ++i) {
+ final SpellCheckerSubtype subtype = sci.getSubtypeAt(i);
+ final String tempSubtypeLocale = subtype.getLocale();
+ final String tempSubtypeLanguage = parseLanguageFromLocaleString(tempSubtypeLocale);
+ if (tempSubtypeLocale.equals(localeStr)) {
+ subtypeInUse = subtype;
+ break;
+ } else if (tempSubtypeLanguage.length() >= 2 &&
+ locale.getLanguage().equals(tempSubtypeLanguage)) {
+ subtypeInUse = subtype;
+ }
+ }
+ }
+ if (subtypeInUse == null) {
+ return null;
+ }
+ final SpellCheckerSession session = new SpellCheckerSession(
+ sci, mService, listener, subtypeInUse);
+ try {
+ mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(),
+ session.getTextServicesSessionListener(),
+ session.getSpellCheckerSessionListener(), bundle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return session;
+ }
+
+ /**
+ * @hide
+ */
+ public SpellCheckerInfo[] getEnabledSpellCheckers() {
+ try {
+ final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers();
+ if (DBG) {
+ Log.d(TAG, "getEnabledSpellCheckers: " + (retval != null ? retval.length : "null"));
+ }
+ return retval;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public SpellCheckerInfo getCurrentSpellChecker() {
+ try {
+ // Passing null as a locale for ICS
+ return mService.getCurrentSpellChecker(null);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setCurrentSpellChecker(SpellCheckerInfo sci) {
+ try {
+ if (sci == null) {
+ throw new NullPointerException("SpellCheckerInfo is null.");
+ }
+ mService.setCurrentSpellChecker(null, sci.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
+ boolean allowImplicitlySelectedSubtype) {
+ try {
+ // Passing null as a locale until we support multiple enabled spell checker subtypes.
+ return mService.getCurrentSpellCheckerSubtype(null, allowImplicitlySelectedSubtype);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setSpellCheckerSubtype(SpellCheckerSubtype subtype) {
+ try {
+ final int hashCode;
+ if (subtype == null) {
+ hashCode = 0;
+ } else {
+ hashCode = subtype.hashCode();
+ }
+ mService.setCurrentSpellCheckerSubtype(null, hashCode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setSpellCheckerEnabled(boolean enabled) {
+ try {
+ mService.setSpellCheckerEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean isSpellCheckerEnabled() {
+ try {
+ return mService.isSpellCheckerEnabled();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static class FakeTextServicesManager implements ITextServicesManager {
+
+ @Override
+ public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void getSpellCheckerService(String arg0, String arg1,
+ ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean isSpellCheckerEnabled() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public IBinder asBinder() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
deleted file mode 100644
index 3017292..0000000
--- a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2011 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.textservice;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.view.textservice.SpellCheckerInfo;
-import android.view.textservice.SpellCheckerSubtype;
-
-
-/**
- * Delegate used to provide new implementation of a select few methods of
- * {@link ITextServicesManager$Stub}
- *
- * Through the layoutlib_create tool, the original methods of Stub have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- */
-public class ITextServicesManager_Stub_Delegate {
-
- @LayoutlibDelegate
- public static ITextServicesManager asInterface(IBinder obj) {
- // ignore the obj and return a fake interface implementation
- return new FakeTextServicesManager();
- }
-
- private static class FakeTextServicesManager implements ITextServicesManager {
-
- @Override
- public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
- throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
- throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void getSpellCheckerService(String arg0, String arg1,
- ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
- throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean isSpellCheckerEnabled() throws RemoteException {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public IBinder asBinder() {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
- }
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
index 0f39e80..ffce1a0 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/animation/NativeInterpolatorFactoryHelper_Delegate.java
@@ -104,7 +104,7 @@
@Override
public float getInterpolation(float input) {
- float lutpos = input * mSize;
+ float lutpos = input * (mSize - 1);
if (lutpos >= (mSize - 1)) {
return mValues[mSize - 1];
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 0b169bd..f47b105 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -495,12 +495,6 @@
}
@Override
- public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
- int badgeDensity) {
- return null;
- }
-
- @Override
public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
return null;
}
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 565feb6..9ee416a 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -30,7 +30,7 @@
layoutlib_api-prebuilt \
tools-common-prebuilt \
sdk-common \
- junit
+ junit-host
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index b7d08f2..a23bad6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -235,7 +235,6 @@
"android.view.ViewGroup#drawChild",
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
- "com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
"dalvik.system.VMRuntime#newUnpaddedArray",
"libcore.io.MemoryMappedFile#mmapRO",
"libcore.io.MemoryMappedFile#close",
@@ -304,6 +303,7 @@
private final static String[] RENAMED_CLASSES =
new String[] {
"android.os.ServiceManager", "android.os._Original_ServiceManager",
+ "android.view.textservice.TextServicesManager", "android.view.textservice._Original_TextServicesManager",
"android.util.LruCache", "android.util._Original_LruCache",
"android.view.SurfaceView", "android.view._Original_SurfaceView",
"android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index dafb9c6..61e381d 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -23,7 +23,7 @@
LOCAL_MODULE := layoutlib-create-tests
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := layoutlib_create junit
+LOCAL_JAVA_LIBRARIES := layoutlib_create junit-host
LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
index 09d95ff..769db6b 100644
--- a/tools/preload2/Android.mk
+++ b/tools/preload2/Android.mk
@@ -12,7 +12,7 @@
# For JDWP access we use the framework in the JDWP tests from Apache Harmony, for
# convenience (and to not depend on internal JDK APIs).
-LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit
+LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit-host
LOCAL_MODULE:= preload2
diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool
index 36dbc1c..322b62f 100644
--- a/tools/preload2/preload-tool
+++ b/tools/preload2/preload-tool
@@ -34,4 +34,4 @@
PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
ANDROID_ROOT=$PROG_DIR/..
-java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main
+java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main $@
diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java
index ca5b0e0..c42a19b 100644
--- a/tools/preload2/src/com/android/preload/Main.java
+++ b/tools/preload2/src/com/android/preload/Main.java
@@ -32,12 +32,18 @@
import com.android.preload.classdataretrieval.ClassDataRetriever;
import com.android.preload.classdataretrieval.hprof.Hprof;
import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever;
-import com.android.preload.ui.UI;
+import com.android.preload.ui.IUI;
+import com.android.preload.ui.SequenceUI;
+import com.android.preload.ui.SwingUI;
+import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import javax.swing.Action;
import javax.swing.DefaultListModel;
@@ -66,7 +72,7 @@
private DumpTableModel dataTableModel;
private DefaultListModel<Client> clientListModel;
- private UI ui;
+ private IUI ui;
// Actions that need to be updated once a device is selected.
private Collection<DeviceSpecific> deviceSpecificActions;
@@ -85,17 +91,30 @@
+ "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|"
+ "(.*\\$NoPreloadHolder$)";
+ public final static String SCAN_ALL_CMD = "scan-all";
+ public final static String SCAN_PACKAGE_CMD = "scan";
+ public final static String COMPUTE_FILE_CMD = "comp";
+ public final static String EXPORT_CMD = "export";
+ public final static String IMPORT_CMD = "import";
+
/**
* @param args
*/
public static void main(String[] args) {
- Main m = new Main();
- top = m;
+ Main m;
+ if (args.length > 0 && args[0].equals("--seq")) {
+ m = createSequencedMain(args);
+ } else {
+ m = new Main(new SwingUI());
+ }
+ top = m;
m.startUp();
}
- public Main() {
+ public Main(IUI ui) {
+ this.ui = ui;
+
clientListModel = new DefaultListModel<Client>();
dataTableModel = new DumpTableModel();
@@ -124,11 +143,74 @@
}
}
- ui = new UI(clientListModel, dataTableModel, actions);
- ui.setVisible(true);
+ ui.prepare(clientListModel, dataTableModel, actions);
}
- public static UI getUI() {
+ /**
+ * @param args
+ * @return
+ */
+ private static Main createSequencedMain(String[] args) {
+ SequenceUI ui = new SequenceUI();
+ Main main = new Main(ui);
+
+ Iterator<String> it = Arrays.asList(args).iterator();
+ it.next(); // --seq
+ // Setup
+ ui.choice("#" + it.next()); // Device.
+ ui.confirmNo(); // Prepare: no.
+ // Actions
+ try {
+ while (it.hasNext()) {
+ String op = it.next();
+ // Operation: Scan a single package
+ if (SCAN_PACKAGE_CMD.equals(op)) {
+ System.out.println("Scanning package.");
+ ui.action(ScanPackageAction.class);
+ ui.client(it.next());
+ // Operation: Scan all packages
+ } else if (SCAN_ALL_CMD.equals(op)) {
+ System.out.println("Scanning all packages.");
+ ui.action(ScanAllPackagesAction.class);
+ // Operation: Export the output to a file
+ } else if (EXPORT_CMD.equals(op)) {
+ System.out.println("Exporting data.");
+ ui.action(ExportAction.class);
+ ui.output(new File(it.next()));
+ // Operation: Import the input from a file or directory
+ } else if (IMPORT_CMD.equals(op)) {
+ System.out.println("Importing data.");
+ File file = new File(it.next());
+ if (!file.exists()) {
+ throw new RuntimeException(
+ String.format("File does not exist, %s.", file.getAbsolutePath()));
+ } else if (file.isFile()) {
+ ui.action(ImportAction.class);
+ ui.input(file);
+ } else if (file.isDirectory()) {
+ for (File content : file.listFiles()) {
+ ui.action(ImportAction.class);
+ ui.input(content);
+ }
+ }
+ // Operation: Compute preloaded classes with specific threshold
+ } else if (COMPUTE_FILE_CMD.equals(op)) {
+ System.out.println("Compute preloaded classes.");
+ ui.action(ComputeThresholdXAction.class);
+ ui.input(it.next());
+ ui.confirmYes();
+ ui.output(new File(it.next()));
+ }
+ }
+ } catch (NoSuchElementException e) {
+ System.out.println("Failed to parse action sequence correctly.");
+ throw e;
+ }
+
+ return main;
+ }
+
+ public static IUI getUI() {
return top.ui;
}
@@ -176,6 +258,7 @@
new ReloadListAction(clientUtils, getDevice(), clientListModel).run();
getUI().hideWaitDialog();
+ getUI().ready();
}
private void initDevice() {
diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
index fbf83d2..5787d85 100644
--- a/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
+++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java
@@ -16,6 +16,7 @@
package com.android.preload.actions;
+import com.android.preload.Main;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
@@ -28,7 +29,11 @@
@Override
public void actionPerformed(ActionEvent e) {
- new Thread(this).start();
+ if (Main.getUI().isSingleThreaded()) {
+ run();
+ } else {
+ new Thread(this).start();
+ }
}
}
diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
index b524716..3a7f7f7 100644
--- a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java
@@ -32,14 +32,13 @@
import java.util.regex.Pattern;
import javax.swing.AbstractAction;
-import javax.swing.JFileChooser;
/**
* Compute an intersection of classes from the given data. A class is in the intersection if it
* appears in at least the number of threshold given packages. An optional blacklist can be
* used to filter classes from the intersection.
*/
-public class ComputeThresholdAction extends AbstractAction implements Runnable {
+public class ComputeThresholdAction extends AbstractThreadedAction {
protected int threshold;
private Pattern blacklist;
private DumpTableModel dataTableModel;
@@ -72,7 +71,7 @@
return;
}
- new Thread(this).start();
+ super.actionPerformed(e);
}
@Override
@@ -92,10 +91,8 @@
boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size()
+ " classes, would you like to save to disk?", "Save?");
if (ret) {
- JFileChooser jfc = new JFileChooser();
- int ret2 = jfc.showSaveDialog(Main.getUI());
- if (ret2 == JFileChooser.APPROVE_OPTION) {
- File f = jfc.getSelectedFile();
+ File f = Main.getUI().showSaveDialog();
+ if (f != null) {
saveSet(result, f);
}
}
diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java
index cb8b3df..848a568 100644
--- a/tools/preload2/src/com/android/preload/actions/ExportAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ExportAction.java
@@ -19,14 +19,11 @@
import com.android.preload.DumpDataIO;
import com.android.preload.DumpTableModel;
import com.android.preload.Main;
-
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.PrintWriter;
-import javax.swing.AbstractAction;
-
-public class ExportAction extends AbstractAction implements Runnable {
+public class ExportAction extends AbstractThreadedAction {
private File lastSaveFile;
private DumpTableModel dataTableModel;
@@ -39,7 +36,7 @@
public void actionPerformed(ActionEvent e) {
lastSaveFile = Main.getUI().showSaveDialog();
if (lastSaveFile != null) {
- new Thread(this).start();
+ super.actionPerformed(e);
}
}
diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java
index 5c19765..bfeeb83 100644
--- a/tools/preload2/src/com/android/preload/actions/ImportAction.java
+++ b/tools/preload2/src/com/android/preload/actions/ImportAction.java
@@ -27,7 +27,7 @@
import javax.swing.AbstractAction;
-public class ImportAction extends AbstractAction implements Runnable {
+public class ImportAction extends AbstractThreadedAction {
private File[] lastOpenFiles;
private DumpTableModel dataTableModel;
@@ -40,7 +40,7 @@
public void actionPerformed(ActionEvent e) {
lastOpenFiles = Main.getUI().showOpenDialog(true);
if (lastOpenFiles != null) {
- new Thread(this).start();
+ super.actionPerformed(e);
}
}
diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
index 385e857..29464fc 100644
--- a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
+++ b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java
@@ -58,7 +58,12 @@
if (packages.isEmpty()) {
packages = DEFAULT_MONKEY_PACKAGES;
}
- new Thread(new RunMonkeyRunnable(packages)).start();
+ Runnable r = new RunMonkeyRunnable(packages);
+ if (Main.getUI().isSingleThreaded()) {
+ r.run();
+ } else {
+ new Thread(r).start();
+ }
}
private class RunMonkeyRunnable implements Runnable {
diff --git a/tools/preload2/src/com/android/preload/ui/IUI.java b/tools/preload2/src/com/android/preload/ui/IUI.java
new file mode 100644
index 0000000..9371463
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/IUI.java
@@ -0,0 +1,45 @@
+package com.android.preload.ui;
+
+import com.android.ddmlib.Client;
+import java.io.File;
+import java.util.List;
+import javax.swing.Action;
+import javax.swing.ListModel;
+import javax.swing.table.TableModel;
+
+/**
+ * UI abstraction for the tool. This allows a graphical mode, command line mode,
+ * or silent mode.
+ */
+public interface IUI {
+
+ void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+ List<Action> actions);
+
+ void ready();
+
+ boolean isSingleThreaded();
+
+ Client getSelectedClient();
+
+ int getSelectedDataTableRow();
+
+ void showWaitDialog();
+
+ void updateWaitDialog(String s);
+
+ void hideWaitDialog();
+
+ void showMessageDialog(String s);
+
+ boolean showConfirmDialog(String title, String message);
+
+ String showInputDialog(String message);
+
+ <T> T showChoiceDialog(String title, String message, T[] choices);
+
+ File showSaveDialog();
+
+ File[] showOpenDialog(boolean multi);
+
+}
diff --git a/tools/preload2/src/com/android/preload/ui/SequenceUI.java b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
new file mode 100644
index 0000000..dc6a4f3
--- /dev/null
+++ b/tools/preload2/src/com/android/preload/ui/SequenceUI.java
@@ -0,0 +1,222 @@
+package com.android.preload.ui;
+
+import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.Action;
+import javax.swing.ListModel;
+import javax.swing.table.TableModel;
+
+public class SequenceUI implements IUI {
+
+ private ListModel<Client> clientListModel;
+ @SuppressWarnings("unused")
+ private TableModel dataTableModel;
+ private List<Action> actions;
+
+ private List<Object> sequence = new LinkedList<>();
+
+ public SequenceUI() {
+ }
+
+ @Override
+ public boolean isSingleThreaded() {
+ return true;
+ }
+
+ @Override
+ public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+ List<Action> actions) {
+ this.clientListModel = clientListModel;
+ this.dataTableModel = dataTableModel;
+ this.actions = actions;
+ }
+
+ public SequenceUI action(Action a) {
+ sequence.add(a);
+ return this;
+ }
+
+ public SequenceUI action(Class<? extends Action> actionClass) {
+ for (Action a : actions) {
+ if (actionClass.equals(a.getClass())) {
+ sequence.add(a);
+ return this;
+ }
+ }
+ throw new IllegalArgumentException("No action of class " + actionClass + " found.");
+ }
+
+ public SequenceUI confirmYes() {
+ sequence.add(Boolean.TRUE);
+ return this;
+ }
+
+ public SequenceUI confirmNo() {
+ sequence.add(Boolean.FALSE);
+ return this;
+ }
+
+ public SequenceUI input(String input) {
+ sequence.add(input);
+ return this;
+ }
+
+ public SequenceUI input(File... f) {
+ sequence.add(f);
+ return this;
+ }
+
+ public SequenceUI output(File f) {
+ sequence.add(f);
+ return this;
+ }
+
+ public SequenceUI tableRow(int i) {
+ sequence.add(i);
+ return this;
+ }
+
+ private class ClientSelector {
+ private String pkg;
+
+ public ClientSelector(String pkg) {
+ this.pkg = pkg;
+ }
+
+ public Client getClient() {
+ for (int i = 0; i < clientListModel.getSize(); i++) {
+ ClientData cd = clientListModel.getElementAt(i).getClientData();
+ if (cd != null) {
+ String s = cd.getClientDescription();
+ if (pkg.equals(s)) {
+ return clientListModel.getElementAt(i);
+ }
+ }
+ }
+ throw new RuntimeException("Didn't find client " + pkg);
+ }
+ }
+
+ public SequenceUI client(String pkg) {
+ sequence.add(new ClientSelector(pkg));
+ return this;
+ }
+
+ public SequenceUI choice(String pattern) {
+ sequence.add(pattern);
+ return this;
+ }
+
+ @Override
+ public void ready() {
+ // Run the actions.
+ // No iterator or foreach loop as the sequence will be emptied while running.
+ try {
+ while (!sequence.isEmpty()) {
+ Object next = sequence.remove(0);
+ if (next instanceof Action) {
+ ((Action)next).actionPerformed(null);
+ } else {
+ throw new IllegalStateException("Didn't expect a non-action: " + next);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
+
+ // Now shut down.
+ System.exit(0);
+ }
+
+ @Override
+ public Client getSelectedClient() {
+ Object next = sequence.remove(0);
+ if (next instanceof ClientSelector) {
+ return ((ClientSelector)next).getClient();
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public int getSelectedDataTableRow() {
+ Object next = sequence.remove(0);
+ if (next instanceof Integer) {
+ return ((Integer)next).intValue();
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public void showWaitDialog() {
+ }
+
+ @Override
+ public void updateWaitDialog(String s) {
+ System.out.println(s);
+ }
+
+ @Override
+ public void hideWaitDialog() {
+ }
+
+ @Override
+ public void showMessageDialog(String s) {
+ System.out.println(s);
+ }
+
+ @Override
+ public boolean showConfirmDialog(String title, String message) {
+ Object next = sequence.remove(0);
+ if (next instanceof Boolean) {
+ return ((Boolean)next).booleanValue();
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public String showInputDialog(String message) {
+ Object next = sequence.remove(0);
+ if (next instanceof String) {
+ return (String)next;
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public <T> T showChoiceDialog(String title, String message, T[] choices) {
+ Object next = sequence.remove(0);
+ if (next instanceof String) {
+ String s = (String)next;
+ for (T t : choices) {
+ if (t.toString().contains(s)) {
+ return t;
+ }
+ }
+ return null;
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public File showSaveDialog() {
+ Object next = sequence.remove(0);
+ if (next instanceof File) {
+ System.out.println(next);
+ return (File)next;
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+ @Override
+ public File[] showOpenDialog(boolean multi) {
+ Object next = sequence.remove(0);
+ if (next instanceof File[]) {
+ return (File[])next;
+ }
+ throw new IllegalStateException("Unexpected: " + next);
+ }
+
+}
diff --git a/tools/preload2/src/com/android/preload/ui/UI.java b/tools/preload2/src/com/android/preload/ui/SwingUI.java
similarity index 93%
rename from tools/preload2/src/com/android/preload/ui/UI.java
rename to tools/preload2/src/com/android/preload/ui/SwingUI.java
index 47174dd..cab3744 100644
--- a/tools/preload2/src/com/android/preload/ui/UI.java
+++ b/tools/preload2/src/com/android/preload/ui/SwingUI.java
@@ -41,7 +41,7 @@
import javax.swing.SwingUtilities;
import javax.swing.table.TableModel;
-public class UI extends JFrame {
+public class SwingUI extends JFrame implements IUI {
private JList<Client> clientList;
private JTable dataTable;
@@ -49,11 +49,18 @@
// Shared file chooser, means the directory is retained.
private JFileChooser jfc;
- public UI(ListModel<Client> clientListModel,
- TableModel dataTableModel,
- List<Action> actions) {
+ public SwingUI() {
super("Preloaded-classes computation");
+ }
+ @Override
+ public boolean isSingleThreaded() {
+ return false;
+ }
+
+ @Override
+ public void prepare(ListModel<Client> clientListModel, TableModel dataTableModel,
+ List<Action> actions) {
getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)),
BorderLayout.WEST);
clientList.setCellRenderer(new ClientListCellRenderer());
@@ -74,18 +81,27 @@
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 800, 600);
+
+ setVisible(true);
}
+ @Override
+ public void ready() {
+ }
+
+ @Override
public Client getSelectedClient() {
return clientList.getSelectedValue();
}
+ @Override
public int getSelectedDataTableRow() {
return dataTable.getSelectedRow();
}
private JDialog currentWaitDialog = null;
+ @Override
public void showWaitDialog() {
if (currentWaitDialog == null) {
currentWaitDialog = new JDialog(this, "Please wait...", true);
@@ -111,6 +127,7 @@
});
}
+ @Override
public void updateWaitDialog(String s) {
if (currentWaitDialog != null) {
((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s);
@@ -124,6 +141,7 @@
}
}
+ @Override
public void hideWaitDialog() {
if (currentWaitDialog != null) {
currentWaitDialog.setVisible(false);
@@ -131,6 +149,7 @@
}
}
+ @Override
public void showMessageDialog(String s) {
// Hide the wait dialog...
if (currentWaitDialog != null) {
@@ -147,6 +166,7 @@
}
}
+ @Override
public boolean showConfirmDialog(String title, String message) {
// Hide the wait dialog...
if (currentWaitDialog != null) {
@@ -164,6 +184,7 @@
}
}
+ @Override
public String showInputDialog(String message) {
// Hide the wait dialog...
if (currentWaitDialog != null) {
@@ -180,6 +201,7 @@
}
}
+ @Override
@SuppressWarnings("unchecked")
public <T> T showChoiceDialog(String title, String message, T[] choices) {
// Hide the wait dialog...
@@ -203,6 +225,7 @@
}
}
+ @Override
public File showSaveDialog() {
// Hide the wait dialog...
if (currentWaitDialog != null) {
@@ -228,6 +251,7 @@
}
}
+ @Override
public File[] showOpenDialog(boolean multi) {
// Hide the wait dialog...
if (currentWaitDialog != null) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 24cd275..82d41e3 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -685,12 +685,22 @@
/**
* @hide
* A hint about whether or not the network represented by this WifiConfiguration
- * is metered.
+ * is metered. This is hinted at via the meteredHint bit on DHCP results set in
+ * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in
+ * {@link com.android.server.wifi.ExternalScoreEvaluator}.
*/
public boolean meteredHint;
/**
* @hide
+ * Indicates if a user has specified the WifiConfiguration to be metered. Users
+ * can toggle if a network is metered within Settings -> Data Usage -> Network
+ * Restrictions.
+ */
+ public boolean meteredOverride;
+
+ /**
+ * @hide
* Setting this value will force scan results associated with this configuration to
* be included in the bucket of networks that are externally scored.
* If not set, associated scan results will be treated as legacy saved networks and
@@ -1367,6 +1377,7 @@
didSelfAdd = false;
ephemeral = false;
meteredHint = false;
+ meteredOverride = false;
useExternalScores = false;
validatedInternetAccess = false;
mIpConfiguration = new IpConfiguration();
@@ -1470,9 +1481,11 @@
if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess");
if (this.ephemeral) sbuf.append(" ephemeral");
if (this.meteredHint) sbuf.append(" meteredHint");
+ if (this.meteredOverride) sbuf.append(" meteredOverride");
if (this.useExternalScores) sbuf.append(" useExternalScores");
if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess
- || this.ephemeral || this.meteredHint || this.useExternalScores) {
+ || this.ephemeral || this.meteredHint || this.meteredOverride
+ || this.useExternalScores) {
sbuf.append("\n");
}
sbuf.append(" KeyMgmt:");
@@ -1897,6 +1910,7 @@
validatedInternetAccess = source.validatedInternetAccess;
ephemeral = source.ephemeral;
meteredHint = source.meteredHint;
+ meteredOverride = source.meteredOverride;
useExternalScores = source.useExternalScores;
if (source.visibility != null) {
visibility = new Visibility(source.visibility);
@@ -1978,6 +1992,7 @@
dest.writeInt(validatedInternetAccess ? 1 : 0);
dest.writeInt(ephemeral ? 1 : 0);
dest.writeInt(meteredHint ? 1 : 0);
+ dest.writeInt(meteredOverride ? 1 : 0);
dest.writeInt(useExternalScores ? 1 : 0);
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
@@ -2049,6 +2064,7 @@
config.validatedInternetAccess = in.readInt() != 0;
config.ephemeral = in.readInt() != 0;
config.meteredHint = in.readInt() != 0;
+ config.meteredOverride = in.readInt() != 0;
config.useExternalScores = in.readInt() != 0;
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 4aacbae..4b21b15 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -22,7 +22,7 @@
/**
* Defines a request object to configure a Wi-Fi Aware network. Built using
* {@link ConfigRequest.Builder}. Configuration is requested using
- * {@link WifiAwareManager#attach(android.os.Handler, WifiAwareAttachCallback)}.
+ * {@link WifiAwareManager#attach(WifiAwareAttachCallback, android.os.Handler)}.
* Note that the actual achieved configuration may be different from the
* requested configuration - since different applications may request different
* configurations.
diff --git a/wifi/java/android/net/wifi/aware/LvBufferUtils.java b/wifi/java/android/net/wifi/aware/LvBufferUtils.java
deleted file mode 100644
index 3265243..0000000
--- a/wifi/java/android/net/wifi/aware/LvBufferUtils.java
+++ /dev/null
@@ -1,340 +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 android.net.wifi.aware;
-
-import android.annotation.Nullable;
-
-import libcore.io.Memory;
-
-import java.nio.ByteOrder;
-import java.util.Iterator;
-
-/**
- * Utility class to construct and parse byte arrays using the LV format -
- * Length/Value format. The utilities accept a configuration of the size of
- * the Length field.
- *
- * @hide PROPOSED_AWARE_API
- */
-public class LvBufferUtils {
- private LvBufferUtils() {
- // no reason to ever create this class
- }
-
- /**
- * Utility class to construct byte arrays using the LV format - Length/Value.
- * <p>
- * A constructor is created specifying the size of the Length (L) field.
- * <p>
- * The byte array is either provided (using
- * {@link LvBufferUtils.LvConstructor#wrap(byte[])}) or allocated (using
- * {@link LvBufferUtils.LvConstructor#allocate(int)}).
- * <p>
- * Values are added to the structure using the {@code LvConstructor.put*()}
- * methods.
- * <p>
- * The final byte array is obtained using {@link LvBufferUtils.LvConstructor#getArray()}.
- */
- public static class LvConstructor {
- private TlvBufferUtils.TlvConstructor mTlvImpl;
-
- /**
- * Define a LV constructor with the specified size of the Length (L) field.
- *
- * @param lengthSize Number of bytes used for the Length (L) field.
- * Values of 1 or 2 bytes are allowed.
- */
- public LvConstructor(int lengthSize) {
- mTlvImpl = new TlvBufferUtils.TlvConstructor(0, lengthSize);
- }
-
- /**
- * Set the byte array to be used to construct the LV.
- *
- * @param array Byte array to be formatted.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor wrap(@Nullable byte[] array) {
- mTlvImpl.wrap(array);
- return this;
- }
-
- /**
- * Allocates a new byte array to be used ot construct a LV.
- *
- * @param capacity The size of the byte array to be allocated.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor allocate(int capacity) {
- mTlvImpl.allocate(capacity);
- return this;
- }
-
- /**
- * Copies a byte into the LV array.
- *
- * @param b The byte to be inserted into the structure.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putByte(byte b) {
- mTlvImpl.putByte(0, b);
- return this;
- }
-
- /**
- * Copies a byte array into the LV.
- *
- * @param array The array to be copied into the LV structure.
- * @param offset Start copying from the array at the specified offset.
- * @param length Copy the specified number (length) of bytes from the
- * array.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putByteArray(@Nullable byte[] array, int offset,
- int length) {
- mTlvImpl.putByteArray(0, array, offset, length);
- return this;
- }
-
- /**
- * Copies a byte array into the LV.
- *
- * @param array The array to be copied (in full) into the LV structure.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putByteArray(int type, @Nullable byte[] array) {
- return putByteArray(array, 0, (array == null) ? 0 : array.length);
- }
-
- /**
- * Places a zero length element (i.e. Length field = 0) into the LV.
- *
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putZeroLengthElement() {
- mTlvImpl.putZeroLengthElement(0);
- return this;
- }
-
- /**
- * Copies short into the LV.
- *
- * @param data The short to be inserted into the structure.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putShort(short data) {
- mTlvImpl.putShort(0, data);
- return this;
- }
-
- /**
- * Copies integer into the LV.
- *
- * @param data The integer to be inserted into the structure.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putInt(int data) {
- mTlvImpl.putInt(0, data);
- return this;
- }
-
- /**
- * Copies a String's byte representation into the LV.
- *
- * @param data The string whose bytes are to be inserted into the
- * structure.
- * @return The constructor to facilitate chaining
- * {@code ctr.putXXX(..).putXXX(..)}.
- */
- public LvBufferUtils.LvConstructor putString(@Nullable String data) {
- mTlvImpl.putString(0, data);
- return this;
- }
-
- /**
- * Returns the constructed LV formatted byte-array. This array is a copy of the wrapped
- * or allocated array - truncated to just the significant bytes - i.e. those written into
- * the LV.
- *
- * @return The byte array containing the LV formatted structure.
- */
- public byte[] getArray() {
- return mTlvImpl.getArray();
- }
- }
-
- /**
- * Utility class used when iterating over an LV formatted byte-array. Use
- * {@link LvBufferUtils.LvIterable} to iterate over array. A {@link LvBufferUtils.LvElement}
- * represents each entry in a LV formatted byte-array.
- */
- public static class LvElement {
- /**
- * The Length (L) field of the current LV element.
- */
- public int length;
-
- /**
- * The Value (V) field - a raw byte array representing the current LV
- * element where the entry starts at {@link LvBufferUtils.LvElement#offset}.
- */
- public byte[] refArray;
-
- /**
- * The offset to be used into {@link LvBufferUtils.LvElement#refArray} to access the
- * raw data representing the current LV element.
- */
- public int offset;
-
- private LvElement(int length, @Nullable byte[] refArray, int offset) {
- this.length = length;
- this.refArray = refArray;
- this.offset = offset;
- }
-
- /**
- * Utility function to return a byte representation of a LV element of
- * length 1. Note: an attempt to call this function on a LV item whose
- * {@link LvBufferUtils.LvElement#length} is != 1 will result in an exception.
- *
- * @return byte representation of current LV element.
- */
- public byte getByte() {
- if (length != 1) {
- throw new IllegalArgumentException(
- "Accesing a byte from a LV element of length " + length);
- }
- return refArray[offset];
- }
-
- /**
- * Utility function to return a short representation of a LV element of
- * length 2. Note: an attempt to call this function on a LV item whose
- * {@link LvBufferUtils.LvElement#length} is != 2 will result in an exception.
- *
- * @return short representation of current LV element.
- */
- public short getShort() {
- if (length != 2) {
- throw new IllegalArgumentException(
- "Accesing a short from a LV element of length " + length);
- }
- return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN);
- }
-
- /**
- * Utility function to return an integer representation of a LV element
- * of length 4. Note: an attempt to call this function on a LV item
- * whose {@link LvBufferUtils.LvElement#length} is != 4 will result in an exception.
- *
- * @return integer representation of current LV element.
- */
- public int getInt() {
- if (length != 4) {
- throw new IllegalArgumentException(
- "Accesing an int from a LV element of length " + length);
- }
- return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN);
- }
-
- /**
- * Utility function to return a String representation of a LV element.
- *
- * @return String representation of the current LV element.
- */
- public String getString() {
- return new String(refArray, offset, length);
- }
- }
-
- /**
- * Utility class to iterate over a LV formatted byte-array.
- */
- public static class LvIterable implements Iterable<LvBufferUtils.LvElement> {
- private final TlvBufferUtils.TlvIterable mTlvIterable;
-
- /**
- * Constructs an LvIterable object - specifying the format of the LV
- * (the size of the Length field), and the byte array whose data is to be parsed.
- *
- * @param lengthSize Number of bytes sued for the Length (L) field.
- * Values values are 1 or 2 bytes.
- * @param array The LV formatted byte-array to parse.
- */
- public LvIterable(int lengthSize, @Nullable byte[] array) {
- mTlvIterable = new TlvBufferUtils.TlvIterable(0, lengthSize, array);
- }
-
- /**
- * Prints out a parsed representation of the LV-formatted byte array.
- * Whenever possible bytes, shorts, and integer are printed out (for
- * fields whose length is 1, 2, or 4 respectively).
- */
- @Override
- public String toString() {
- return mTlvIterable.toString();
- }
-
- /**
- * Returns an iterator to step through a LV formatted byte-array. The
- * individual elements returned by the iterator are {@link LvBufferUtils.LvElement}.
- */
- @Override
- public Iterator<LvBufferUtils.LvElement> iterator() {
- return new Iterator<LvBufferUtils.LvElement>() {
- private Iterator<TlvBufferUtils.TlvElement> mTlvIterator = mTlvIterable.iterator();
-
- @Override
- public boolean hasNext() {
- return mTlvIterator.hasNext();
- }
-
- @Override
- public LvBufferUtils.LvElement next() {
- TlvBufferUtils.TlvElement tlvE = mTlvIterator.next();
-
- return new LvElement(tlvE.length, tlvE.refArray, tlvE.offset);
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- }
-
- /**
- * Validates that a LV array is constructed correctly. I.e. that its specified Length
- * fields correctly fill the specified length (and do not overshoot).
- *
- * @param array The LV array to verify.
- * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
- * @return A boolean indicating whether the array is valid (true) or invalid (false).
- */
- public static boolean isValid(@Nullable byte[] array, int lengthSize) {
- return TlvBufferUtils.isValid(array, 0, lengthSize);
- }
-}
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index ba493a0..3925bd7 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -28,6 +28,7 @@
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.List;
/**
* Defines the configuration of a Aware publish session. Built using
@@ -84,7 +85,8 @@
/** @hide */
public final boolean mEnableTerminateNotification;
- private PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+ /** @hide */
+ public PublishConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
int publishType, int publichCount, int ttlSec, boolean enableTerminateNotification) {
mServiceName = serviceName;
mServiceSpecificInfo = serviceSpecificInfo;
@@ -99,9 +101,9 @@
public String toString() {
return "PublishConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
(mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
- + ", mTxFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
- + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
- + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
+ + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
+ mMatchFilter)).toString() + ", mPublishType=" + mPublishType + ", mPublishCount="
+ + mPublishCount + ", mTtlSec=" + mTtlSec + ", mEnableTerminateNotification="
+ mEnableTerminateNotification + "]";
}
@@ -186,7 +188,7 @@
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
- if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
+ if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) {
throw new IllegalArgumentException(
"Invalid txFilter configuration - LV fields do not match up to length");
}
@@ -281,18 +283,17 @@
* The match filter for a publish session. Used to determine whether a service
* discovery occurred - in addition to relying on the service name.
* <p>
- * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
- * the Length field) of a value blob.
- * <p>
* Optional. Empty by default.
*
- * @param matchFilter The byte-array containing the LV formatted match filter.
+ * @param matchFilter A list of match filter entries (each of which is an arbitrary byte
+ * array).
*
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder setMatchFilter(@Nullable byte[] matchFilter) {
- mMatchFilter = matchFilter;
+ public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) {
+ mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut(
+ matchFilter).getArray();
return this;
}
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 5e14f8f..bf35445 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -28,6 +28,7 @@
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.List;
/**
* Defines the configuration of a Aware subscribe session. Built using
@@ -106,7 +107,8 @@
/** @hide */
public final boolean mEnableTerminateNotification;
- private SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
+ /** @hide */
+ public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
int subscribeType, int publichCount, int ttlSec, int matchStyle,
boolean enableTerminateNotification) {
mServiceName = serviceName;
@@ -123,10 +125,11 @@
public String toString() {
return "SubscribeConfig [mServiceName='" + mServiceName + ", mServiceSpecificInfo='" + (
(mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
- + ", mMatchFilter=" + (new LvBufferUtils.LvIterable(1, mMatchFilter)).toString()
- + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount
- + ", mTtlSec=" + mTtlSec + ", mMatchType=" + mMatchStyle
- + ", mEnableTerminateNotification=" + mEnableTerminateNotification + "]";
+ + ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
+ mMatchFilter)).toString() + ", mSubscribeType=" + mSubscribeType
+ + ", mSubscribeCount=" + mSubscribeCount + ", mTtlSec=" + mTtlSec + ", mMatchType="
+ + mMatchStyle + ", mEnableTerminateNotification=" + mEnableTerminateNotification
+ + "]";
}
@Override
@@ -213,7 +216,7 @@
throws IllegalArgumentException {
WifiAwareUtils.validateServiceName(mServiceName);
- if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
+ if (!TlvBufferUtils.isValid(mMatchFilter, 0, 1)) {
throw new IllegalArgumentException(
"Invalid matchFilter configuration - LV fields do not match up to length");
}
@@ -313,18 +316,17 @@
* The match filter for a subscribe session. Used to determine whether a service
* discovery occurred - in addition to relying on the service name.
* <p>
- * Format is an LV byte array: a single byte Length field followed by L bytes (the value of
- * the Length field) of a value blob.
- * <p>
* Optional. Empty by default.
*
- * @param matchFilter The byte-array containing the LV formatted match filter.
+ * @param matchFilter A list of match filter entries (each of which is an arbitrary byte
+ * array).
*
* @return The builder to facilitate chaining
* {@code builder.setXXX(..).setXXX(..)}.
*/
- public Builder setMatchFilter(@Nullable byte[] matchFilter) {
- mMatchFilter = matchFilter;
+ public Builder setMatchFilter(@Nullable List<byte[]> matchFilter) {
+ mMatchFilter = new TlvBufferUtils.TlvConstructor(0, 1).allocateAndPut(
+ matchFilter).getArray();
return this;
}
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index 56c9069..29f10e9 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -22,8 +22,10 @@
import java.nio.BufferOverflowException;
import java.nio.ByteOrder;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
+import java.util.List;
import java.util.NoSuchElementException;
/**
@@ -32,7 +34,7 @@
* the Type field and the Length field. A Type field size of 0 is allowed -
* allowing usage for LV (no T) array formats.
*
- * @hide PROPOSED_AWARE_API
+ * @hide
*/
public class TlvBufferUtils {
private TlvBufferUtils() {
@@ -111,6 +113,31 @@
}
/**
+ * Creates a TLV array (of the previously specified Type and Length sizes) from the input
+ * list. Allocates an array matching the contents (and required Type and Length
+ * fields), copies the contents, and set the Length fields. The Type field is set to 0.
+ *
+ * @param list A list of fields to be added to the TLV buffer.
+ * @return The constructor of the TLV.
+ */
+ public TlvConstructor allocateAndPut(@Nullable List<byte[]> list) {
+ if (list != null) {
+ int size = 0;
+ for (byte[] field : list) {
+ size += mTypeSize + mLengthSize;
+ if (field != null) {
+ size += field.length;
+ }
+ }
+ allocate(size);
+ for (byte[] field : list) {
+ putByteArray(0, field);
+ }
+ }
+ return this;
+ }
+
+ /**
* Copies a byte into the TLV with the indicated type. For an LV
* formatted structure (i.e. typeLength=0 in {@link TlvConstructor
* TlvConstructor(int, int)} ) the type field is ignored.
@@ -319,6 +346,10 @@
this.length = length;
this.refArray = refArray;
this.offset = offset;
+
+ if (offset + length > refArray.length) {
+ throw new BufferOverflowException();
+ }
}
/**
@@ -393,7 +424,7 @@
* @param typeSize Number of bytes used for the Type (T) field. Valid
* values are 0 (i.e. indicating the format is LV rather than
* TLV), 1, and 2 bytes.
- * @param lengthSize Number of bytes sued for the Length (L) field.
+ * @param lengthSize Number of bytes used for the Length (L) field.
* Values values are 1 or 2 bytes.
* @param array The TLV formatted byte-array to parse.
*/
@@ -450,6 +481,18 @@
}
/**
+ * Returns a List with the raw contents (no types) of the iterator.
+ */
+ public List<byte[]> toList() {
+ List<byte[]> list = new ArrayList<>();
+ for (TlvElement tlv : this) {
+ list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length));
+ }
+
+ return list;
+ }
+
+ /**
* Returns an iterator to step through a TLV formatted byte-array. The
* individual elements returned by the iterator are {@link TlvElement}.
*/
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
index 072ccab..95d128d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareCharacteristics.java
@@ -69,8 +69,9 @@
/**
* Returns the maximum length of byte array that can be used to specify a Aware match filter.
- * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and
- * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}.
+ * Restricts the parameters of the
+ * {@link PublishConfig.Builder#setMatchFilter(java.util.List<byte[]>)} and
+ * {@link SubscribeConfig.Builder#setMatchFilter(java.util.List<byte[]>)}.
*
* @return A positive integer, maximum legngth of byte array for Aware discovery match filter.
*/
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
index e8335d1..451d8a5 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoveryBaseSession.java
@@ -35,7 +35,7 @@
* <li>Sending messages: {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[])} or
* {@link #sendMessage(WifiAwareManager.PeerHandle, int, byte[], int)} methods.
* <li>Creating a network-specifier when requesting a Aware connection:
- * {@link #createNetworkSpecifier(int, WifiAwareManager.PeerHandle, byte[])}.
+ * {@link #createNetworkSpecifier(WifiAwareManager.PeerHandle, byte[])}.
* </ul>
* The {@link #destroy()} method must be called to destroy discovery sessions once they are
* no longer needed.
@@ -140,7 +140,7 @@
* Sends a message to the specified destination. Aware messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} event.
+ * byte[], java.util.List<byte[]>)} event.
* <p>
* Aware messages are not guaranteed delivery. Callbacks on
* {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
@@ -154,7 +154,7 @@
*
* @param peerHandle The peer's handle for the message. Must be a result of an
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} or
+ * byte[], java.util.List<byte[]>)} or
* {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
* byte[])} events.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
@@ -187,7 +187,7 @@
* Sends a message to the specified destination. Aware messages are transmitted in the context
* of a discovery session - executed subsequent to a publish/subscribe
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} event.
+ * byte[], java.util.List<byte[]>)} event.
* <p>
* Aware messages are not guaranteed delivery. Callbacks on
* {@link WifiAwareDiscoverySessionCallback} indicate message was transmitted successfully,
@@ -203,7 +203,7 @@
*
* @param peerHandle The peer's handle for the message. Must be a result of an
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} or
+ * byte[], java.util.List<byte[]>)} or
* {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
* byte[])} events.
* @param messageId An arbitrary integer used by the caller to identify the message. The same
@@ -220,7 +220,7 @@
/**
* Start a ranging operation with the specified peers. The peer IDs are obtained from an
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} or
+ * byte[], java.util.List<byte[]>)} or
* {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
* byte[])} operation - can
* only range devices which are part of an ongoing discovery session.
@@ -260,13 +260,13 @@
* OOB (out-of-band) mechanism then use the alternative
* {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
* peer's MAC address.
+ * <p>
+ * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+ * and a Publisher is a RESPONDER.
*
- * @param role The role of this device:
- * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
- * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peerHandle The peer's handle obtained through
* {@link WifiAwareDiscoverySessionCallback#onServiceDiscovered(WifiAwareManager.PeerHandle,
- * byte[], byte[])} or
+ * byte[], java.util.List<byte[]>)} or
* {@link WifiAwareDiscoverySessionCallback#onMessageReceived(WifiAwareManager.PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
* from only that peer. A RESPONDER may specified a null - indicating that
@@ -283,8 +283,8 @@
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
- public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
- @Nullable WifiAwareManager.PeerHandle peerHandle, @Nullable byte[] token) {
+ public String createNetworkSpecifier(@Nullable WifiAwareManager.PeerHandle peerHandle,
+ @Nullable byte[] token) {
if (mTerminated) {
Log.w(TAG, "createNetworkSpecifier: called on terminated session");
return null;
@@ -295,6 +295,10 @@
return null;
}
+ int role = this instanceof WifiAwareSubscribeDiscoverySession
+ ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
}
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
index 6331c9c..fdf0d01 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareDiscoverySessionCallback.java
@@ -21,6 +21,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
/**
* Base class for Aware session events callbacks. Should be extended by
@@ -130,11 +131,10 @@
* @param serviceSpecificInfo The service specific information (arbitrary
* byte array) provided by the peer as part of its discovery
* configuration.
- * @param matchFilter The filter (Tx on advertiser and Rx on listener) which
- * resulted in this service discovery.
+ * @param matchFilter The filter which resulted in this service discovery.
*/
public void onServiceDiscovered(WifiAwareManager.PeerHandle peerHandle,
- byte[] serviceSpecificInfo, byte[] matchFilter) {
+ byte[] serviceSpecificInfo, List<byte[]> matchFilter) {
/* empty */
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index a34ef47..029794d 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -45,7 +45,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
+import java.nio.BufferOverflowException;
import java.util.Arrays;
+import java.util.List;
/**
* This class provides the primary API for managing Wi-Fi Aware operations:
@@ -63,7 +65,7 @@
* <li>Create a Aware network specifier to be used with
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
* to set-up a Aware connection with a peer. Refer to
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])} and
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])} and
* {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])}.
* </ul>
* <p>
@@ -114,7 +116,7 @@
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
* {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} or
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])}.
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
*
* @hide PROPOSED_AWARE_API
@@ -224,7 +226,7 @@
* Connection creation role is that of INITIATOR. Used to create a network specifier string
* when requesting a Aware network.
*
- * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
+ * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
* @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_AWARE_DATA_PATH_ROLE_INITIATOR = 0;
@@ -233,7 +235,7 @@
* Connection creation role is that of RESPONDER. Used to create a network specifier string
* when requesting a Aware network.
*
- * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int, PeerHandle, byte[])
+ * @see WifiAwareDiscoveryBaseSession#createNetworkSpecifier(PeerHandle, byte[])
* @see WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])
*/
public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1;
@@ -874,12 +876,22 @@
case CALLBACK_SESSION_TERMINATED:
onProxySessionTerminated(msg.arg1);
break;
- case CALLBACK_MATCH:
- mOriginalCallback.onServiceDiscovered(
- new PeerHandle(msg.arg1),
+ case CALLBACK_MATCH: {
+ List<byte[]> matchFilter = null;
+ byte[] arg = msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2);
+ try {
+ matchFilter = new TlvBufferUtils.TlvIterable(0, 1, arg).toList();
+ } catch (BufferOverflowException e) {
+ matchFilter = null;
+ Log.e(TAG, "onServiceDiscovered: invalid match filter byte array '"
+ + new String(HexEncoding.encode(arg))
+ + "' - cannot be parsed: e=" + e);
+ }
+ mOriginalCallback.onServiceDiscovered(new PeerHandle(msg.arg1),
msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE),
- msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2));
+ matchFilter);
break;
+ }
case CALLBACK_MESSAGE_SEND_SUCCESS:
mOriginalCallback.onMessageSendSucceeded(msg.arg1);
break;
@@ -966,7 +978,7 @@
@Override
public void onMessageReceived(int peerId, byte[] message) {
if (VDBG) {
- Log.v(TAG, "onMessageReceived: peerId='" + peerId);
+ Log.v(TAG, "onMessageReceived: peerId=" + peerId);
}
Message msg = mHandler.obtainMessage(CALLBACK_MESSAGE_RECEIVED);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index acb60a4..005895a 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -193,8 +193,8 @@
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(int,
- * WifiAwareManager.PeerHandle, byte[])}.
+ * {@link WifiAwareDiscoveryBaseSession#createNetworkSpecifier(WifiAwareManager.PeerHandle,
+ * byte[])}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
@@ -211,7 +211,7 @@
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
- * {@link android.net.ConnectivityManager#requestNetwork(NetworkRequest,
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
*/
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 4b6957b..15641ab 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -24,6 +24,10 @@
import org.junit.Test;
import org.junit.rules.ErrorCollector;
+import java.nio.BufferOverflowException;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Unit test harness for TlvBufferUtils class.
*/
@@ -47,9 +51,9 @@
collector.checkThat("tlv11-correct-construction",
tlv11.getArray(), equalTo(new byte[]{0, 1, 2, 2, 3, 0, 1, 2}));
- LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+ TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
tlv01.allocate(15);
- tlv01.putByte((byte) 2);
+ tlv01.putByte(0, (byte) 2);
tlv01.putByteArray(2, new byte[] {
0, 1, 2 });
@@ -60,10 +64,63 @@
TlvBufferUtils.isValid(tlv11.getArray(), 1, 1),
equalTo(true));
collector.checkThat("tlv01-valid",
- LvBufferUtils.isValid(tlv01.getArray(), 1),
+ TlvBufferUtils.isValid(tlv01.getArray(), 0, 1),
equalTo(true));
}
+ /**
+ * Verify that can build a valid TLV from a List of byte[].
+ */
+ @Test
+ public void testTlvListOperations() {
+ byte[] entry1 = { 1, 2, 3 };
+ byte[] entry2 = { 4, 5 };
+ byte[] entry3 = new byte[0];
+ List<byte[]> data = new ArrayList<>();
+ data.add(entry1);
+ data.add(entry2);
+ data.add(entry3);
+ data.add(null); // zero-length should work
+
+ TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
+ tlv01.allocateAndPut(data);
+ byte[] tlvData = tlv01.getArray();
+ List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, tlvData).toList();
+
+ collector.checkThat("tlvData-correct-length", tlvData.length,
+ equalTo(entry1.length + 1 + entry2.length + 1 + entry3.length + 1 + 1));
+ collector.checkThat("parsedList-correct-length", parsedList.size(), equalTo(4));
+ collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(entry1));
+ collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(entry2));
+ collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(entry3));
+ collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0]));
+ }
+
+ /**
+ * Verify that can parse a (correctly formatted) byte array to a list.
+ */
+ @Test
+ public void testTlvParseToList() {
+ byte[] validTlv01 = { 0, 1, 55, 2, 33, 66, 0 };
+
+ List<byte[]> parsedList = new TlvBufferUtils.TlvIterable(0, 1, validTlv01).toList();
+
+ collector.checkThat("parsedList-entry1", parsedList.get(0), equalTo(new byte[0]));
+ collector.checkThat("parsedList-entry2", parsedList.get(1), equalTo(new byte[] { 55 }));
+ collector.checkThat("parsedList-entry3", parsedList.get(2), equalTo(new byte[] { 33, 66 }));
+ collector.checkThat("parsedList-entry4", parsedList.get(3), equalTo(new byte[0]));
+ }
+
+ /**
+ * Verify that an exception is thrown when trying to parse an invalid array.
+ */
+ @Test(expected = BufferOverflowException.class)
+ public void testTlvParseToListError() {
+ byte[] invalidTlv01 = { 0, 1, 55, 2, 55, 66, 3 }; // bad data
+
+ List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList();
+ }
+
@Test
public void testTlvIterate() {
final String ascii = "ABC";
@@ -137,7 +194,7 @@
TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),
equalTo(true));
collector.checkThat("tlv02-valid",
- LvBufferUtils.isValid(tlv02.getArray(), 2),
+ TlvBufferUtils.isValid(tlv02.getArray(), 0, 2),
equalTo(true));
}
@@ -211,15 +268,15 @@
*/
@Test
public void testTlvInvalidByteArray() {
- LvBufferUtils.LvConstructor tlv01 = new LvBufferUtils.LvConstructor(1);
+ TlvBufferUtils.TlvConstructor tlv01 = new TlvBufferUtils.TlvConstructor(0, 1);
tlv01.allocate(15);
- tlv01.putByte((byte) 2);
+ tlv01.putByte(0, (byte) 2);
tlv01.putByteArray(2, new byte[]{0, 1, 2});
byte[] array = tlv01.getArray();
array[0] = 10;
collector.checkThat("tlv01-invalid",
- LvBufferUtils.isValid(array, 1), equalTo(false));
+ TlvBufferUtils.isValid(array, 0, 1), equalTo(false));
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index b30ecf7..24c0127 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -49,6 +49,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
/**
* Unit test harness for WifiAwareManager class.
*/
@@ -276,7 +278,7 @@
final PublishConfig publishConfig = new PublishConfig.Builder().build();
final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
final String string1 = "hey from here...";
- final String string2 = "some other arbitrary string...";
+ final byte[] matchFilter = { 1, 12, 2, 31, 32 };
final int messageId = 2123;
final int reason = AWARE_STATUS_ERROR;
@@ -292,6 +294,8 @@
.forClass(WifiAwarePublishDiscoverySession.class);
ArgumentCaptor<WifiAwareManager.PeerHandle> peerIdCaptor = ArgumentCaptor.forClass(
WifiAwareManager.PeerHandle.class);
+ ArgumentCaptor<List<byte[]>> matchFilterCaptor = ArgumentCaptor.forClass(
+ (Class) List.class);
// (0) connect + success
mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
@@ -314,8 +318,7 @@
// (3) ...
publishSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
- sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
- string2.getBytes());
+ sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter);
sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
@@ -324,13 +327,22 @@
inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
- eq(string1.getBytes()), eq(string2.getBytes()));
- assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
- peerHandle.peerId);
+ eq(string1.getBytes()),
+ matchFilterCaptor.capture());
+
+ // note: need to capture/compare elements since the Mockito eq() is a shallow comparator
+ List<byte[]> parsedMatchFilter = new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList();
+ collector.checkThat("match-filter-size", parsedMatchFilter.size(),
+ equalTo(matchFilterCaptor.getValue().size()));
+ collector.checkThat("match-filter-entry0", parsedMatchFilter.get(0),
+ equalTo(matchFilterCaptor.getValue().get(0)));
+ collector.checkThat("match-filter-entry1", parsedMatchFilter.get(1),
+ equalTo(matchFilterCaptor.getValue().get(1)));
+
+ assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId);
inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
eq(string1.getBytes()));
- assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
- peerHandle.peerId);
+ assertEquals(peerIdCaptor.getValue().peerId, peerHandle.peerId);
inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
@@ -418,7 +430,7 @@
final SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(873);
final String string1 = "hey from here...";
- final String string2 = "some other arbitrary string...";
+ final byte[] matchFilter = { 1, 12, 3, 31, 32 }; // bad data!
final int messageId = 2123;
final int reason = AWARE_STATUS_ERROR;
@@ -456,8 +468,7 @@
// (3) ...
subscribeSession.getValue().sendMessage(peerHandle, messageId, string1.getBytes());
- sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(),
- string2.getBytes());
+ sessionProxyCallback.getValue().onMatch(peerHandle.peerId, string1.getBytes(), matchFilter);
sessionProxyCallback.getValue().onMessageReceived(peerHandle.peerId, string1.getBytes());
sessionProxyCallback.getValue().onMessageSendFail(messageId, reason);
sessionProxyCallback.getValue().onMessageSendSuccess(messageId);
@@ -466,13 +477,11 @@
inOrder.verify(mockAwareService).sendMessage(eq(clientId), eq(sessionId),
eq(peerHandle.peerId), eq(string1.getBytes()), eq(messageId), eq(0));
inOrder.verify(mockSessionCallback).onServiceDiscovered(peerIdCaptor.capture(),
- eq(string1.getBytes()), eq(string2.getBytes()));
- assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
- peerHandle.peerId);
+ eq(string1.getBytes()), (List<byte[]>) isNull());
+ assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId);
inOrder.verify(mockSessionCallback).onMessageReceived(peerIdCaptor.capture(),
eq(string1.getBytes()));
- assertEquals(((WifiAwareManager.PeerHandle) peerIdCaptor.getValue()).peerId,
- peerHandle.peerId);
+ assertEquals((peerIdCaptor.getValue()).peerId, peerHandle.peerId);
inOrder.verify(mockSessionCallback).onMessageSendFailed(eq(messageId));
inOrder.verify(mockSessionCallback).onMessageSendSucceeded(eq(messageId));
@@ -676,8 +685,7 @@
public void testSubscribeConfigBuilder() {
final String serviceName = "some_service_or_other";
final String serviceSpecificInfo = "long arbitrary string with some info";
- final byte[] matchFilter = {
- 0, 1, 16, 1, 22 };
+ final byte[] matchFilter = { 1, 16, 1, 22 };
final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
final int subscribeCount = 10;
final int subscribeTtl = 15;
@@ -685,7 +693,8 @@
final boolean enableTerminateNotification = false;
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
- .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+ .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+ new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setSubscribeType(subscribeType)
.setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -709,8 +718,7 @@
public void testSubscribeConfigParcel() {
final String serviceName = "some_service_or_other";
final String serviceSpecificInfo = "long arbitrary string with some info";
- final byte[] matchFilter = {
- 0, 1, 16, 1, 22 };
+ final byte[] matchFilter = { 1, 16, 1, 22 };
final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
final int subscribeCount = 10;
final int subscribeTtl = 15;
@@ -718,7 +726,8 @@
final boolean enableTerminateNotification = true;
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
- .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+ .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+ new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setSubscribeType(subscribeType)
.setSubscribeCount(subscribeCount).setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -780,15 +789,15 @@
public void testPublishConfigBuilder() {
final String serviceName = "some_service_or_other";
final String serviceSpecificInfo = "long arbitrary string with some info";
- final byte[] matchFilter = {
- 0, 1, 16, 1, 22 };
+ final byte[] matchFilter = { 1, 16, 1, 22 };
final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
final int publishCount = 10;
final int publishTtl = 15;
final boolean enableTerminateNotification = false;
PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
- .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+ .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+ new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setPublishType(publishType)
.setPublishCount(publishCount).setTtlSec(publishTtl)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -809,15 +818,15 @@
public void testPublishConfigParcel() {
final String serviceName = "some_service_or_other";
final String serviceSpecificInfo = "long arbitrary string with some info";
- final byte[] matchFilter = {
- 0, 1, 16, 1, 22 };
+ final byte[] matchFilter = { 1, 16, 1, 22 };
final int publishType = PublishConfig.PUBLISH_TYPE_SOLICITED;
final int publishCount = 10;
final int publishTtl = 15;
final boolean enableTerminateNotification = false;
PublishConfig publishConfig = new PublishConfig.Builder().setServiceName(serviceName)
- .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(matchFilter)
+ .setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
+ new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setPublishType(publishType)
.setPublishCount(publishCount).setTtlSec(publishTtl)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
@@ -945,7 +954,7 @@
final int clientId = 4565;
final int sessionId = 123;
final WifiAwareManager.PeerHandle peerHandle = new WifiAwareManager.PeerHandle(123412);
- final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+ final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
final String token = "Some arbitrary token string - can really be anything";
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
@@ -982,7 +991,7 @@
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
// (3) request a network specifier from the session
- String networkSpecifier = publishSession.getValue().createNetworkSpecifier(role, peerHandle,
+ String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
token.getBytes());
// validate format