Merge "WifiMetrics: Add metrics for HAL/wificond crashes"
diff --git a/Android.bp b/Android.bp
index 4ab5f1f..33f3213 100644
--- a/Android.bp
+++ b/Android.bp
@@ -28,31 +28,32 @@
proto: {
type: "full",
},
+ srcs: [
+ "core/proto/**/*.proto",
+ "libs/incident/**/*.proto",
+ ],
},
android: {
proto: {
type: "lite",
},
+ // We only build the protos that are optimized for the lite
+ // runtime, as well as the only protos that are actually
+ // needed by the device.
+ srcs: [
+ "core/proto/android/service/graphicsstats.proto",
+ ],
shared: {
- // The proto files generate full protos, but we only use
- // them as lite on device. This works fine for a static
- // library, where the unused full symbols are stripped,
- // but fails if it is linked as a standalone shared
- // library because it is missing the full runtime.
enabled: false,
},
},
},
-
- srcs: [
- "core/proto/**/*.proto",
- "libs/incident/**/*.proto",
- ],
}
subdirs = [
"core/jni",
"libs/*",
+ "media/*",
"tools/*",
"native/android",
"native/graphics/jni",
diff --git a/Android.mk b/Android.mk
index 28abb89..623b522 100644
--- a/Android.mk
+++ b/Android.mk
@@ -283,10 +283,17 @@
core/java/android/service/carrier/ICarrierService.aidl \
core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
core/java/android/service/carrier/ICarrierMessagingService.aidl \
+ core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl \
core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl \
+ core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl \
core/java/android/service/euicc/IEuiccService.aidl \
+ core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl \
core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl \
core/java/android/service/euicc/IGetEidCallback.aidl \
+ core/java/android/service/euicc/IGetEuiccInfoCallback.aidl \
+ core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl \
+ core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl \
+ core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl \
core/java/android/service/gatekeeper/IGateKeeperService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
@@ -628,7 +635,6 @@
frameworks/base/telephony/java/android/telephony/mbms/FileInfo.aidl \
frameworks/base/telephony/java/android/telephony/mbms/FileServiceInfo.aidl \
frameworks/base/telephony/java/android/telephony/mbms/ServiceInfo.aidl \
- frameworks/base/telephony/java/android/telephony/mbms/StreamingService.aidl \
frameworks/base/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \
@@ -639,6 +645,7 @@
frameworks/base/telephony/java/android/telephony/ModemActivityInfo.aidl \
frameworks/base/telephony/java/android/telephony/UiccAccessRule.aidl \
frameworks/base/telephony/java/android/telephony/euicc/DownloadableSubscription.aidl \
+ frameworks/base/telephony/java/android/telephony/euicc/EuiccInfo.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/location/java/android/location/Address.aidl \
frameworks/base/location/java/android/location/Criteria.aidl \
@@ -752,8 +759,14 @@
frameworks/base/core/java/android/view/textservice/SuggestionsInfo.aidl \
frameworks/base/core/java/android/service/carrier/CarrierIdentifier.aidl \
frameworks/base/core/java/android/service/carrier/MessagePdu.aidl \
+ frameworks/base/core/java/android/service/euicc/DeleteResult.aidl \
frameworks/base/core/java/android/service/euicc/DownloadResult.aidl \
+ frameworks/base/core/java/android/service/euicc/EraseResult.aidl \
+ frameworks/base/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl \
frameworks/base/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl \
+ frameworks/base/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl \
+ frameworks/base/core/java/android/service/euicc/SwitchResult.aidl \
+ frameworks/base/core/java/android/service/euicc/UpdateNicknameResult.aidl \
frameworks/base/core/java/android/service/notification/Adjustment.aidl \
frameworks/base/core/java/android/service/notification/Condition.aidl \
frameworks/base/core/java/android/service/notification/SnoozeCriterion.aidl \
diff --git a/apct-tests/perftests/core/res/font/samplefont.ttf b/apct-tests/perftests/core/res/font/samplefont.ttf
new file mode 100644
index 0000000..b8302d4
--- /dev/null
+++ b/apct-tests/perftests/core/res/font/samplefont.ttf
Binary files differ
diff --git a/apct-tests/perftests/core/res/font/samplefont_source.ttx b/apct-tests/perftests/core/res/font/samplefont_source.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/apct-tests/perftests/core/res/font/samplefont_source.ttx
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x0061" name="a" />
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml b/apct-tests/perftests/core/res/font/samplexmlfont.xml
similarity index 71%
rename from packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
rename to apct-tests/perftests/core/res/font/samplexmlfont.xml
index 1820bab..b226446 100644
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
+++ b/apct-tests/perftests/core/res/font/samplexmlfont.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,7 +12,8 @@
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.
+ limitations under the License
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:font="@font/samplefont" />
+</font-family>
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml b/apct-tests/perftests/core/res/layout/test_textview_font_family_file.xml
similarity index 61%
copy from packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
copy to apct-tests/perftests/core/res/layout/test_textview_font_family_file.xml
index 1820bab..3689a64 100644
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
+++ b/apct-tests/perftests/core/res/layout/test_textview_font_family_file.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,7 +11,10 @@
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.
+ limitations under the License
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:text="@string/short_text"
+ android:fontFamily="@font/samplefont" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml b/apct-tests/perftests/core/res/layout/test_textview_font_family_string.xml
similarity index 62%
copy from packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
copy to apct-tests/perftests/core/res/layout/test_textview_font_family_string.xml
index 1820bab..5f236f5 100644
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
+++ b/apct-tests/perftests/core/res/layout/test_textview_font_family_string.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,7 +11,10 @@
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.
+ limitations under the License
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:text="@string/short_text"
+ android:fontFamily="sans-serif" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml b/apct-tests/perftests/core/res/layout/test_textview_font_family_xml.xml
similarity index 61%
copy from packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
copy to apct-tests/perftests/core/res/layout/test_textview_font_family_xml.xml
index 1820bab..0331fa5 100644
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
+++ b/apct-tests/perftests/core/res/layout/test_textview_font_family_xml.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,7 +11,10 @@
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.
+ limitations under the License
-->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="100dp"
+ android:layout_height="100dp"
+ android:text="@string/short_text"
+ android:fontFamily="@font/samplexmlfont" />
diff --git a/apct-tests/perftests/core/res/values/strings.xml b/apct-tests/perftests/core/res/values/strings.xml
index 5d1f6f0..7ab325f 100644
--- a/apct-tests/perftests/core/res/values/strings.xml
+++ b/apct-tests/perftests/core/res/values/strings.xml
@@ -28,4 +28,5 @@
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>
+ <string name="short_text">text text</string>
</resources>
diff --git a/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java
new file mode 100644
index 0000000..099134f
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/SharedPreferencesTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.os;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SharedPreferencesTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void timeCachedGetSharedPreferences() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Context context = InstrumentationRegistry.getTargetContext();
+ // Do the real work once as we're only interested in cache-hit performance
+ SharedPreferences prefs = context.getSharedPreferences("test", Context.MODE_PRIVATE);
+ while (state.keepRunning()) {
+ prefs = context.getSharedPreferences("test", Context.MODE_PRIVATE);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java
new file mode 100644
index 0000000..4b6da6b
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/widget/TextViewFontFamilyLayoutPerfTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+
+import com.android.perftests.core.R;
+
+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 TextViewFontFamilyLayoutPerfTest {
+ @Parameters(name = "{0}")
+ public static Collection layouts() {
+ return Arrays.asList(new Object[][] {
+ { "String fontFamily attribute", R.layout.test_textview_font_family_string},
+ { "File fontFamily attribute", R.layout.test_textview_font_family_file},
+ { "XML fontFamily attribute", R.layout.test_textview_font_family_xml},
+ });
+ }
+
+ private int mLayoutId;
+
+ public TextViewFontFamilyLayoutPerfTest(String key, int layoutId) {
+ mLayoutId = layoutId;
+ }
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testConstruction() throws Throwable {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final LayoutInflater inflator =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ while (state.keepRunning()) {
+ inflator.inflate(mLayoutId, null, false);
+ }
+ }
+}
diff --git a/api/current.txt b/api/current.txt
index a25b334..c0f8bae 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -206,9 +206,6 @@
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed1 = 16844099; // 0x1010543
- field public static final int __removed2 = 16844104; // 0x1010548
- field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -273,7 +270,7 @@
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
field public static final int alpha = 16843551; // 0x101031f
- field public static final int alphabeticModifiers = 16844112; // 0x1010550
+ field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -293,7 +290,7 @@
field public static final int anyDensity = 16843372; // 0x101026c
field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
- field public static final int appCategory = 16844102; // 0x1010546
+ field public static final int appCategory = 16844101; // 0x1010545
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -301,7 +298,7 @@
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
- field public static final int autoSizeMaxTextSize = 16844103; // 0x1010547
+ field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
@@ -310,8 +307,8 @@
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
- field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofilledHighlight = 16844139; // 0x101056b
+ field public static final int autofillHints = 16844118; // 0x1010556
+ field public static final int autofilledHighlight = 16844136; // 0x1010568
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -361,7 +358,7 @@
field public static final int canRecord = 16844060; // 0x101051c
field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
- field public static final int canRequestFingerprintGestures = 16844111; // 0x101054f
+ field public static final int canRequestFingerprintGestures = 16844109; // 0x101054d
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
@@ -373,7 +370,7 @@
field public static final int centerMedium = 16842959; // 0x10100cf
field public static final int centerX = 16843170; // 0x10101a2
field public static final int centerY = 16843171; // 0x10101a3
- field public static final int certDigest = 16844106; // 0x101054a
+ field public static final int certDigest = 16844104; // 0x1010548
field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
field public static final int checkMark = 16843016; // 0x1010108
field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -412,12 +409,12 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
- field public static final int colorError = 16844100; // 0x1010544
+ field public static final int colorError = 16844099; // 0x1010543
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
- field public static final int colorMode = 16844108; // 0x101054c
+ field public static final int colorMode = 16844106; // 0x101054a
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -470,7 +467,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
- field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
+ field public static final int defaultFocusHighlightEnabled = 16844130; // 0x1010562
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -602,15 +599,15 @@
field public static final int flipInterval = 16843129; // 0x1010179
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
- field public static final int focusedByDefault = 16844101; // 0x1010545
+ field public static final int focusedByDefault = 16844100; // 0x1010544
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
- field public static final int fontProviderAuthority = 16844114; // 0x1010552
- field public static final int fontProviderCerts = 16844128; // 0x1010560
- field public static final int fontProviderPackage = 16844122; // 0x101055a
- field public static final int fontProviderQuery = 16844115; // 0x1010553
+ field public static final int fontProviderAuthority = 16844112; // 0x1010550
+ field public static final int fontProviderCerts = 16844125; // 0x101055d
+ field public static final int fontProviderPackage = 16844119; // 0x1010557
+ field public static final int fontProviderQuery = 16844113; // 0x1010551
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
@@ -696,9 +693,9 @@
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconSpaceReserved = 16844132; // 0x1010564
- field public static final int iconTint = 16844129; // 0x1010561
- field public static final int iconTintMode = 16844130; // 0x1010562
+ field public static final int iconSpaceReserved = 16844129; // 0x1010561
+ field public static final int iconTint = 16844126; // 0x101055e
+ field public static final int iconTintMode = 16844127; // 0x101055f
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -715,7 +712,7 @@
field public static final int imeSubtypeMode = 16843501; // 0x10102ed
field public static final int immersive = 16843456; // 0x10102c0
field public static final int importantForAccessibility = 16843690; // 0x10103aa
- field public static final int importantForAutofill = 16844123; // 0x101055b
+ field public static final int importantForAutofill = 16844120; // 0x1010558
field public static final int inAnimation = 16843127; // 0x1010177
field public static final int includeFontPadding = 16843103; // 0x101015f
field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -750,21 +747,21 @@
field public static final int isAsciiCapable = 16843753; // 0x10103e9
field public static final int isAuxiliary = 16843647; // 0x101037f
field public static final int isDefault = 16843297; // 0x1010221
- field public static final int isFeatureSplit = 16844126; // 0x101055e
+ field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
- field public static final int isStatic = 16844125; // 0x101055d
+ field public static final int isStatic = 16844122; // 0x101055a
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
- field public static final int isolatedSplits = 16844109; // 0x101054d
+ field public static final int isolatedSplits = 16844107; // 0x101054b
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
- field public static final int justificationMode = 16844138; // 0x101056a
+ field public static final int justificationMode = 16844135; // 0x1010567
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -881,7 +878,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxAspectRatio = 16844131; // 0x1010563
+ field public static final int maxAspectRatio = 16844128; // 0x1010560
field public static final int maxButtonHeight = 16844029; // 0x10104fd
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -944,7 +941,7 @@
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
- field public static final int numericModifiers = 16844113; // 0x1010551
+ field public static final int numericModifiers = 16844111; // 0x101054f
field public static final int numericShortcut = 16843236; // 0x10101e4
field public static final int offset = 16844052; // 0x1010514
field public static final int onClick = 16843375; // 0x101026f
@@ -992,7 +989,7 @@
field public static final int persistableMode = 16843821; // 0x101042d
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
- field public static final int persistentWhenFeatureAvailable = 16844134; // 0x1010566
+ field public static final int persistentWhenFeatureAvailable = 16844131; // 0x1010563
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
@@ -1018,7 +1015,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16844117; // 0x1010555
+ field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,8 +1058,8 @@
field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
field public static final int readPermission = 16842759; // 0x1010007
field public static final int recognitionService = 16843932; // 0x101049c
- field public static final int recreateOnConfigChanges = 16844105; // 0x1010549
- field public static final int recycleEnabled = 16844124; // 0x101055c
+ field public static final int recreateOnConfigChanges = 16844103; // 0x1010547
+ field public static final int recycleEnabled = 16844121; // 0x1010559
field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
field public static final int reparent = 16843964; // 0x10104bc
field public static final int reparentWithOverlay = 16843965; // 0x10104bd
@@ -1076,9 +1073,9 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
- field public static final int requiredFeature = 16844119; // 0x1010557
+ field public static final int requiredFeature = 16844116; // 0x1010554
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
- field public static final int requiredNotFeature = 16844120; // 0x1010558
+ field public static final int requiredNotFeature = 16844117; // 0x1010555
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1146,7 +1143,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16844118; // 0x1010556
+ field public static final int secondaryContentAlpha = 16844115; // 0x1010553
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1186,7 +1183,7 @@
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
- field public static final int singleLineTitle = 16844127; // 0x101055f
+ field public static final int singleLineTitle = 16844124; // 0x101055c
field public static final int singleUser = 16843711; // 0x10103bf
field public static final int slideEdge = 16843824; // 0x1010430
field public static final int smallIcon = 16843422; // 0x101029e
@@ -1200,7 +1197,7 @@
field public static final int spinnerStyle = 16842881; // 0x1010081
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
- field public static final int splitName = 16844107; // 0x101054b
+ field public static final int splitName = 16844105; // 0x1010549
field public static final int splitTrack = 16843852; // 0x101044c
field public static final int spotShadowAlpha = 16843967; // 0x10104bf
field public static final int src = 16843033; // 0x1010119
@@ -1297,7 +1294,7 @@
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetProcesses = 16844097; // 0x1010541
- field public static final int targetSandboxVersion = 16844110; // 0x101054e
+ field public static final int targetSandboxVersion = 16844108; // 0x101054c
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -1540,7 +1537,7 @@
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
- field public static final int windowSplashscreenContent = 16844135; // 0x1010567
+ field public static final int windowSplashscreenContent = 16844132; // 0x1010564
field public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
field public static final int windowTitleSize = 16842842; // 0x101005a
@@ -30528,7 +30525,7 @@
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
field public static final int N_MR1 = 25; // 0x19
- field public static final int O = 10000; // 0x2710
+ field public static final int O = 26; // 0x1a
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/api/removed.txt b/api/removed.txt
index f52b39a..9baafeb 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -254,18 +254,6 @@
field public static final int BADGING_SD = 10; // 0xa
}
- public abstract class NetworkRecommendationProvider {
- ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
- method public deprecated void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
- field public static final deprecated java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
- field public static final deprecated java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
- }
-
- public static deprecated class NetworkRecommendationProvider.ResultCallback {
- ctor public NetworkRecommendationProvider.ResultCallback(android.os.IRemoteCallback, int);
- method public void onResult(android.net.RecommendationResult);
- }
-
public abstract class PskKeyManager {
ctor public PskKeyManager();
field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
@@ -273,37 +261,6 @@
field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
- public final deprecated class RecommendationRequest implements android.os.Parcelable {
- ctor protected RecommendationRequest(android.os.Parcel);
- method public android.net.wifi.WifiConfiguration[] getConnectableConfigs();
- method public android.net.wifi.WifiConfiguration getConnectedConfig();
- method public android.net.wifi.WifiConfiguration getDefaultWifiConfig();
- method public int getLastSelectedNetworkId();
- method public long getLastSelectedNetworkTimestamp();
- method public android.net.wifi.ScanResult[] getScanResults();
- method public void setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public void setConnectedConfig(android.net.wifi.WifiConfiguration);
- field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
- }
-
- public static final deprecated class RecommendationRequest.Builder {
- ctor public RecommendationRequest.Builder();
- method public android.net.RecommendationRequest build();
- method public android.net.RecommendationRequest.Builder setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public android.net.RecommendationRequest.Builder setConnectedWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setDefaultWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setLastSelectedNetwork(int, long);
- method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
- }
-
- public final deprecated class RecommendationResult implements android.os.Parcelable {
- method public static android.net.RecommendationResult createConnectRecommendation(android.net.wifi.WifiConfiguration);
- method public static android.net.RecommendationResult createDoNotConnectRecommendation();
- method public android.net.wifi.WifiConfiguration getWifiConfiguration();
- method public boolean hasRecommendation();
- field public static final android.os.Parcelable.Creator<android.net.RecommendationResult> CREATOR;
- }
-
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index b104542..0865c96 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -327,9 +327,6 @@
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed1 = 16844099; // 0x1010543
- field public static final int __removed2 = 16844104; // 0x1010548
- field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -394,7 +391,7 @@
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
field public static final int alpha = 16843551; // 0x101031f
- field public static final int alphabeticModifiers = 16844112; // 0x1010550
+ field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -414,7 +411,7 @@
field public static final int anyDensity = 16843372; // 0x101026c
field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
- field public static final int appCategory = 16844102; // 0x1010546
+ field public static final int appCategory = 16844101; // 0x1010545
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -422,7 +419,7 @@
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
- field public static final int autoSizeMaxTextSize = 16844103; // 0x1010547
+ field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
@@ -431,8 +428,8 @@
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
- field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofilledHighlight = 16844139; // 0x101056b
+ field public static final int autofillHints = 16844118; // 0x1010556
+ field public static final int autofilledHighlight = 16844136; // 0x1010568
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -482,7 +479,7 @@
field public static final int canRecord = 16844060; // 0x101051c
field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
- field public static final int canRequestFingerprintGestures = 16844111; // 0x101054f
+ field public static final int canRequestFingerprintGestures = 16844109; // 0x101054d
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
@@ -494,7 +491,7 @@
field public static final int centerMedium = 16842959; // 0x10100cf
field public static final int centerX = 16843170; // 0x10101a2
field public static final int centerY = 16843171; // 0x10101a3
- field public static final int certDigest = 16844106; // 0x101054a
+ field public static final int certDigest = 16844104; // 0x1010548
field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
field public static final int checkMark = 16843016; // 0x1010108
field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -533,12 +530,12 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
- field public static final int colorError = 16844100; // 0x1010544
+ field public static final int colorError = 16844099; // 0x1010543
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
- field public static final int colorMode = 16844108; // 0x101054c
+ field public static final int colorMode = 16844106; // 0x101054a
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -591,7 +588,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
- field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
+ field public static final int defaultFocusHighlightEnabled = 16844130; // 0x1010562
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -723,15 +720,15 @@
field public static final int flipInterval = 16843129; // 0x1010179
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
- field public static final int focusedByDefault = 16844101; // 0x1010545
+ field public static final int focusedByDefault = 16844100; // 0x1010544
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
- field public static final int fontProviderAuthority = 16844114; // 0x1010552
- field public static final int fontProviderCerts = 16844128; // 0x1010560
- field public static final int fontProviderPackage = 16844122; // 0x101055a
- field public static final int fontProviderQuery = 16844115; // 0x1010553
+ field public static final int fontProviderAuthority = 16844112; // 0x1010550
+ field public static final int fontProviderCerts = 16844125; // 0x101055d
+ field public static final int fontProviderPackage = 16844119; // 0x1010557
+ field public static final int fontProviderQuery = 16844113; // 0x1010551
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
@@ -817,9 +814,9 @@
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconSpaceReserved = 16844132; // 0x1010564
- field public static final int iconTint = 16844129; // 0x1010561
- field public static final int iconTintMode = 16844130; // 0x1010562
+ field public static final int iconSpaceReserved = 16844129; // 0x1010561
+ field public static final int iconTint = 16844126; // 0x101055e
+ field public static final int iconTintMode = 16844127; // 0x101055f
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -836,7 +833,7 @@
field public static final int imeSubtypeMode = 16843501; // 0x10102ed
field public static final int immersive = 16843456; // 0x10102c0
field public static final int importantForAccessibility = 16843690; // 0x10103aa
- field public static final int importantForAutofill = 16844123; // 0x101055b
+ field public static final int importantForAutofill = 16844120; // 0x1010558
field public static final int inAnimation = 16843127; // 0x1010177
field public static final int includeFontPadding = 16843103; // 0x101015f
field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -871,21 +868,21 @@
field public static final int isAsciiCapable = 16843753; // 0x10103e9
field public static final int isAuxiliary = 16843647; // 0x101037f
field public static final int isDefault = 16843297; // 0x1010221
- field public static final int isFeatureSplit = 16844126; // 0x101055e
+ field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
- field public static final int isStatic = 16844125; // 0x101055d
+ field public static final int isStatic = 16844122; // 0x101055a
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
- field public static final int isolatedSplits = 16844109; // 0x101054d
+ field public static final int isolatedSplits = 16844107; // 0x101054b
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
- field public static final int justificationMode = 16844138; // 0x101056a
+ field public static final int justificationMode = 16844135; // 0x1010567
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -1002,7 +999,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxAspectRatio = 16844131; // 0x1010563
+ field public static final int maxAspectRatio = 16844128; // 0x1010560
field public static final int maxButtonHeight = 16844029; // 0x10104fd
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -1065,7 +1062,7 @@
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
- field public static final int numericModifiers = 16844113; // 0x1010551
+ field public static final int numericModifiers = 16844111; // 0x101054f
field public static final int numericShortcut = 16843236; // 0x10101e4
field public static final int offset = 16844052; // 0x1010514
field public static final int onClick = 16843375; // 0x101026f
@@ -1113,7 +1110,7 @@
field public static final int persistableMode = 16843821; // 0x101042d
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
- field public static final int persistentWhenFeatureAvailable = 16844134; // 0x1010566
+ field public static final int persistentWhenFeatureAvailable = 16844131; // 0x1010563
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
@@ -1139,7 +1136,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16844117; // 0x1010555
+ field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1182,8 +1179,8 @@
field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
field public static final int readPermission = 16842759; // 0x1010007
field public static final int recognitionService = 16843932; // 0x101049c
- field public static final int recreateOnConfigChanges = 16844105; // 0x1010549
- field public static final int recycleEnabled = 16844124; // 0x101055c
+ field public static final int recreateOnConfigChanges = 16844103; // 0x1010547
+ field public static final int recycleEnabled = 16844121; // 0x1010559
field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
field public static final int reparent = 16843964; // 0x10104bc
field public static final int reparentWithOverlay = 16843965; // 0x10104bd
@@ -1197,11 +1194,11 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
- field public static final int requiredFeature = 16844119; // 0x1010557
+ field public static final int requiredFeature = 16844116; // 0x1010554
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
- field public static final int requiredNotFeature = 16844120; // 0x1010558
- field public static final int requiredSystemPropertyName = 16844136; // 0x1010568
- field public static final int requiredSystemPropertyValue = 16844137; // 0x1010569
+ field public static final int requiredNotFeature = 16844117; // 0x1010555
+ field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
+ field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1273,7 +1270,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16844118; // 0x1010556
+ field public static final int secondaryContentAlpha = 16844115; // 0x1010553
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1313,7 +1310,7 @@
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
- field public static final int singleLineTitle = 16844127; // 0x101055f
+ field public static final int singleLineTitle = 16844124; // 0x101055c
field public static final int singleUser = 16843711; // 0x10103bf
field public static final int slideEdge = 16843824; // 0x1010430
field public static final int smallIcon = 16843422; // 0x101029e
@@ -1327,7 +1324,7 @@
field public static final int spinnerStyle = 16842881; // 0x1010081
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
- field public static final int splitName = 16844107; // 0x101054b
+ field public static final int splitName = 16844105; // 0x1010549
field public static final int splitTrack = 16843852; // 0x101044c
field public static final int spotShadowAlpha = 16843967; // 0x10104bf
field public static final int src = 16843033; // 0x1010119
@@ -1424,7 +1421,7 @@
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetProcesses = 16844097; // 0x1010541
- field public static final int targetSandboxVersion = 16844110; // 0x101054e
+ field public static final int targetSandboxVersion = 16844108; // 0x101054c
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -1667,7 +1664,7 @@
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
- field public static final int windowSplashscreenContent = 16844135; // 0x1010567
+ field public static final int windowSplashscreenContent = 16844132; // 0x1010564
field public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
field public static final int windowTitleSize = 16842842; // 0x101005a
@@ -33245,7 +33242,7 @@
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
field public static final int N_MR1 = 25; // 0x19
- field public static final int O = 10000; // 0x2710
+ field public static final int O = 26; // 0x1a
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 9f3970d..b1a29e7 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -252,18 +252,6 @@
field public static final int BADGING_SD = 10; // 0xa
}
- public abstract class NetworkRecommendationProvider {
- ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
- method public deprecated void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
- field public static final deprecated java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
- field public static final deprecated java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
- }
-
- public static deprecated class NetworkRecommendationProvider.ResultCallback {
- ctor public NetworkRecommendationProvider.ResultCallback(android.os.IRemoteCallback, int);
- method public void onResult(android.net.RecommendationResult);
- }
-
public abstract class PskKeyManager {
ctor public PskKeyManager();
field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
@@ -271,37 +259,6 @@
field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
- public final deprecated class RecommendationRequest implements android.os.Parcelable {
- ctor protected RecommendationRequest(android.os.Parcel);
- method public android.net.wifi.WifiConfiguration[] getConnectableConfigs();
- method public android.net.wifi.WifiConfiguration getConnectedConfig();
- method public android.net.wifi.WifiConfiguration getDefaultWifiConfig();
- method public int getLastSelectedNetworkId();
- method public long getLastSelectedNetworkTimestamp();
- method public android.net.wifi.ScanResult[] getScanResults();
- method public void setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public void setConnectedConfig(android.net.wifi.WifiConfiguration);
- field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
- }
-
- public static final deprecated class RecommendationRequest.Builder {
- ctor public RecommendationRequest.Builder();
- method public android.net.RecommendationRequest build();
- method public android.net.RecommendationRequest.Builder setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public android.net.RecommendationRequest.Builder setConnectedWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setDefaultWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setLastSelectedNetwork(int, long);
- method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
- }
-
- public final deprecated class RecommendationResult implements android.os.Parcelable {
- method public static android.net.RecommendationResult createConnectRecommendation(android.net.wifi.WifiConfiguration);
- method public static android.net.RecommendationResult createDoNotConnectRecommendation();
- method public android.net.wifi.WifiConfiguration getWifiConfiguration();
- method public boolean hasRecommendation();
- field public static final android.os.Parcelable.Creator<android.net.RecommendationResult> CREATOR;
- }
-
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 84fe4c5..1ad3d19 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -206,9 +206,6 @@
public static final class R.attr {
ctor public R.attr();
- field public static final int __removed1 = 16844099; // 0x1010543
- field public static final int __removed2 = 16844104; // 0x1010548
- field public static final int __removed3 = 16844116; // 0x1010554
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -273,7 +270,7 @@
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
field public static final int alpha = 16843551; // 0x101031f
- field public static final int alphabeticModifiers = 16844112; // 0x1010550
+ field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
@@ -293,7 +290,7 @@
field public static final int anyDensity = 16843372; // 0x101026c
field public static final int apduServiceBanner = 16843757; // 0x10103ed
field public static final int apiKey = 16843281; // 0x1010211
- field public static final int appCategory = 16844102; // 0x1010546
+ field public static final int appCategory = 16844101; // 0x1010545
field public static final int author = 16843444; // 0x10102b4
field public static final int authorities = 16842776; // 0x1010018
field public static final int autoAdvanceViewId = 16843535; // 0x101030f
@@ -301,7 +298,7 @@
field public static final int autoLink = 16842928; // 0x10100b0
field public static final int autoMirrored = 16843754; // 0x10103ea
field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
- field public static final int autoSizeMaxTextSize = 16844103; // 0x1010547
+ field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
field public static final int autoSizePresetSizes = 16844087; // 0x1010537
field public static final int autoSizeStepGranularity = 16844086; // 0x1010536
@@ -310,8 +307,8 @@
field public static final deprecated int autoText = 16843114; // 0x101016a
field public static final int autoUrlDetect = 16843404; // 0x101028c
field public static final int autoVerify = 16844014; // 0x10104ee
- field public static final int autofillHints = 16844121; // 0x1010559
- field public static final int autofilledHighlight = 16844139; // 0x101056b
+ field public static final int autofillHints = 16844118; // 0x1010556
+ field public static final int autofilledHighlight = 16844136; // 0x1010568
field public static final int background = 16842964; // 0x10100d4
field public static final int backgroundDimAmount = 16842802; // 0x1010032
field public static final int backgroundDimEnabled = 16843295; // 0x101021f
@@ -361,7 +358,7 @@
field public static final int canRecord = 16844060; // 0x101051c
field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
- field public static final int canRequestFingerprintGestures = 16844111; // 0x101054f
+ field public static final int canRequestFingerprintGestures = 16844109; // 0x101054d
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
@@ -373,7 +370,7 @@
field public static final int centerMedium = 16842959; // 0x10100cf
field public static final int centerX = 16843170; // 0x10101a2
field public static final int centerY = 16843171; // 0x10101a3
- field public static final int certDigest = 16844106; // 0x101054a
+ field public static final int certDigest = 16844104; // 0x1010548
field public static final int checkBoxPreferenceStyle = 16842895; // 0x101008f
field public static final int checkMark = 16843016; // 0x1010108
field public static final int checkMarkTint = 16843943; // 0x10104a7
@@ -412,12 +409,12 @@
field public static final int colorControlHighlight = 16843820; // 0x101042c
field public static final int colorControlNormal = 16843817; // 0x1010429
field public static final int colorEdgeEffect = 16843982; // 0x10104ce
- field public static final int colorError = 16844100; // 0x1010544
+ field public static final int colorError = 16844099; // 0x1010543
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
- field public static final int colorMode = 16844108; // 0x101054c
+ field public static final int colorMode = 16844106; // 0x101054a
field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
field public static final int colorPressedHighlight = 16843661; // 0x101038d
field public static final int colorPrimary = 16843827; // 0x1010433
@@ -470,7 +467,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
- field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
+ field public static final int defaultFocusHighlightEnabled = 16844130; // 0x1010562
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -602,15 +599,15 @@
field public static final int flipInterval = 16843129; // 0x1010179
field public static final int focusable = 16842970; // 0x10100da
field public static final int focusableInTouchMode = 16842971; // 0x10100db
- field public static final int focusedByDefault = 16844101; // 0x1010545
+ field public static final int focusedByDefault = 16844100; // 0x1010544
field public static final deprecated int focusedMonthDateColor = 16843587; // 0x1010343
field public static final int font = 16844082; // 0x1010532
field public static final int fontFamily = 16843692; // 0x10103ac
field public static final int fontFeatureSettings = 16843959; // 0x10104b7
- field public static final int fontProviderAuthority = 16844114; // 0x1010552
- field public static final int fontProviderCerts = 16844128; // 0x1010560
- field public static final int fontProviderPackage = 16844122; // 0x101055a
- field public static final int fontProviderQuery = 16844115; // 0x1010553
+ field public static final int fontProviderAuthority = 16844112; // 0x1010550
+ field public static final int fontProviderCerts = 16844125; // 0x101055d
+ field public static final int fontProviderPackage = 16844119; // 0x1010557
+ field public static final int fontProviderQuery = 16844113; // 0x1010551
field public static final int fontStyle = 16844095; // 0x101053f
field public static final int fontWeight = 16844083; // 0x1010533
field public static final int footerDividersEnabled = 16843311; // 0x101022f
@@ -696,9 +693,9 @@
field public static final int hyphenationFrequency = 16843998; // 0x10104de
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconSpaceReserved = 16844132; // 0x1010564
- field public static final int iconTint = 16844129; // 0x1010561
- field public static final int iconTintMode = 16844130; // 0x1010562
+ field public static final int iconSpaceReserved = 16844129; // 0x1010561
+ field public static final int iconTint = 16844126; // 0x101055e
+ field public static final int iconTintMode = 16844127; // 0x101055f
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -715,7 +712,7 @@
field public static final int imeSubtypeMode = 16843501; // 0x10102ed
field public static final int immersive = 16843456; // 0x10102c0
field public static final int importantForAccessibility = 16843690; // 0x10103aa
- field public static final int importantForAutofill = 16844123; // 0x101055b
+ field public static final int importantForAutofill = 16844120; // 0x1010558
field public static final int inAnimation = 16843127; // 0x1010177
field public static final int includeFontPadding = 16843103; // 0x101015f
field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -750,21 +747,21 @@
field public static final int isAsciiCapable = 16843753; // 0x10103e9
field public static final int isAuxiliary = 16843647; // 0x101037f
field public static final int isDefault = 16843297; // 0x1010221
- field public static final int isFeatureSplit = 16844126; // 0x101055e
+ field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
- field public static final int isStatic = 16844125; // 0x101055d
+ field public static final int isStatic = 16844122; // 0x101055a
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
- field public static final int isolatedSplits = 16844109; // 0x101054d
+ field public static final int isolatedSplits = 16844107; // 0x101054b
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
field public static final int itemTextAppearance = 16843052; // 0x101012c
- field public static final int justificationMode = 16844138; // 0x101056a
+ field public static final int justificationMode = 16844135; // 0x1010567
field public static final int keepScreenOn = 16843286; // 0x1010216
field public static final int key = 16843240; // 0x10101e8
field public static final int keyBackground = 16843315; // 0x1010233
@@ -881,7 +878,7 @@
field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
field public static final int matchOrder = 16843855; // 0x101044f
field public static final int max = 16843062; // 0x1010136
- field public static final int maxAspectRatio = 16844131; // 0x1010563
+ field public static final int maxAspectRatio = 16844128; // 0x1010560
field public static final int maxButtonHeight = 16844029; // 0x10104fd
field public static final int maxDate = 16843584; // 0x1010340
field public static final int maxEms = 16843095; // 0x1010157
@@ -944,7 +941,7 @@
field public static final int numbersSelectorColor = 16843939; // 0x10104a3
field public static final int numbersTextColor = 16843937; // 0x10104a1
field public static final deprecated int numeric = 16843109; // 0x1010165
- field public static final int numericModifiers = 16844113; // 0x1010551
+ field public static final int numericModifiers = 16844111; // 0x101054f
field public static final int numericShortcut = 16843236; // 0x10101e4
field public static final int offset = 16844052; // 0x1010514
field public static final int onClick = 16843375; // 0x101026f
@@ -992,7 +989,7 @@
field public static final int persistableMode = 16843821; // 0x101042d
field public static final int persistent = 16842765; // 0x101000d
field public static final int persistentDrawingCache = 16842990; // 0x10100ee
- field public static final int persistentWhenFeatureAvailable = 16844134; // 0x1010566
+ field public static final int persistentWhenFeatureAvailable = 16844131; // 0x1010563
field public static final deprecated int phoneNumber = 16843111; // 0x1010167
field public static final int pivotX = 16843189; // 0x10101b5
field public static final int pivotY = 16843190; // 0x10101b6
@@ -1018,7 +1015,7 @@
field public static final int preferenceStyle = 16842894; // 0x101008e
field public static final int presentationTheme = 16843712; // 0x10103c0
field public static final int previewImage = 16843482; // 0x10102da
- field public static final int primaryContentAlpha = 16844117; // 0x1010555
+ field public static final int primaryContentAlpha = 16844114; // 0x1010552
field public static final int priority = 16842780; // 0x101001c
field public static final int privateImeOptions = 16843299; // 0x1010223
field public static final int process = 16842769; // 0x1010011
@@ -1061,8 +1058,8 @@
field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
field public static final int readPermission = 16842759; // 0x1010007
field public static final int recognitionService = 16843932; // 0x101049c
- field public static final int recreateOnConfigChanges = 16844105; // 0x1010549
- field public static final int recycleEnabled = 16844124; // 0x101055c
+ field public static final int recreateOnConfigChanges = 16844103; // 0x1010547
+ field public static final int recycleEnabled = 16844121; // 0x1010559
field public static final int relinquishTaskIdentity = 16843894; // 0x1010476
field public static final int reparent = 16843964; // 0x10104bc
field public static final int reparentWithOverlay = 16843965; // 0x10104bd
@@ -1076,9 +1073,9 @@
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
- field public static final int requiredFeature = 16844119; // 0x1010557
+ field public static final int requiredFeature = 16844116; // 0x1010554
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
- field public static final int requiredNotFeature = 16844120; // 0x1010558
+ field public static final int requiredNotFeature = 16844117; // 0x1010555
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1146,7 +1143,7 @@
field public static final int searchSuggestSelection = 16843224; // 0x10101d8
field public static final int searchSuggestThreshold = 16843373; // 0x101026d
field public static final int searchViewStyle = 16843904; // 0x1010480
- field public static final int secondaryContentAlpha = 16844118; // 0x1010556
+ field public static final int secondaryContentAlpha = 16844115; // 0x1010553
field public static final int secondaryProgress = 16843064; // 0x1010138
field public static final int secondaryProgressTint = 16843879; // 0x1010467
field public static final int secondaryProgressTintMode = 16843880; // 0x1010468
@@ -1186,7 +1183,7 @@
field public static final deprecated int shownWeekCount = 16843585; // 0x1010341
field public static final int shrinkColumns = 16843082; // 0x101014a
field public static final deprecated int singleLine = 16843101; // 0x101015d
- field public static final int singleLineTitle = 16844127; // 0x101055f
+ field public static final int singleLineTitle = 16844124; // 0x101055c
field public static final int singleUser = 16843711; // 0x10103bf
field public static final int slideEdge = 16843824; // 0x1010430
field public static final int smallIcon = 16843422; // 0x101029e
@@ -1200,7 +1197,7 @@
field public static final int spinnerStyle = 16842881; // 0x1010081
field public static final int spinnersShown = 16843595; // 0x101034b
field public static final int splitMotionEvents = 16843503; // 0x10102ef
- field public static final int splitName = 16844107; // 0x101054b
+ field public static final int splitName = 16844105; // 0x1010549
field public static final int splitTrack = 16843852; // 0x101044c
field public static final int spotShadowAlpha = 16843967; // 0x10104bf
field public static final int src = 16843033; // 0x1010119
@@ -1297,7 +1294,7 @@
field public static final int targetName = 16843853; // 0x101044d
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetProcesses = 16844097; // 0x1010541
- field public static final int targetSandboxVersion = 16844110; // 0x101054e
+ field public static final int targetSandboxVersion = 16844108; // 0x101054c
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
@@ -1540,7 +1537,7 @@
field public static final int windowShowAnimation = 16842934; // 0x10100b6
field public static final int windowShowWallpaper = 16843410; // 0x1010292
field public static final int windowSoftInputMode = 16843307; // 0x101022b
- field public static final int windowSplashscreenContent = 16844135; // 0x1010567
+ field public static final int windowSplashscreenContent = 16844132; // 0x1010564
field public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
field public static final int windowTitleSize = 16842842; // 0x101005a
@@ -5989,6 +5986,7 @@
method public void destroy();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
+ method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -30637,7 +30635,7 @@
field public static final int M = 23; // 0x17
field public static final int N = 24; // 0x18
field public static final int N_MR1 = 25; // 0x19
- field public static final int O = 10000; // 0x2710
+ field public static final int O = 26; // 0x1a
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/api/test-removed.txt b/api/test-removed.txt
index f52b39a..9baafeb 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -254,18 +254,6 @@
field public static final int BADGING_SD = 10; // 0xa
}
- public abstract class NetworkRecommendationProvider {
- ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
- method public deprecated void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
- field public static final deprecated java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
- field public static final deprecated java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
- }
-
- public static deprecated class NetworkRecommendationProvider.ResultCallback {
- ctor public NetworkRecommendationProvider.ResultCallback(android.os.IRemoteCallback, int);
- method public void onResult(android.net.RecommendationResult);
- }
-
public abstract class PskKeyManager {
ctor public PskKeyManager();
field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
@@ -273,37 +261,6 @@
field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
- public final deprecated class RecommendationRequest implements android.os.Parcelable {
- ctor protected RecommendationRequest(android.os.Parcel);
- method public android.net.wifi.WifiConfiguration[] getConnectableConfigs();
- method public android.net.wifi.WifiConfiguration getConnectedConfig();
- method public android.net.wifi.WifiConfiguration getDefaultWifiConfig();
- method public int getLastSelectedNetworkId();
- method public long getLastSelectedNetworkTimestamp();
- method public android.net.wifi.ScanResult[] getScanResults();
- method public void setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public void setConnectedConfig(android.net.wifi.WifiConfiguration);
- field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
- }
-
- public static final deprecated class RecommendationRequest.Builder {
- ctor public RecommendationRequest.Builder();
- method public android.net.RecommendationRequest build();
- method public android.net.RecommendationRequest.Builder setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
- method public android.net.RecommendationRequest.Builder setConnectedWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setDefaultWifiConfig(android.net.wifi.WifiConfiguration);
- method public android.net.RecommendationRequest.Builder setLastSelectedNetwork(int, long);
- method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
- }
-
- public final deprecated class RecommendationResult implements android.os.Parcelable {
- method public static android.net.RecommendationResult createConnectRecommendation(android.net.wifi.WifiConfiguration);
- method public static android.net.RecommendationResult createDoNotConnectRecommendation();
- method public android.net.wifi.WifiConfiguration getWifiConfiguration();
- method public boolean hasRecommendation();
- field public static final android.os.Parcelable.Creator<android.net.RecommendationResult> CREATOR;
- }
-
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
diff --git a/cmds/hid/README.md b/cmds/hid/README.md
new file mode 100644
index 0000000..7e22d08
--- /dev/null
+++ b/cmds/hid/README.md
@@ -0,0 +1,145 @@
+# Usage
+## Two options to use the hid command:
+### 1. Interactive through stdin:
+type `hid -` into the terminal, then type/paste commands to send to the binary.
+Use Ctrl+D to signal end of stream to the binary (EOF).
+
+This mode can be also used from an app to send HID events.
+For an example, see the cts test case at: [InputTestCase.java][2]
+
+When using another program to control hid in interactive mode, registering a
+new input device (for example, a bluetooth joystick) should be the first step.
+After the device is added, you need to wait for the _onInputDeviceAdded_
+(see [InputDeviceListener][1]) notification before issuing commands
+to the device.
+Failure to do so will cause missed events and inconsistent behaviour.
+In the current implementation of the hid command, the hid binary will wait
+for the file descriptor to the uhid node to send the UHID_START and UHID_OPEN
+signals before returning. However, this is not sufficient. These signals
+only notify the readiness of the kernel driver,
+but do not take into account the inputflinger framework.
+
+
+### 2. Using a file as an input:
+type `hid <filename>`, and the file will be used an an input to the binary.
+You must add a sufficient delay after a "register" command to ensure device
+is ready. The interactive mode is the recommended method of communicating
+with the hid binary.
+
+All of the input commands should be in pseudo-JSON format as documented below.
+See examples [here][3].
+
+The file can have multiple commands one after the other (which is not strictly
+legal JSON format, as this would imply multiple root elements).
+
+## Command description
+
+1. `register`
+Register a new uhid device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:--------------------------|
+| id | integer | Device id |
+| command | string | Must be set to "register" |
+| name | string | Device name |
+| vid | 16-bit integer| Vendor id |
+| pid | 16-bit integer| Product id |
+| descriptor | byte array | USB HID report descriptor |
+
+Device ID is used for matching the subsequent commands to a specific device
+to avoid ambiguity when multiple devices are registered.
+
+USB HID report descriptor should be generated according the the USB HID spec
+and can be checked by reverse parsing using a variety of tools, for example
+[usbdescreqparser][5].
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "register",
+ "name": "Odie (Test)",
+ "vid": 0x18d1,
+ "pid": 0x2c40,
+ "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
+ 0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
+ 0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
+ 0x23, 0x02, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0b, 0x81, 0x02, 0x75, 0x01, 0x95,
+ 0x01, 0x81, 0x03, 0x05, 0x01, 0x75, 0x04, 0x95, 0x01, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x66,
+ 0x14, 0x00, 0x09, 0x39, 0x81, 0x42, 0x66, 0x00, 0x00, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,
+ 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x05, 0x02, 0x09, 0xc5, 0x09, 0xc4, 0x15, 0x00, 0x26,
+ 0xff, 0x00, 0x35, 0x00, 0x46, 0xff, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0x85,
+ 0x02, 0x05, 0x08, 0x0a, 0x01, 0x00, 0x0a, 0x02, 0x00, 0x0a, 0x03, 0x00, 0x0a, 0x04, 0x00,
+ 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x91, 0x02, 0x75, 0x04, 0x95, 0x01, 0x91,
+ 0x03, 0xc0, 0x05, 0x0c, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x03, 0x05, 0x01, 0x09, 0x06, 0xa1,
+ 0x02, 0x05, 0x06, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81,
+ 0x02, 0x06, 0xbc, 0xff, 0x0a, 0xad, 0xbd, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0xc0]
+}
+```
+2. `delay`
+Add a delay to command processing
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "delay" |
+| duration | integer | Delay in milliseconds |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "delay",
+ "duration": 10
+}
+```
+
+3. `report`
+Send a report to the HID device
+
+| Field | Type | Description |
+|:-------------:|:-------------:|:-------------------------- |
+| id | integer | Device id |
+| command | string | Must be set to "report" |
+| report | byte array | Report data to send |
+
+Example:
+```json
+{
+ "id": 1,
+ "command": "report",
+ "report": [0x01, 0x01, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00]
+}
+```
+
+### Sending a joystick button press event
+To send a button press event on a joystick device:
+1. Register the joystick device
+2. Send button down event with coordinates ABS_X, ABS_Y, ABS_Z, and ABS_RZ
+at the center of the range. If the coordinates are not centered, this event
+will generate a motion event within the input framework, in addition to the
+button press event. The range can be determined from the uhid report descriptor.
+3. Send the button up event with the same coordinates as in 2.
+4. Check that the button press event was received.
+
+### Notes
+1. As soon as EOF is reached (either in interactive mode, or in file mode),
+the device that was created will be unregistered. There is no
+explicit command for unregistering a device.
+2. The linux input subsystem does not generate events for those values
+that remain unchanged. For example, if there are two events sent to the driver,
+and both events have the same value of ABS_X, then ABS_X coordinate
+will not be reported.
+3. The description of joystick actions is available [here][6].
+4. Joysticks are split axes. When an analog stick is in a resting state,
+the reported coordinates are at the center of the range.
+5. The `getevent` utility can used to print out the key events
+for debugging purposes.
+
+
+[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
+[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+[3]: ../../../../cts/tests/tests/hardware/res/raw/
+[4]: https://developer.android.com/training/game-controllers/controller-input.html#button
+[5]: http://eleccelerator.com/usbdescreqparser/
+[6]: https://developer.android.com/training/game-controllers/controller-input.html
\ No newline at end of file
diff --git a/cmds/hid/jni/Android.mk b/cmds/hid/jni/Android.mk
index d41d39d..86f4e01 100644
--- a/cmds/hid/jni/Android.mk
+++ b/cmds/hid/jni/Android.mk
@@ -6,14 +6,9 @@
com_android_commands_hid_Device.cpp
LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
- frameworks/base/core/jni
+ $(JNI_H_INCLUDE)
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- liblog \
- libnativehelper \
- libutils
+LOCAL_LDLIBS += -landroid -llog -lnativehelper
LOCAL_MODULE := libhidcommand_jni
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
index 1ea33ce..107dc86 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.cpp
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -26,17 +26,17 @@
#include <memory>
#include <unistd.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <android_runtime/Log.h>
-#include <android_os_MessageQueue.h>
-#include <core_jni_helpers.h>
#include <jni.h>
#include <JNIHelp.h>
#include <ScopedPrimitiveArray.h>
#include <ScopedUtfChars.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
+#include <android/looper.h>
+#include <android/log.h>
+
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
namespace android {
namespace uhid {
@@ -56,59 +56,67 @@
static void checkAndClearException(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
- ALOGE("An exception was thrown by callback '%s'.", methodName);
- LOGE_EX(env);
+ LOGE("An exception was thrown by callback '%s'.", methodName);
env->ExceptionClear();
}
}
DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
- mCallbackObject(env->NewGlobalRef(callback)) { }
+ mCallbackObject(env->NewGlobalRef(callback)) {
+ env->GetJavaVM(&mJavaVM);
+ }
DeviceCallback::~DeviceCallback() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->DeleteGlobalRef(mCallbackObject);
}
void DeviceCallback::onDeviceError() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
checkAndClearException(env, "onDeviceError");
}
void DeviceCallback::onDeviceOpen() {
- JNIEnv* env = AndroidRuntime::getJNIEnv();
+ JNIEnv* env = getJNIEnv();
env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
checkAndClearException(env, "onDeviceOpen");
}
+JNIEnv* DeviceCallback::getJNIEnv() {
+ JNIEnv* env;
+ mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+}
+
Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
- std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) {
+ std::unique_ptr<DeviceCallback> callback) {
int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
if (fd < 0) {
- ALOGE("Failed to open uhid: %s", strerror(errno));
+ LOGE("Failed to open uhid: %s", strerror(errno));
return nullptr;
}
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
- ev.type = UHID_CREATE;
- strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH);
- ev.u.create.rd_data = descriptor.get();
- ev.u.create.rd_size = descriptorSize;
- ev.u.create.bus = BUS_BLUETOOTH;
- ev.u.create.vendor = vid;
- ev.u.create.product = pid;
- ev.u.create.version = 0;
- ev.u.create.country = 0;
+ ev.type = UHID_CREATE2;
+ strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH);
+ memcpy(&ev.u.create2.rd_data, descriptor.get(),
+ descriptorSize * sizeof(ev.u.create2.rd_data[0]));
+ ev.u.create2.rd_size = descriptorSize;
+ ev.u.create2.bus = BUS_BLUETOOTH;
+ ev.u.create2.vendor = vid;
+ ev.u.create2.product = pid;
+ ev.u.create2.version = 0;
+ ev.u.create2.country = 0;
errno = 0;
ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
if (ret < 0 || ret != sizeof(ev)) {
::close(fd);
- ALOGE("Failed to create uhid node: %s", strerror(errno));
+ LOGE("Failed to create uhid node: %s", strerror(errno));
return nullptr;
}
@@ -116,20 +124,30 @@
ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
if (ret < 0 || ev.type != UHID_START) {
::close(fd);
- ALOGE("uhid node failed to start: %s", strerror(errno));
+ LOGE("uhid node failed to start: %s", strerror(errno));
return nullptr;
}
-
- return new Device(id, fd, std::move(callback), looper);
+ return new Device(id, fd, std::move(callback));
}
-Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) :
- mId(id), mFd(fd), mDeviceCallback(std::move(callback)), mLooper(looper) {
- looper->addFd(fd, 0, Looper::EVENT_INPUT, handleLooperEvents, reinterpret_cast<void*>(this));
+Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
+ mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
+ ALooper* aLooper = ALooper_forThread();
+ if (aLooper == NULL) {
+ LOGE("Could not get ALooper, ALooper_forThread returned NULL");
+ aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
+ }
+ ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
+ reinterpret_cast<void*>(this));
}
Device::~Device() {
- mLooper->removeFd(mFd);
+ ALooper* looper = ALooper_forThread();
+ if (looper != NULL) {
+ ALooper_removeFd(looper, mFd);
+ } else {
+ LOGE("Could not remove fd, ALooper_forThread() returned NULL!");
+ }
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_DESTROY;
@@ -141,25 +159,25 @@
void Device::sendReport(uint8_t* report, size_t reportSize) {
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
- ev.type = UHID_INPUT;
- ev.u.input.size = reportSize;
- memcpy(&ev.u.input.data, report, reportSize);
+ ev.type = UHID_INPUT2;
+ ev.u.input2.size = reportSize;
+ memcpy(&ev.u.input2.data, report, reportSize);
ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
if (ret < 0 || ret != sizeof(ev)) {
- ALOGE("Failed to send hid event: %s", strerror(errno));
+ LOGE("Failed to send hid event: %s", strerror(errno));
}
}
int Device::handleEvents(int events) {
- if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
+ if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
+ LOGE("uhid node was closed or an error occurred. events=0x%x", events);
mDeviceCallback->onDeviceError();
return 0;
}
struct uhid_event ev;
ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
if (ret < 0) {
- ALOGE("Failed to read from uhid node: %s", strerror(errno));
+ LOGE("Failed to read from uhid node: %s", strerror(errno));
mDeviceCallback->onDeviceError();
return 0;
}
@@ -184,7 +202,7 @@
}
static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
- jbyteArray rawDescriptor, jobject queue, jobject callback) {
+ jbyteArray rawDescriptor, jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
@@ -194,20 +212,21 @@
std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);
std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
- sp<Looper> looper = android_os_MessageQueue_getMessageQueue(env, queue)->getLooper();
uhid::Device* d = uhid::Device::open(
id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
- std::move(desc), size, std::move(cb), std::move(looper));
+ std::move(desc), size, std::move(cb));
return reinterpret_cast<jlong>(d);
}
-static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr,jbyteArray rawReport) {
+static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
size_t size;
std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
if (d) {
d->sendReport(report.get(), size);
+ } else {
+ LOGE("Could not send report, Device* is null!");
}
}
@@ -220,7 +239,7 @@
static JNINativeMethod sMethods[] = {
{ "nativeOpenDevice",
- "(Ljava/lang/String;III[BLandroid/os/MessageQueue;"
+ "(Ljava/lang/String;III[B"
"Lcom/android/commands/hid/Device$DeviceCallback;)J",
reinterpret_cast<void*>(openDevice) },
{ "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
@@ -228,11 +247,21 @@
};
int register_com_android_commands_hid_Device(JNIEnv* env) {
- jclass clazz = FindClassOrDie(env, "com/android/commands/hid/Device$DeviceCallback");
+ jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback");
+ if (clazz == NULL) {
+ LOGE("Unable to find class 'DeviceCallback'");
+ return JNI_ERR;
+ }
uhid::gDeviceCallbackClassInfo.onDeviceOpen =
- GetMethodIDOrDie(env, clazz, "onDeviceOpen", "()V");
- uhid::gDeviceCallbackClassInfo.onDeviceError=
- GetMethodIDOrDie(env, clazz, "onDeviceError", "()V");
+ env->GetMethodID(clazz, "onDeviceOpen", "()V");
+ uhid::gDeviceCallbackClassInfo.onDeviceError =
+ env->GetMethodID(clazz, "onDeviceError", "()V");
+ if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
+ uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) {
+ LOGE("Unable to obtain onDeviceOpen or onDeviceError methods");
+ return JNI_ERR;
+ }
+
return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
sMethods, NELEM(sMethods));
}
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
index 6c5899e..149456d 100644
--- a/cmds/hid/jni/com_android_commands_hid_Device.h
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -17,8 +17,6 @@
#include <memory>
#include <jni.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
namespace android {
namespace uhid {
@@ -32,16 +30,18 @@
void onDeviceError();
private:
+ JNIEnv* getJNIEnv();
jobject mCallbackObject;
+ JavaVM* mJavaVM;
};
class Device {
public:
static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
- std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+ std::unique_ptr<DeviceCallback> callback);
- Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+ Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback);
~Device();
void sendReport(uint8_t* report, size_t reportSize);
@@ -53,7 +53,6 @@
int32_t mId;
int mFd;
std::unique_ptr<DeviceCallback> mDeviceCallback;
- sp<Looper> mLooper;
};
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
index dbe883b..8c52a8e 100644
--- a/cmds/hid/src/com/android/commands/hid/Device.java
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -29,22 +29,14 @@
public class Device {
private static final String TAG = "HidDevice";
- // Minimum amount of time to wait before sending input events to a device. Even though we're
- // guaranteed that the device has been created and opened by the input system, there's still a
- // window in which the system hasn't started reading events out of it. If a stream of events
- // begins in during this window (like a button down event) and *then* we start reading, we're
- // liable to ignore the whole stream.
- private static final int MIN_WAIT_FOR_FIRST_EVENT = 150;
-
private static final int MSG_OPEN_DEVICE = 1;
private static final int MSG_SEND_REPORT = 2;
private static final int MSG_CLOSE_DEVICE = 3;
-
private final int mId;
private final HandlerThread mThread;
private final DeviceHandler mHandler;
- private long mEventTime;
+ private long mTimeToSend;
private final Object mCond = new Object();
@@ -53,7 +45,7 @@
}
private static native long nativeOpenDevice(String name, int id, int vid, int pid,
- byte[] descriptor, MessageQueue queue, DeviceCallback callback);
+ byte[] descriptor, DeviceCallback callback);
private static native void nativeSendReport(long ptr, byte[] data);
private static native void nativeCloseDevice(long ptr);
@@ -74,22 +66,22 @@
args.arg2 = descriptor;
args.arg3 = report;
mHandler.obtainMessage(MSG_OPEN_DEVICE, args).sendToTarget();
- mEventTime = SystemClock.uptimeMillis() + MIN_WAIT_FOR_FIRST_EVENT;
+ mTimeToSend = SystemClock.uptimeMillis();
}
public void sendReport(byte[] report) {
Message msg = mHandler.obtainMessage(MSG_SEND_REPORT, report);
- mHandler.sendMessageAtTime(msg, mEventTime);
+ // if two messages are sent at identical time, they will be processed in order received
+ mHandler.sendMessageAtTime(msg, mTimeToSend);
}
public void addDelay(int delay) {
- mEventTime += delay;
+ mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
}
public void close() {
Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
- msg.setAsynchronous(true);
- mHandler.sendMessageAtTime(msg, mEventTime + 1);
+ mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1);
try {
synchronized (mCond) {
mCond.wait();
@@ -111,8 +103,7 @@
case MSG_OPEN_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
- (byte[]) args.arg2, getLooper().myQueue(), new DeviceCallback());
- nativeSendReport(mPtr, (byte[]) args.arg3);
+ (byte[]) args.arg2, new DeviceCallback());
pauseEvents();
break;
case MSG_SEND_REPORT:
@@ -155,6 +146,7 @@
}
public void onDeviceError() {
+ Log.e(TAG, "Device error occurred, closing /dev/uhid");
Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
msg.setAsynchronous(true);
msg.sendToTarget();
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
index 976a782..234e47f 100644
--- a/cmds/hid/src/com/android/commands/hid/Hid.java
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -16,7 +16,6 @@
package com.android.commands.hid;
-import android.os.SystemClock;
import android.util.JsonReader;
import android.util.JsonToken;
import android.util.Log;
@@ -91,7 +90,6 @@
}
}
-
private void process(Event e) {
final int index = mDevices.indexOfKey(e.getId());
if (index >= 0) {
@@ -101,10 +99,16 @@
} else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
d.sendReport(e.getReport());
} else {
- error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ } else {
+ error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ }
}
- } else {
+ } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
registerDevice(e);
+ } else {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
}
}
@@ -124,7 +128,6 @@
}
private static void error(String msg, Exception e) {
- System.out.println(msg);
Log.e(TAG, msg);
if (e != null) {
Log.e(TAG, Log.getStackTraceString(e));
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 3fd0f50..d8c8cb9 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1346,6 +1346,8 @@
for (int n = 0; n < nodeCount; n++) {
final Node node = mNodes.get(n);
Node nodeClone = node.clone();
+ // Remove the old internal listener from the cloned child
+ nodeClone.mAnimation.removeListener(mDummyListener);
clonesMap.put(node, nodeClone);
anim.mNodes.add(nodeClone);
anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
@@ -1651,6 +1653,8 @@
int childrenSize = parent.mChildNodes.size();
for (int i = 0; i < childrenSize; i++) {
Node child = parent.mChildNodes.get(i);
+ child.mTotalDuration = child.mAnimation.getTotalDuration(); // Update cached duration.
+
int index = visited.indexOf(child);
if (index >= 0) {
// Child has been visited, cycle found. Mark all the nodes in the cycle.
@@ -1677,9 +1681,8 @@
child.mStartTime = parent.mEndTime;
}
- long duration = child.mAnimation.getTotalDuration();
- child.mEndTime = duration == DURATION_INFINITE ?
- DURATION_INFINITE : child.mStartTime + duration;
+ child.mEndTime = child.mTotalDuration == DURATION_INFINITE
+ ? DURATION_INFINITE : child.mStartTime + child.mTotalDuration;
}
}
updatePlayTime(child, visited);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a8183f2..ab03556 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2092,7 +2092,6 @@
if (params == null) {
throw new IllegalArgumentException("Expected non-null picture-in-picture params");
}
- updatePictureInPictureParamsForContentInsets(params);
return ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken, params);
} catch (RemoteException e) {
return false;
@@ -2116,7 +2115,6 @@
if (params == null) {
throw new IllegalArgumentException("Expected non-null picture-in-picture params");
}
- updatePictureInPictureParamsForContentInsets(params);
ActivityManagerNative.getDefault().setPictureInPictureParams(mToken, params);
} catch (RemoteException e) {
}
@@ -2136,21 +2134,6 @@
}
}
- /**
- * Updates the provided {@param params} with the last known content insets for this activity, to
- * be used with the source hint rect for the transition into PiP.
- */
- private void updatePictureInPictureParamsForContentInsets(PictureInPictureParams params) {
- if (params != null && params.hasSourceBoundsHint() && getWindow() != null &&
- getWindow().peekDecorView() != null &&
- getWindow().peekDecorView().getViewRootImpl() != null) {
- params.setSourceRectHintInsets(
- getWindow().peekDecorView().getViewRootImpl().getLastContentInsets());
- } else {
- params.setSourceRectHintInsets(null);
- }
- }
-
void dispatchMovedToDisplay(int displayId, Configuration config) {
updateDisplay(displayId);
onMovedToDisplay(displayId, config);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4c3e1b0..3b9480f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -126,6 +126,14 @@
private static volatile boolean sSystemReady = false;
+
+ private static final int FIRST_START_FATAL_ERROR_CODE = -100;
+ private static final int LAST_START_FATAL_ERROR_CODE = -1;
+ private static final int FIRST_START_SUCCESS_CODE = 0;
+ private static final int LAST_START_SUCCESS_CODE = 99;
+ private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100;
+ private static final int LAST_START_NON_FATAL_ERROR_CODE = 199;
+
/**
* System property to enable task snapshots.
* @hide
@@ -219,53 +227,56 @@
*/
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
+ // NOTE: Before adding a new start result, please reference the defined ranges to ensure the
+ // result is properly categorized.
+
/**
* Result for IActivityManager.startVoiceActivity: active session is currently hidden.
* @hide
*/
- public static final int START_VOICE_HIDDEN_SESSION = -10;
+ public static final int START_VOICE_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE;
/**
* Result for IActivityManager.startVoiceActivity: active session does not match
* the requesting token.
* @hide
*/
- public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+ public static final int START_VOICE_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 1;
/**
* Result for IActivityManager.startActivity: trying to start a background user
* activity that shouldn't be displayed for all users.
* @hide
*/
- public static final int START_NOT_CURRENT_USER_ACTIVITY = -8;
+ public static final int START_NOT_CURRENT_USER_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 2;
/**
* Result for IActivityManager.startActivity: trying to start an activity under voice
* control when that activity does not support the VOICE category.
* @hide
*/
- public static final int START_NOT_VOICE_COMPATIBLE = -7;
+ public static final int START_NOT_VOICE_COMPATIBLE = FIRST_START_FATAL_ERROR_CODE + 3;
/**
* Result for IActivityManager.startActivity: an error where the
* start had to be canceled.
* @hide
*/
- public static final int START_CANCELED = -6;
+ public static final int START_CANCELED = FIRST_START_FATAL_ERROR_CODE + 4;
/**
* Result for IActivityManager.startActivity: an error where the
* thing being started is not an activity.
* @hide
*/
- public static final int START_NOT_ACTIVITY = -5;
+ public static final int START_NOT_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 5;
/**
* Result for IActivityManager.startActivity: an error where the
* caller does not have permission to start the activity.
* @hide
*/
- public static final int START_PERMISSION_DENIED = -4;
+ public static final int START_PERMISSION_DENIED = FIRST_START_FATAL_ERROR_CODE + 6;
/**
* Result for IActivityManager.startActivity: an error where the
@@ -273,49 +284,49 @@
* a result.
* @hide
*/
- public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3;
+ public static final int START_FORWARD_AND_REQUEST_CONFLICT = FIRST_START_FATAL_ERROR_CODE + 7;
/**
* Result for IActivityManager.startActivity: an error where the
* requested class is not found.
* @hide
*/
- public static final int START_CLASS_NOT_FOUND = -2;
+ public static final int START_CLASS_NOT_FOUND = FIRST_START_FATAL_ERROR_CODE + 8;
/**
* Result for IActivityManager.startActivity: an error where the
* given Intent could not be resolved to an activity.
* @hide
*/
- public static final int START_INTENT_NOT_RESOLVED = -1;
+ public static final int START_INTENT_NOT_RESOLVED = FIRST_START_FATAL_ERROR_CODE + 9;
/**
* Result for IActivityManaqer.startActivity: the activity was started
* successfully as normal.
* @hide
*/
- public static final int START_SUCCESS = 0;
+ public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE;
/**
* Result for IActivityManaqer.startActivity: the caller asked that the Intent not
* be executed if it is the recipient, and that is indeed the case.
* @hide
*/
- public static final int START_RETURN_INTENT_TO_CALLER = 1;
+ public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1;
/**
* Result for IActivityManaqer.startActivity: activity wasn't really started, but
* a task was simply brought to the foreground.
* @hide
*/
- public static final int START_TASK_TO_FRONT = 2;
+ public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2;
/**
* Result for IActivityManaqer.startActivity: activity wasn't really started, but
* the given Intent was given to the existing top activity.
* @hide
*/
- public static final int START_DELIVERED_TO_TOP = 3;
+ public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3;
/**
* Result for IActivityManaqer.startActivity: request was canceled because
@@ -323,14 +334,15 @@
* (such as pressing home) is performed.
* @hide
*/
- public static final int START_SWITCHES_CANCELED = 4;
+ public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE;
/**
* Result for IActivityManaqer.startActivity: a new activity was attempted to be started
* while in Lock Task Mode.
* @hide
*/
- public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = 5;
+ public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION =
+ FIRST_START_NON_FATAL_ERROR_CODE + 1;
/**
* Flag for IActivityManaqer.startActivity: do special start mode where
@@ -566,6 +578,22 @@
}
/**
+ * Returns whether the launch was successful.
+ * @hide
+ */
+ public static final boolean isStartResultSuccessful(int result) {
+ return FIRST_START_SUCCESS_CODE <= result && result <= LAST_START_SUCCESS_CODE;
+ }
+
+ /**
+ * Returns whether the launch result was a fatal error.
+ * @hide
+ */
+ public static final boolean isStartResultFatalError(int result) {
+ return FIRST_START_FATAL_ERROR_CODE <= result && result <= LAST_START_FATAL_ERROR_CODE;
+ }
+
+ /**
* Screen compatibility mode: the application most always run in
* compatibility mode.
* @hide
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 3eec596..53608fb 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -38,6 +38,7 @@
import android.util.Pair;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -213,6 +214,7 @@
private static final String KEY_INSTANT_APP_VERIFICATION_BUNDLE
= "android:instantapps.installerbundle";
+ private static final String KEY_SPECS_FUTURE = "android:activity.specsFuture";
/** @hide */
public static final int ANIM_NONE = 0;
@@ -268,6 +270,7 @@
private AppTransitionAnimationSpec mAnimSpecs[];
private int mRotationAnimationHint = -1;
private Bundle mAppVerificationBundle;
+ private IAppTransitionAnimationSpecsFuture mSpecsFuture;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -492,35 +495,12 @@
* is not executed, the callback will happen immediately.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
- * @hide
*/
- public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
+ private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
}
- /**
- * Create an ActivityOptions specifying an animation where an activity window
- * is scaled from a given position to a thumbnail at a specified location.
- *
- * @param source The View that this thumbnail is animating to. This
- * defines the coordinate space for <var>startX</var> and <var>startY</var>.
- * @param thumbnail The bitmap that will be shown as the final thumbnail
- * of the animation.
- * @param startX The x end location of the bitmap, relative to <var>source</var>.
- * @param startY The y end location of the bitmap, relative to <var>source</var>.
- * @param listener Optional OnAnimationStartedListener to find out when the
- * requested animation has started running. If for some reason the animation
- * is not executed, the callback will happen immediately.
- * @return Returns a new ActivityOptions object that you can use to
- * supply these options as the options Bundle when starting an activity.
- * @hide
- */
- public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
- Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
- return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
- }
-
private static ActivityOptions makeThumbnailAnimation(View source,
Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
boolean scaleUp) {
@@ -537,29 +517,21 @@
}
/**
- * Create an ActivityOptions specifying an animation where the new activity
- * window and a thumbnail is aspect-scaled to a new location.
- *
- * @param source The View that this thumbnail is animating from. This
- * defines the coordinate space for <var>startX</var> and <var>startY</var>.
- * @param thumbnail The bitmap that will be shown as the initial thumbnail
- * of the animation.
- * @param startX The x starting location of the bitmap, relative to <var>source</var>.
- * @param startY The y starting location of the bitmap, relative to <var>source</var>.
- * @param handler If <var>listener</var> is non-null this must be a valid
- * Handler on which to dispatch the callback; otherwise it should be null.
- * @param listener Optional OnAnimationStartedListener to find out when the
- * requested animation has started running. If for some reason the animation
- * is not executed, the callback will happen immediately.
- * @return Returns a new ActivityOptions object that you can use to
- * supply these options as the options Bundle when starting an activity.
+ * Create an ActivityOptions specifying an animation where a list of activity windows and
+ * thumbnails are aspect scaled to/from a new location.
* @hide
*/
- public static ActivityOptions makeThumbnailAspectScaleUpAnimation(View source,
- Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
- Handler handler, OnAnimationStartedListener listener) {
- return makeAspectScaledThumbnailAnimation(source, thumbnail, startX, startY,
- targetWidth, targetHeight, handler, listener, true);
+ public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context,
+ Handler handler, IAppTransitionAnimationSpecsFuture specsFuture,
+ OnAnimationStartedListener listener, boolean scaleUp) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mPackageName = context.getPackageName();
+ opts.mAnimationType = scaleUp
+ ? ANIM_THUMBNAIL_ASPECT_SCALE_UP
+ : ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
+ opts.mSpecsFuture = specsFuture;
+ opts.setOnAnimationStartedListener(handler, listener);
+ return opts;
}
/**
@@ -891,6 +863,10 @@
}
mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT);
mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE);
+ if (opts.containsKey(KEY_SPECS_FUTURE)) {
+ mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder(
+ KEY_SPECS_FUTURE));
+ }
}
/**
@@ -1029,6 +1005,11 @@
public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
/** @hide */
+ public IAppTransitionAnimationSpecsFuture getSpecsFuture() {
+ return mSpecsFuture;
+ }
+
+ /** @hide */
public static ActivityOptions fromBundle(Bundle bOptions) {
return bOptions != null ? new ActivityOptions(bOptions) : null;
}
@@ -1205,6 +1186,7 @@
}
mAnimSpecs = otherOptions.mAnimSpecs;
mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
+ mSpecsFuture = otherOptions.mSpecsFuture;
}
/**
@@ -1279,6 +1261,9 @@
if (mAnimationFinishedListener != null) {
b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
}
+ if (mSpecsFuture != null) {
+ b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder());
+ }
b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint);
if (mAppVerificationBundle != null) {
b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 928ef7e..ed706fc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5477,15 +5477,6 @@
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
- if (data.persistent) {
- // Persistent processes on low-memory devices do not get to
- // use hardware accelerated drawing, since this can add too much
- // overhead to the process.
- if (!ActivityManager.isHighEndGfx()) {
- ThreadedRenderer.disable(false);
- }
- }
-
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5bb54c2..9c90b5b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -482,7 +482,7 @@
public @NonNull List<SharedLibraryInfo> getSharedLibrariesAsUser(int flags, int userId) {
try {
ParceledListSlice<SharedLibraryInfo> sharedLibs = mPM.getSharedLibraries(
- flags, userId);
+ mContext.getOpPackageName(), flags, userId);
if (sharedLibs == null) {
return Collections.emptyList();
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1dcc3e2..8d33c96 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -63,7 +63,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.system.ErrnoException;
@@ -373,21 +372,21 @@
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
- checkMode(mode);
- if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
- if (isCredentialProtectedStorage()
- && !getSystemService(StorageManager.class).isUserKeyUnlocked(
- UserHandle.myUserId())
- && !isBuggy()) {
- throw new IllegalStateException("SharedPreferences in credential encrypted "
- + "storage are not available until after user is unlocked");
- }
- }
SharedPreferencesImpl sp;
synchronized (ContextImpl.class) {
final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
sp = cache.get(file);
if (sp == null) {
+ checkMode(mode);
+ if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) {
+ if (isCredentialProtectedStorage()
+ && !getSystemService(StorageManager.class).isUserKeyUnlocked(
+ UserHandle.myUserId())
+ && !isBuggy()) {
+ throw new IllegalStateException("SharedPreferences in credential encrypted "
+ + "storage are not available until after user is unlocked");
+ }
+ }
sp = new SharedPreferencesImpl(file, mode);
cache.put(file, sp);
return sp;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 1b2543c..95d55dc 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2303,11 +2303,15 @@
*/
private void completeExecute(BackStackRecord record, boolean isPop, boolean runTransitions,
boolean moveToState) {
+ if (isPop) {
+ record.executePopOps(moveToState);
+ } else {
+ record.executeOps();
+ }
ArrayList<BackStackRecord> records = new ArrayList<>(1);
ArrayList<Boolean> isRecordPop = new ArrayList<>(1);
records.add(record);
isRecordPop.add(isPop);
- executeOps(records, isRecordPop, 0, 1);
if (runTransitions) {
FragmentTransition.startTransitions(this, records, isRecordPop, 0, 1, true);
}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 4994fbb..b5b1017 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -30,7 +30,7 @@
void onTaskStackChanged();
/** Called whenever an Activity is moved to the pinned stack from another stack. */
- void onActivityPinned(String packageName);
+ void onActivityPinned(String packageName, int taskId);
/** Called whenever an Activity is moved from the pinned stack to another stack. */
void onActivityUnpinned();
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 7640e75..b26117d 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -42,7 +42,8 @@
WindowContentFrameStats getWindowContentFrameStats(int windowId);
void clearWindowAnimationFrameStats();
WindowAnimationFrameStats getWindowAnimationFrameStats();
- void executeShellCommand(String command, in ParcelFileDescriptor fd);
+ void executeShellCommand(String command, in ParcelFileDescriptor sink,
+ in ParcelFileDescriptor source);
void grantRuntimePermission(String packageName, String permission, int userId);
void revokeRuntimePermission(String packageName, String permission, int userId);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 5b2cf81f..84efcee 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1921,7 +1921,7 @@
/** @hide */
public static void checkStartActivityResult(int res, Object intent) {
- if (res >= ActivityManager.START_SUCCESS) {
+ if (!ActivityManager.isStartResultFatalError(res)) {
return;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccbd5b4..3ed174b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,8 @@
package android.app;
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
@@ -42,7 +44,6 @@
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.BadParcelableException;
-import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -72,6 +73,7 @@
import android.widget.RemoteViews;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.NotificationColorUtil;
import com.android.internal.util.Preconditions;
@@ -1110,6 +1112,16 @@
@SystemApi
public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+ /**
+ * This is set on the notification shown by the activity manager about all apps
+ * running in the background. It indicates that the notification should be shown
+ * only if any of the given apps do not already have a {@link #FLAG_FOREGROUND_SERVICE}
+ * notification currently visible to the user. This is a string array of all
+ * package names of the apps.
+ * @hide
+ */
+ public static final String EXTRA_FOREGROUND_APPS = "android.foregroundApps";
+
private Icon mSmallIcon;
private Icon mLargeIcon;
@@ -2670,6 +2682,19 @@
private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY =
SystemProperties.getBoolean("notifications.only_title", true);
+ /**
+ * The lightness difference that has to be added to the primary text color to obtain the
+ * secondary text color when the background is light.
+ */
+ private static final int LIGHTNESS_TEXT_DIFFERENCE_LIGHT = 20;
+
+ /**
+ * The lightness difference that has to be added to the primary text color to obtain the
+ * secondary text color when the background is dark.
+ * A bit less then the above value, since it looks better on dark backgrounds.
+ */
+ private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10;
+
private Context mContext;
private Notification mN;
private Bundle mUserExtras = new Bundle();
@@ -3836,11 +3861,26 @@
contentView.setTextColor(id, mPrimaryTextColor);
}
- private int getPrimaryTextColor() {
+ /**
+ * @return the primary text color
+ * @hide
+ */
+ @VisibleForTesting
+ public int getPrimaryTextColor() {
ensureColors();
return mPrimaryTextColor;
}
+ /**
+ * @return the secondary text color
+ * @hide
+ */
+ @VisibleForTesting
+ public int getSecondaryTextColor() {
+ ensureColors();
+ return mSecondaryTextColor;
+ }
+
private int getActionBarColor() {
ensureColors();
return mActionBarColor;
@@ -3880,16 +3920,21 @@
double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
double contrast = NotificationColorUtil.calculateContrast(mForegroundColor,
backgroundColor);
- boolean textDark = backLum > textLum;
+ // We only respect the given colors if worst case Black or White still has
+ // contrast
+ boolean backgroundLight = backLum > textLum
+ && satisfiesTextContrast(backgroundColor, Color.BLACK)
+ || backLum <= textLum
+ && !satisfiesTextContrast(backgroundColor, Color.WHITE);
if (contrast < 4.5f) {
- if (textDark) {
+ if (backgroundLight) {
mSecondaryTextColor = NotificationColorUtil.findContrastColor(
mForegroundColor,
backgroundColor,
true /* findFG */,
4.5f);
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, -20);
+ mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_LIGHT);
} else {
mSecondaryTextColor =
NotificationColorUtil.findContrastColorAgainstDark(
@@ -3898,16 +3943,17 @@
true /* findFG */,
4.5f);
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, 10);
+ mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_DARK);
}
} else {
mPrimaryTextColor = mForegroundColor;
mSecondaryTextColor = NotificationColorUtil.changeColorLightness(
- mPrimaryTextColor, textDark ? 10 : -20);
+ mPrimaryTextColor, backgroundLight ? LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+ : LIGHTNESS_TEXT_DIFFERENCE_DARK);
if (NotificationColorUtil.calculateContrast(mSecondaryTextColor,
backgroundColor) < 4.5f) {
// oh well the secondary is not good enough
- if (textDark) {
+ if (backgroundLight) {
mSecondaryTextColor = NotificationColorUtil.findContrastColor(
mSecondaryTextColor,
backgroundColor,
@@ -3922,7 +3968,9 @@
4.5f);
}
mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
- mSecondaryTextColor, textDark ? -20 : 10);
+ mSecondaryTextColor, backgroundLight
+ ? -LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+ : -LIGHTNESS_TEXT_DIFFERENCE_DARK);
}
}
}
diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java
index d7317f4..cbe8bb9 100644
--- a/core/java/android/app/PictureInPictureArgs.java
+++ b/core/java/android/app/PictureInPictureArgs.java
@@ -160,9 +160,6 @@
if (in.readInt() != 0) {
mSourceRectHint = Rect.CREATOR.createFromParcel(in);
}
- if (in.readInt() != 0) {
- mSourceRectHintInsets = Rect.CREATOR.createFromParcel(in);
- }
}
private PictureInPictureArgs(Rational aspectRatio, List<RemoteAction> actions,
@@ -220,9 +217,6 @@
if (otherArgs.hasSourceBoundsHint()) {
mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
}
- if (otherArgs.hasSourceBoundsHintInsets()) {
- mSourceRectHintInsets = new Rect(otherArgs.getSourceRectHintInsets());
- }
}
/**
@@ -346,12 +340,6 @@
} else {
out.writeInt(0);
}
- if (mSourceRectHintInsets != null) {
- out.writeInt(1);
- mSourceRectHintInsets.writeToParcel(out, 0);
- } else {
- out.writeInt(0);
- }
}
public static final Creator<PictureInPictureArgs> CREATOR =
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 323a0fb..7313b0d 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -135,13 +135,6 @@
@Nullable
private Rect mSourceRectHint;
- /**
- * The content insets that are used with the source hint rect for the transition into PiP where
- * the insets are removed at the beginning of the transition.
- */
- @Nullable
- private Rect mSourceRectHintInsets;
-
/** {@hide} */
PictureInPictureParams() {
}
@@ -158,9 +151,6 @@
if (in.readInt() != 0) {
mSourceRectHint = Rect.CREATOR.createFromParcel(in);
}
- if (in.readInt() != 0) {
- mSourceRectHintInsets = Rect.CREATOR.createFromParcel(in);
- }
}
/** {@hide} */
@@ -185,9 +175,6 @@
if (otherArgs.hasSourceBoundsHint()) {
mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
}
- if (otherArgs.hasSourceBoundsHintInsets()) {
- mSourceRectHintInsets = new Rect(otherArgs.getSourceRectHintInsets());
- }
}
/**
@@ -241,19 +228,6 @@
}
/**
- * Sets the insets to be used with the source rect hint bounds.
- * @hide
- */
- @Deprecated
- public void setSourceRectHintInsets(Rect insets) {
- if (insets == null) {
- mSourceRectHintInsets = null;
- } else {
- mSourceRectHintInsets = new Rect(insets);
- }
- }
-
- /**
* @return the source rect hint
* @hide
*/
@@ -262,14 +236,6 @@
}
/**
- * @return the source rect hint insets.
- * @hide
- */
- public Rect getSourceRectHintInsets() {
- return mSourceRectHintInsets;
- }
-
- /**
* @return whether there are launch bounds set
* @hide
*/
@@ -277,14 +243,6 @@
return mSourceRectHint != null && !mSourceRectHint.isEmpty();
}
- /**
- * @return whether there are source rect hint insets set
- * @hide
- */
- public boolean hasSourceBoundsHintInsets() {
- return mSourceRectHintInsets != null;
- }
-
@Override
public int describeContents() {
return 0;
@@ -311,12 +269,6 @@
} else {
out.writeInt(0);
}
- if (mSourceRectHintInsets != null) {
- out.writeInt(1);
- mSourceRectHintInsets.writeToParcel(out, 0);
- } else {
- out.writeInt(0);
- }
}
public static final Creator<PictureInPictureParams> CREATOR =
@@ -328,4 +280,4 @@
return new PictureInPictureParams[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index e57a9b5..ab301bd 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -92,6 +92,7 @@
public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+ public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
private Context mContext;
private IStatusBarService mService;
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 2df011f..a52ca0a 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -31,7 +31,7 @@
}
@Override
- public void onActivityPinned(String packageName) throws RemoteException {
+ public void onActivityPinned(String packageName, int taskId) throws RemoteException {
}
@Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 18e7599..c99de5d 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -975,11 +975,11 @@
}
/**
- * Executes a shell command. This method returs a file descriptor that points
+ * Executes a shell command. This method returns a file descriptor that points
* to the standard output stream. The command execution is similar to running
* "adb shell <command>" from a host connected to the device.
* <p>
- * <strong>Note:</strong> It is your responsibility to close the retunred file
+ * <strong>Note:</strong> It is your responsibility to close the returned file
* descriptor once you are done reading.
* </p>
*
@@ -1000,7 +1000,7 @@
sink = pipe[1];
// Calling out without a lock held.
- mUiAutomationConnection.executeShellCommand(command, sink);
+ mUiAutomationConnection.executeShellCommand(command, sink, null);
} catch (IOException ioe) {
Log.e(LOG_TAG, "Error executing shell command!", ioe);
} catch (RemoteException re) {
@@ -1012,6 +1012,59 @@
return source;
}
+ /**
+ * Executes a shell command. This method returns two file descriptors,
+ * one that points to the standard output stream (element at index 0), and one that points
+ * to the standard input stream (element at index 1). The command execution is similar
+ * to running "adb shell <command>" from a host connected to the device.
+ * <p>
+ * <strong>Note:</strong> It is your responsibility to close the returned file
+ * descriptors once you are done reading/writing.
+ * </p>
+ *
+ * @param command The command to execute.
+ * @return File descriptors (out, in) to the standard output/input streams.
+ *
+ * @hide
+ */
+ @TestApi
+ public ParcelFileDescriptor[] executeShellCommandRw(String command) {
+ synchronized (mLock) {
+ throwIfNotConnectedLocked();
+ }
+
+ ParcelFileDescriptor source_read = null;
+ ParcelFileDescriptor sink_read = null;
+
+ ParcelFileDescriptor source_write = null;
+ ParcelFileDescriptor sink_write = null;
+
+ try {
+ ParcelFileDescriptor[] pipe_read = ParcelFileDescriptor.createPipe();
+ source_read = pipe_read[0];
+ sink_read = pipe_read[1];
+
+ ParcelFileDescriptor[] pipe_write = ParcelFileDescriptor.createPipe();
+ source_write = pipe_write[0];
+ sink_write = pipe_write[1];
+
+ // Calling out without a lock held.
+ mUiAutomationConnection.executeShellCommand(command, sink_read, source_write);
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Error executing shell command!", ioe);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error executing shell command!", re);
+ } finally {
+ IoUtils.closeQuietly(sink_read);
+ IoUtils.closeQuietly(source_write);
+ }
+
+ ParcelFileDescriptor[] result = new ParcelFileDescriptor[2];
+ result[0] = source_read;
+ result[1] = sink_write;
+ return result;
+ }
+
private static float getDegreesForRotation(int value) {
switch (value) {
case Surface.ROTATION_90: {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 9960df6..5e414b8 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -36,9 +36,11 @@
import android.view.WindowContentFrameStats;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.IAccessibilityManager;
+import android.util.Log;
import libcore.io.IoUtils;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -55,6 +57,8 @@
*/
public final class UiAutomationConnection extends IUiAutomationConnection.Stub {
+ private static final String TAG = "UiAutomationConnection";
+
private static final int INITIAL_FROZEN_ROTATION_UNSPECIFIED = -1;
private final IWindowManager mWindowManager = IWindowManager.Stub.asInterface(
@@ -267,47 +271,95 @@
}
}
+ public class Repeater implements Runnable {
+ // Continuously read readFrom and write back to writeTo until EOF is encountered
+ private final InputStream readFrom;
+ private final OutputStream writeTo;
+ public Repeater (InputStream readFrom, OutputStream writeTo) {
+ this.readFrom = readFrom;
+ this.writeTo = writeTo;
+ }
+ @Override
+ public void run() {
+ try {
+ final byte[] buffer = new byte[8192];
+ int readByteCount;
+ while (true) {
+ readByteCount = readFrom.read(buffer);
+ if (readByteCount < 0) {
+ break;
+ }
+ writeTo.write(buffer, 0, readByteCount);
+ writeTo.flush();
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException("Error while reading/writing ", ioe);
+ } finally {
+ IoUtils.closeQuietly(readFrom);
+ IoUtils.closeQuietly(writeTo);
+ }
+ }
+ }
+
@Override
- public void executeShellCommand(final String command, final ParcelFileDescriptor sink)
- throws RemoteException {
+ public void executeShellCommand(final String command, final ParcelFileDescriptor sink,
+ final ParcelFileDescriptor source) throws RemoteException {
synchronized (mLock) {
throwIfCalledByNotTrustedUidLocked();
throwIfShutdownLocked();
throwIfNotConnectedLocked();
}
+ final java.lang.Process process;
- Thread streamReader = new Thread() {
+ try {
+ process = Runtime.getRuntime().exec(command);
+ } catch (IOException exc) {
+ throw new RuntimeException("Error running shell command '" + command + "'", exc);
+ }
+
+ // Read from process and write to pipe
+ final Thread readFromProcess;
+ if (sink != null) {
+ InputStream sink_in = process.getInputStream();;
+ OutputStream sink_out = new FileOutputStream(sink.getFileDescriptor());
+
+ readFromProcess = new Thread(new Repeater(sink_in, sink_out));
+ readFromProcess.start();
+ } else {
+ readFromProcess = null;
+ }
+
+ // Read from pipe and write to process
+ final Thread writeToProcess;
+ if (source != null) {
+ OutputStream source_out = process.getOutputStream();
+ InputStream source_in = new FileInputStream(source.getFileDescriptor());
+
+ writeToProcess = new Thread(new Repeater(source_in, source_out));
+ writeToProcess.start();
+ } else {
+ writeToProcess = null;
+ }
+
+ Thread cleanup = new Thread(new Runnable() {
+ @Override
public void run() {
- InputStream in = null;
- OutputStream out = null;
- java.lang.Process process = null;
-
try {
- process = Runtime.getRuntime().exec(command);
-
- in = process.getInputStream();
- out = new FileOutputStream(sink.getFileDescriptor());
-
- final byte[] buffer = new byte[8192];
- while (true) {
- final int readByteCount = in.read(buffer);
- if (readByteCount < 0) {
- break;
- }
- out.write(buffer, 0, readByteCount);
+ if (writeToProcess != null) {
+ writeToProcess.join();
}
- } catch (IOException ioe) {
- throw new RuntimeException("Error running shell command", ioe);
- } finally {
- if (process != null) {
- process.destroy();
+ if (readFromProcess != null) {
+ readFromProcess.join();
}
- IoUtils.closeQuietly(out);
- IoUtils.closeQuietly(sink);
+ } catch (InterruptedException exc) {
+ Log.e(TAG, "At least one of the threads was interrupted");
}
- };
- };
- streamReader.start();
+ IoUtils.closeQuietly(sink);
+ IoUtils.closeQuietly(source);
+ process.destroy();
+ }
+ });
+ cleanup.start();
}
@Override
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index eae9e1e..c613d97 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -862,10 +862,10 @@
out.writeInt(mAutofillType);
out.writeStringArray(mAutofillHints);
final AutofillValue sanitizedValue;
- if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
- sanitizedValue = mAutofillOverlay.value;
- } else if (writeSensitive) {
+ if (writeSensitive) {
sanitizedValue = mAutofillValue;
+ } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+ sanitizedValue = mAutofillOverlay.value;
} else {
sanitizedValue = null;
}
@@ -1936,7 +1936,7 @@
}
/** @hide */
- public void dump() {
+ public void dump(boolean showSensitive) {
if (mActivityComponent == null) {
Log.i(TAG, "dump(): calling ensureData() first");
ensureData();
@@ -1949,11 +1949,11 @@
WindowNode node = getWindowNodeAt(i);
Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
+ " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
- dump(" ", node.getRootViewNode());
+ dump(" ", node.getRootViewNode(), showSensitive);
}
}
- void dump(String prefix, ViewNode node) {
+ void dump(String prefix, ViewNode node, boolean showSensitive) {
Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+ " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
int id = node.getId();
@@ -1992,12 +1992,15 @@
}
CharSequence text = node.getText();
if (text != null) {
+ final String safeText = node.isSanitized() || showSensitive ? text.toString()
+ : "REDACTED[" + text.length() + " chars]";
Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
- + node.getTextSelectionEnd() + "): " + text);
+ + node.getTextSelectionEnd() + "): " + safeText);
Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
+ node.getTextStyle());
Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
+ ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+ Log.i(TAG, prefix + " Input type: " + node.getInputType());
}
String webDomain = node.getWebDomain();
if (webDomain != null) {
@@ -2031,7 +2034,6 @@
Log.i(TAG, prefix + "Autofill info: id= " + autofillId
+ ", type=" + node.getAutofillType()
+ ", options=" + Arrays.toString(node.getAutofillOptions())
- + ", inputType=" + node.getInputType()
+ ", hints=" + Arrays.toString(node.getAutofillHints())
+ ", value=" + node.getAutofillValue()
+ ", sanitized=" + node.isSanitized());
@@ -2043,7 +2045,7 @@
String cprefix = prefix + " ";
for (int i=0; i<NCHILDREN; i++) {
ViewNode cnode = node.getChildAt(i);
- dump(cprefix, cnode);
+ dump(cprefix, cnode, showSensitive);
}
}
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 007ea88..3cb59f2 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -111,8 +111,11 @@
/* Minimum flex for a periodic job, in milliseconds. */
private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
- /* Minimum backoff interval for a job, in milliseconds */
- private static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
+ /**
+ * Minimum backoff interval for a job, in milliseconds
+ * @hide
+ */
+ public static final long MIN_BACKOFF_MILLIS = 10 * 1000L; // 10 seconds
/**
* Query the minimum interval allowed for periodic scheduled jobs. Attempting
@@ -431,7 +434,7 @@
/**
* The amount of time the JobScheduler will wait before rescheduling a failed job. This value
* will be increased depending on the backoff policy specified at job creation time. Defaults
- * to 5 seconds.
+ * to 30 seconds, minimum is currently 10 seconds.
*/
public long getInitialBackoffMillis() {
final long minBackoff = getMinBackoffMillis();
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index ce8b05a..0d7a941 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -15,10 +15,13 @@
*/
package android.app.usage;
+import android.annotation.IntDef;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
@@ -28,6 +31,12 @@
*/
public final class UsageEvents implements Parcelable {
+ /** @hide */
+ public static final String INSTANT_APP_PACKAGE_NAME = "android.instant_app";
+
+ /** @hide */
+ public static final String INSTANT_APP_CLASS_NAME = "android.instant_class";
+
/**
* An event representing a state change for a component.
*/
@@ -91,6 +100,17 @@
*/
public static final int CHOOSER_ACTION = 9;
+ /** @hide */
+ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
+
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ FLAG_IS_PACKAGE_INSTANT_APP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EventFlags {}
+
/**
* {@hide}
*/
@@ -145,6 +165,27 @@
*/
public String[] mContentAnnotations;
+ /** @hide */
+ @EventFlags
+ public int mFlags;
+
+ public Event() {
+ }
+
+ /** @hide */
+ public Event(Event orig) {
+ mPackage = orig.mPackage;
+ mClass = orig.mClass;
+ mTimeStamp = orig.mTimeStamp;
+ mEventType = orig.mEventType;
+ mConfiguration = orig.mConfiguration;
+ mShortcutId = orig.mShortcutId;
+ mAction = orig.mAction;
+ mContentType = orig.mContentType;
+ mContentAnnotations = orig.mContentAnnotations;
+ mFlags = orig.mFlags;
+ }
+
/**
* The package name of the source of this event.
*/
@@ -196,6 +237,20 @@
public String getShortcutId() {
return mShortcutId;
}
+
+ /** @hide */
+ public Event getObfuscatedIfInstantApp() {
+ if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
+ return this;
+ }
+ final Event ret = new Event(this);
+ ret.mPackage = INSTANT_APP_PACKAGE_NAME;
+ ret.mClass = INSTANT_APP_CLASS_NAME;
+
+ // Note there are other string fields too, but they're for app shortcuts and choosers,
+ // which instant apps can't use anyway, so there's no need to hide them.
+ return ret;
+ }
}
// Only used when creating the resulting events. Not used for reading/unparceling.
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 0874095..7eef85c 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -85,6 +85,17 @@
mChooserCounts = stats.mChooserCounts;
}
+ /**
+ * {@hide}
+ */
+ public UsageStats getObfuscatedForInstantApp() {
+ final UsageStats ret = new UsageStats(this);
+
+ ret.mPackageName = UsageEvents.INSTANT_APP_PACKAGE_NAME;
+
+ return ret;
+ }
+
public String getPackageName() {
return mPackageName;
}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 08595dd..dbaace2 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -127,7 +127,12 @@
public abstract void applyRestoredPayload(int user, String key, byte[] payload);
- /* Cache Quota Service API */
+ /**
+ * Return usage stats.
+ *
+ * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
+ * result.
+ */
public abstract List<UsageStats> queryUsageStatsForUser(
- int userId, int interval, long beginTime, long endTime);
+ int userId, int interval, long beginTime, long endTime, boolean obfuscateInstantApps);
}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 5fabbb6..a3d6e9f 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.content.Context;
import android.os.Handler;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -927,6 +926,31 @@
}
/**
+ * Discovers a service by UUID. This is exposed only for passing PTS tests.
+ * It should never be used by real applications. The service is not searched
+ * for characteristics and descriptors, or returned in any callback.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @return true, if the remote service discovery has been started
+ * @hide
+ */
+ public boolean discoverServiceByUuid(UUID uuid) {
+ if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress());
+ if (mService == null || mClientIf == 0) return false;
+
+ mServices.clear();
+
+ try {
+ mService.discoverServiceByUuid(mClientIf, mDevice.getAddress(), new ParcelUuid(uuid));
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Returns a list of GATT services offered by the remote device.
*
* <p>This function requires that service discovery has been completed
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index dc5c7b6..167f5e9 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -80,6 +80,7 @@
void clientReadPhy(in int clientIf, in String address);
void refreshDevice(in int clientIf, in String address);
void discoverServices(in int clientIf, in String address);
+ void discoverServiceByUuid(in int clientIf, in String address, in ParcelUuid uuid);
void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
in int startHandle, in int endHandle, in int authReq);
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index c3d6606..f907721 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -330,10 +330,32 @@
* This can be called by an application in {@link #onReceive} to allow
* it to keep the broadcast active after returning from that function.
* This does <em>not</em> change the expectation of being relatively
- * responsive to the broadcast (finishing it within 10s), but does allow
+ * responsive to the broadcast, but does allow
* the implementation to move work related to it over to another thread
* to avoid glitching the main UI thread due to disk IO.
*
+ * <p>As a general rule, broadcast receivers are allowed to run for up to 10 seconds
+ * before they system will consider them non-responsive and ANR the app. Since these usually
+ * execute on the app's main thread, they are already bound by the ~5 second time limit
+ * of various operations that can happen there (not to mention just avoiding UI jank), so
+ * the receive limit is generally not of concern. However, once you use {@goAsync}, though
+ * able to be off the main thread, the broadcast execution limit still applies, and that
+ * includes the time spent between calling this method and ultimately
+ * {@link PendingResult#finish() PendingResult.finish()}.</p>
+ *
+ * <p>If you are taking advantage of this method to have more time to execute, it is useful
+ * to know that the available time can be longer in certain situations. In particular, if
+ * the broadcast you are receiving is not a foreground broadcast (that is, the sender has not
+ * used {@link Intent#FLAG_RECEIVER_FOREGROUND}), then more time is allowed for the receivers
+ * to run, allowing them to execute for 30 seconds or even a bit more. This is something that
+ * receivers should rarely take advantage of (long work should be punted to another system
+ * facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
+ * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
+ * certain rare cases where it is necessary to do some work as soon as the broadcast is
+ * delivered. Keep in mind that the work you do here will block further broadcasts until
+ * it completes, so taking advantage of this at all excessively can be counter-productive
+ * and cause later events to be received more slowly.</p>
+ *
* @return Returns a {@link PendingResult} representing the result of
* the active broadcast. The BroadcastRecord itself is no longer active;
* all data and other interaction must go through {@link PendingResult}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1d5377b..d719da9 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -650,12 +650,14 @@
int getInstallReason(String packageName, int userId);
- ParceledListSlice getSharedLibraries(int flags, int userId);
+ ParceledListSlice getSharedLibraries(in String packageName, int flags, int userId);
boolean canRequestPackageInstalls(String packageName, int userId);
void deletePreloadsFileCache();
+ ComponentName getInstantAppResolverComponent();
+
ComponentName getInstantAppResolverSettingsComponent();
ComponentName getInstantAppInstallerComponent();
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 426f3cf..87e6a84 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -341,4 +341,7 @@
* Return the taget SDK version for the app with the given UID.
*/
public abstract int getUidTargetSdkVersion(int uid);
+
+ /** Whether the binder caller can access instant apps. */
+ public abstract boolean canAccessInstantApps(int callingUid);
}
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index e3e0cc5..f779aeb 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -886,6 +886,11 @@
/**
* Return the max width for icons, in pixels.
+ *
+ * <p> Note that this method returns max width of icon's visible part. Hence, it does not take
+ * into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image
+ * to function as {@link AcaptiveIconDrawable}, multiply
+ * 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size.
*/
public int getIconMaxWidth() {
try {
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index bdfef83..b3adf82 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -772,6 +772,10 @@
}
final String file = value.string.toString();
+ if (!file.startsWith("res/")) {
+ return null;
+ }
+
Typeface cached = Typeface.findFromCache(mAssets, file);
if (cached != null) {
return cached;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index fccc877..b00e65a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -100,8 +100,8 @@
public static final int FINGERPRINT_ERROR_CANCELED = 5;
/**
- * The {@link FingerprintManager#remove(Fingerprint, RemovalCallback)} call failed. Typically
- * this will happen when the provided fingerprint id was incorrect.
+ * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
+ * provided fingerprint id was incorrect.
*
* @hide
*/
@@ -118,6 +118,15 @@
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR = 8;
+
+ /**
+ * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
+ * Fingerprint authentication is disabled until the user unlocks with strong authentication
+ * (PIN/Pattern/Password)
+ * @hide
+ */
+ public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
+
/**
* @hide
*/
@@ -389,10 +398,10 @@
};
/**
- * Callback structure provided to {@link FingerprintManager#remove(int). Users of
- * {@link #FingerprintManager()} may optionally provide an implementation of this to
- * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
- * fingerprint template removal events.
+ * Callback structure provided to {@link #remove}. Users of {@link FingerprintManager} may
+ * optionally provide an implementation of this to
+ * {@link #remove(Fingerprint, int, RemovalCallback)} for listening to fingerprint template
+ * removal events.
*
* @hide
*/
@@ -407,9 +416,13 @@
/**
* Called when a given fingerprint is successfully removed.
- * @param fingerprint the fingerprint template that was removed.
+ * @param fp The fingerprint template that was removed.
+ * @param remaining The number of fingerprints yet to be removed in this operation. If
+ * {@link #remove} is called on one fingerprint, this should be 0. If
+ * {@link #remove} is called on a group, this should be the number of remaining
+ * fingerprints in the group, and 0 after the last fingerprint is removed.
*/
- public void onRemovalSucceeded(Fingerprint fingerprint) { }
+ public void onRemovalSucceeded(Fingerprint fp, int remaining) { }
};
/**
@@ -869,29 +882,38 @@
msg.arg2 /* vendorCode */);
break;
case MSG_REMOVED:
- sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
- msg.arg2 /* groupId */);
+ sendRemovedResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
+ break;
case MSG_ENUMERATED:
sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
msg.arg2 /* groupId */);
+ break;
}
}
- private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
- if (mRemovalCallback != null) {
- int reqFingerId = mRemovalFingerprint.getFingerId();
- int reqGroupId = mRemovalFingerprint.getGroupId();
- if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
- Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
- return;
- }
- if (groupId != reqGroupId) {
- Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
- return;
- }
- mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
- deviceId));
+ private void sendRemovedResult(Fingerprint fingerprint, int remaining) {
+ if (mRemovalCallback == null) {
+ return;
}
+ if (fingerprint == null) {
+ Log.e(TAG, "Received MSG_REMOVED, but fingerprint is null");
+ return;
+ }
+
+ int fingerId = fingerprint.getFingerId();
+ int reqFingerId = mRemovalFingerprint.getFingerId();
+ if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
+ Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ return;
+ }
+ int groupId = fingerprint.getGroupId();
+ int reqGroupId = mRemovalFingerprint.getGroupId();
+ if (groupId != reqGroupId) {
+ Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ return;
+ }
+
+ mRemovalCallback.onRemovalSucceeded(fingerprint, remaining);
}
private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
@@ -1013,6 +1035,9 @@
return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
case FINGERPRINT_ERROR_LOCKOUT:
return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
+ case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
+ return mContext.getString(
+ com.android.internal.R.string.fingerprint_error_lockout_permanent);
case FINGERPRINT_ERROR_VENDOR: {
String[] msgArray = mContext.getResources().getStringArray(
com.android.internal.R.array.fingerprint_error_vendor);
@@ -1086,8 +1111,8 @@
@Override // binder call
public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
- // TODO: propagate remaining
- mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
+ mHandler.obtainMessage(MSG_REMOVED, remaining, 0,
+ new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
}
@Override // binder call
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index 4e6a1e7..1fc71e0 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -58,4 +58,32 @@
void cancel();
RadioManager.ProgramInfo getProgramInformation();
+
+ /**
+ * @returns {@code true} if the scan was properly scheduled,
+ * {@code false} if the scan feature is unavailable
+ */
+ boolean startBackgroundScan();
+
+ /**
+ * @returns the list, or null if scan is in progress
+ * @throws IllegalArgumentException if invalid arguments are passed
+ * @throws IllegalStateException if the scan has not been started, client may
+ * call startBackgroundScan to fix this.
+ */
+ List<RadioManager.ProgramInfo> getProgramList(String filter);
+
+ /**
+ * @throws IllegalStateException if the switch is not supported at current
+ * configuration.
+ */
+ boolean isAnalogForced();
+
+ /**
+ * @throws IllegalStateException if the switch is not supported at current
+ * configuration.
+ */
+ void setAnalogForced(boolean isForced);
+
+ boolean isAntennaConnected();
}
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index bffca61..a457494 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -182,32 +182,47 @@
@Override
public boolean startBackgroundScan() {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ return mTuner.startBackgroundScan();
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
}
@Override
public @NonNull List<RadioManager.ProgramInfo> getProgramList(@Nullable String filter) {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ return mTuner.getProgramList(filter);
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
}
@Override
public boolean isAnalogForced() {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ return mTuner.isAnalogForced();
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
}
@Override
public void setAnalogForced(boolean isForced) {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ mTuner.setAnalogForced(isForced);
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
}
@Override
public boolean isAntennaConnected() {
- // TODO(b/36863239): forward to mTuner
- throw new RuntimeException("Not implemented");
+ try {
+ return mTuner.isAntennaConnected();
+ } catch (RemoteException e) {
+ throw new RuntimeException("service died", e);
+ }
}
@Override
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index dadc5f5..083345d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -45,7 +45,6 @@
import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.telephony.ITelephony;
@@ -2642,7 +2641,7 @@
/**
* Called if no network is found in the timeout time specified in
- * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)} call. This callback is not
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not
* called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
* without timeout. When this callback is invoked the associated
* {@link NetworkRequest} will have already been removed and released, as if
@@ -2939,7 +2938,7 @@
* This {@link NetworkRequest} will live until released via
* {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
* version of the method which takes a timeout is
- * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
@@ -2974,7 +2973,7 @@
* This {@link NetworkRequest} will live until released via
* {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. A
* version of the method which takes a timeout is
- * {@link #requestNetwork(NetworkRequest, int, NetworkCallback)}.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}.
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index d7b58f7..fdb4ba0 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -20,19 +20,14 @@
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Build;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
-import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* The base class for implementing a network recommendation provider.
@@ -55,34 +50,10 @@
public abstract class NetworkRecommendationProvider {
private static final String TAG = "NetworkRecProvider";
private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
- /** The key into the callback Bundle where the RecommendationResult will be found.
- * @deprecated to be removed.
- * @removed
- */
- public static final String EXTRA_RECOMMENDATION_RESULT =
- "android.net.extra.RECOMMENDATION_RESULT";
- /** The key into the callback Bundle where the sequence will be found.
- * @deprecated to be removed.
- * @removed
- */
- public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
private final IBinder mService;
/**
* Constructs a new instance.
- * @param handler indicates which thread to use when handling requests. Cannot be {@code null}.
- * @deprecated use {@link #NetworkRecommendationProvider(Context, Executor)}
- * @removed
- */
- public NetworkRecommendationProvider(Handler handler) {
- if (handler == null) {
- throw new IllegalArgumentException("The provided handler cannot be null.");
- }
- mService = new ServiceWrapper(handler);
- }
-
- /**
- * Constructs a new instance.
* @param context the current context instance. Cannot be {@code null}.
* @param executor used to execute the incoming requests. Cannot be {@code null}.
*/
@@ -93,19 +64,6 @@
}
/**
- * Invoked when a recommendation has been requested.
- *
- * @param request a {@link RecommendationRequest} instance containing additional
- * request details
- * @param callback a {@link ResultCallback} instance. When a {@link RecommendationResult} is
- * available it must be passed into
- * {@link ResultCallback#onResult(RecommendationResult)}.
- * @deprecated to be removed.
- * @removed
- */
- public void onRequestRecommendation(RecommendationRequest request, ResultCallback callback) {}
-
- /**
* Invoked when network scores have been requested.
* <p>
* Use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to respond to score requests.
@@ -123,66 +81,6 @@
}
/**
- * A callback implementing applications should invoke when a {@link RecommendationResult}
- * is available.
- *
- * @deprecated to be removed.
- * @removed
- */
- public static class ResultCallback {
- private final IRemoteCallback mCallback;
- private final int mSequence;
- private final AtomicBoolean mCallbackRun;
-
- /**
- * @hide
- */
- @VisibleForTesting
- public ResultCallback(IRemoteCallback callback, int sequence) {
- mCallback = callback;
- mSequence = sequence;
- mCallbackRun = new AtomicBoolean(false);
- }
-
- /**
- * Run the callback with the available {@link RecommendationResult}.
- * @param result a {@link RecommendationResult} instance.
- */
- public void onResult(RecommendationResult result) {
- if (VERBOSE) Log.v(TAG, "onResult(seq=" + mSequence + ")");
- if (!mCallbackRun.compareAndSet(false, true)) {
- throw new IllegalStateException("The callback cannot be run more than once. "
- + "seq=" + mSequence);
- }
- final Bundle data = new Bundle();
- data.putInt(EXTRA_SEQUENCE, mSequence);
- data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
- try {
- mCallback.sendResult(data);
- } catch (RemoteException e) {
- Log.w(TAG, "Callback failed for seq: " + mSequence, e);
- }
- if (VERBOSE) Log.v(TAG, "onResult() complete. seq=" + mSequence);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- ResultCallback that = (ResultCallback) o;
-
- return mSequence == that.mSequence
- && Objects.equals(mCallback, that.mCallback);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mCallback, mSequence);
- }
- }
-
- /**
* A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
*/
private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
@@ -190,12 +88,6 @@
private final Executor mExecutor;
private final Handler mHandler;
- ServiceWrapper(Handler handler) {
- mHandler = handler;
- mExecutor = null;
- mContext = null;
- }
-
ServiceWrapper(Context context, Executor executor) {
mContext = context;
mExecutor = executor;
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index caf7982..0d2fcd0 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,8 +18,8 @@
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_PROXY;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -34,8 +34,8 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.BackupUtils;
+import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.io.ByteArrayOutputStream;
@@ -52,14 +52,18 @@
* @hide
*/
public class NetworkTemplate implements Parcelable {
+ private static final String TAG = "NetworkTemplate";
+
/**
* Current Version of the Backup Serializer.
*/
private static final int BACKUP_VERSION = 1;
public static final int MATCH_MOBILE_ALL = 1;
+ /** @deprecated don't use this any more */
@Deprecated
public static final int MATCH_MOBILE_3G_LOWER = 2;
+ /** @deprecated don't use this any more */
@Deprecated
public static final int MATCH_MOBILE_4G = 3;
public static final int MATCH_WIFI = 4;
@@ -69,9 +73,26 @@
public static final int MATCH_BLUETOOTH = 8;
public static final int MATCH_PROXY = 9;
+ private static boolean isKnownMatchRule(final int rule) {
+ switch (rule) {
+ case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE_3G_LOWER:
+ case MATCH_MOBILE_4G:
+ case MATCH_WIFI:
+ case MATCH_ETHERNET:
+ case MATCH_MOBILE_WILDCARD:
+ case MATCH_WIFI_WILDCARD:
+ case MATCH_BLUETOOTH:
+ case MATCH_PROXY:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
private static boolean sForceAllNetworkTypes = false;
- @VisibleForTesting
public static void forceAllNetworkTypes() {
sForceAllNetworkTypes = true;
}
@@ -180,6 +201,11 @@
mSubscriberId = subscriberId;
mMatchSubscriberIds = matchSubscriberIds;
mNetworkId = networkId;
+
+ if (!isKnownMatchRule(matchRule)) {
+ Log.e(TAG, "Unknown network template rule " + matchRule
+ + " will not match any identity.");
+ }
}
private NetworkTemplate(Parcel in) {
@@ -294,7 +320,9 @@
case MATCH_PROXY:
return matchesProxy(ident);
default:
- throw new IllegalArgumentException("unknown network template");
+ // We have no idea what kind of network template we are, so we
+ // just claim not to match anything.
+ return false;
}
}
@@ -428,7 +456,7 @@
case MATCH_PROXY:
return "PROXY";
default:
- return "UNKNOWN";
+ return "UNKNOWN(" + matchRule + ")";
}
}
@@ -496,6 +524,11 @@
String subscriberId = BackupUtils.readString(in);
String networkId = BackupUtils.readString(in);
+ if (!isKnownMatchRule(matchRule)) {
+ throw new BackupUtils.BadVersionException(
+ "Restored network template contains unknown match rule " + matchRule);
+ }
+
return new NetworkTemplate(matchRule, subscriberId, networkId);
}
}
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
deleted file mode 100644
index 21641d9..0000000
--- a/core/java/android/net/RecommendationRequest.java
+++ /dev/null
@@ -1,268 +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.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * A request for a network recommendation.
- *
- * @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
- * @hide
- * @deprecated to be removed.
- * @removed
- */
-public final class RecommendationRequest implements Parcelable {
- private final ScanResult[] mScanResults;
- private final WifiConfiguration mDefaultConfig;
- private WifiConfiguration mConnectedConfig;
- private WifiConfiguration[] mConnectableConfigs;
- private final int mLastSelectedNetworkId;
- private final long mLastSelectedNetworkTimestamp;
-
- /**
- * Builder class for constructing {@link RecommendationRequest} instances.
- * @hide
- * @deprecated to be removed.
- * @removed
- */
- public static final class Builder {
- private ScanResult[] mScanResults;
- private WifiConfiguration mDefaultConfig;
- private WifiConfiguration mConnectedConfig;
- private WifiConfiguration[] mConnectableConfigs;
- private int mLastSelectedNetworkId = -1;
- private long mLastSelectedTimestamp;
-
- public Builder setScanResults(ScanResult[] scanResults) {
- mScanResults = scanResults;
- return this;
- }
-
- /**
- * @param config the {@link WifiConfiguration} to return if no recommendation is available.
- * @return this
- */
- public Builder setDefaultWifiConfig(WifiConfiguration config) {
- this.mDefaultConfig = config;
- return this;
- }
-
- /**
- * @param config the {@link WifiConfiguration} of the connected network at the time the
- * this request was made.
- * @return this
- */
- public Builder setConnectedWifiConfig(WifiConfiguration config) {
- this.mConnectedConfig = config;
- return this;
- }
-
- /**
- * @param connectableConfigs the set of saved {@link WifiConfiguration}s that can be
- * connected to based on the current set of {@link ScanResult}s.
- * @return this
- */
- public Builder setConnectableConfigs(WifiConfiguration[] connectableConfigs) {
- this.mConnectableConfigs = connectableConfigs;
- return this;
- }
-
- /**
- * @param networkId The {@link WifiConfiguration#networkId} of the last user selected
- * network.
- * @param timestamp The {@link android.os.SystemClock#elapsedRealtime()} when the user
- * selected {@code networkId}.
- * @return this
- */
- public Builder setLastSelectedNetwork(int networkId, long timestamp) {
- this.mLastSelectedNetworkId = networkId;
- this.mLastSelectedTimestamp = timestamp;
- return this;
- }
-
- /**
- * @return a new {@link RecommendationRequest} instance
- */
- public RecommendationRequest build() {
- return new RecommendationRequest(mScanResults, mDefaultConfig, mConnectedConfig,
- mConnectableConfigs, mLastSelectedNetworkId, mLastSelectedTimestamp);
- }
- }
-
- /**
- * @return the array of {@link ScanResult}s the recommendation must be constrained to i.e. if a
- * non-null wifi config recommendation is returned then it must be able to connect to
- * one of the networks in the results list.
- *
- * If the array is {@code null} or empty then there is no constraint.
- */
- public ScanResult[] getScanResults() {
- return mScanResults;
- }
-
- /**
- * @return the {@link WifiConfiguration} to return if no recommendation is available.
- */
- public WifiConfiguration getDefaultWifiConfig() {
- return mDefaultConfig;
- }
-
- /**
- * @return the {@link WifiConfiguration} of the connected network at the time the this request
- * was made.
- */
- public WifiConfiguration getConnectedConfig() {
- return mConnectedConfig;
- }
-
- /**
- * @return the set of saved {@link WifiConfiguration}s that can be connected to based on the
- * current set of {@link ScanResult}s.
- */
- public WifiConfiguration[] getConnectableConfigs() {
- return mConnectableConfigs;
- }
-
- /**
- * @param connectedConfig the {@link WifiConfiguration} of the connected network at the time
- * the this request was made.
- */
- public void setConnectedConfig(WifiConfiguration connectedConfig) {
- mConnectedConfig = connectedConfig;
- }
-
- /**
- * @param connectableConfigs the set of saved {@link WifiConfiguration}s that can be connected
- * to based on the current set of {@link ScanResult}s.
- */
- public void setConnectableConfigs(WifiConfiguration[] connectableConfigs) {
- mConnectableConfigs = connectableConfigs;
- }
-
- /**
- * @return The {@link WifiConfiguration#networkId} of the last user selected network.
- * {@code -1} if not set.
- */
- public int getLastSelectedNetworkId() {
- return mLastSelectedNetworkId;
- }
-
- /**
- * @return The {@link android.os.SystemClock#elapsedRealtime()} when the user selected
- * {@link #getLastSelectedNetworkId()}. {@code 0} if not set.
- */
- public long getLastSelectedNetworkTimestamp() {
- return mLastSelectedNetworkTimestamp;
- }
-
- @VisibleForTesting
- RecommendationRequest(ScanResult[] scanResults,
- WifiConfiguration defaultWifiConfig,
- WifiConfiguration connectedWifiConfig,
- WifiConfiguration[] connectableConfigs,
- int lastSelectedNetworkId,
- long lastSelectedNetworkTimestamp) {
- mScanResults = scanResults;
- mDefaultConfig = defaultWifiConfig;
- mConnectedConfig = connectedWifiConfig;
- mConnectableConfigs = connectableConfigs;
- mLastSelectedNetworkId = lastSelectedNetworkId;
- mLastSelectedNetworkTimestamp = lastSelectedNetworkTimestamp;
- }
-
- protected RecommendationRequest(Parcel in) {
- final int resultCount = in.readInt();
- if (resultCount > 0) {
- mScanResults = new ScanResult[resultCount];
- final ClassLoader classLoader = ScanResult.class.getClassLoader();
- for (int i = 0; i < resultCount; i++) {
- mScanResults[i] = in.readParcelable(classLoader);
- }
- } else {
- mScanResults = null;
- }
-
- mDefaultConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
- mConnectedConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
-
- final int configCount = in.readInt();
- if (configCount > 0) {
- mConnectableConfigs = new WifiConfiguration[configCount];
- final ClassLoader classLoader = WifiConfiguration.class.getClassLoader();
- for (int i = 0; i < configCount; i++) {
- mConnectableConfigs[i] = in.readParcelable(classLoader);
- }
- } else {
- mConnectableConfigs = null;
- }
-
- mLastSelectedNetworkId = in.readInt();
- mLastSelectedNetworkTimestamp = in.readLong();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- if (mScanResults != null) {
- dest.writeInt(mScanResults.length);
- for (int i = 0; i < mScanResults.length; i++) {
- dest.writeParcelable(mScanResults[i], flags);
- }
- } else {
- dest.writeInt(0);
- }
-
- dest.writeParcelable(mDefaultConfig, flags);
- dest.writeParcelable(mConnectedConfig, flags);
-
- if (mConnectableConfigs != null) {
- dest.writeInt(mConnectableConfigs.length);
- for (int i = 0; i < mConnectableConfigs.length; i++) {
- dest.writeParcelable(mConnectableConfigs[i], flags);
- }
- } else {
- dest.writeInt(0);
- }
-
- dest.writeInt(mLastSelectedNetworkId);
- dest.writeLong(mLastSelectedNetworkTimestamp);
- }
-
- public static final Creator<RecommendationRequest> CREATOR =
- new Creator<RecommendationRequest>() {
- @Override
- public RecommendationRequest createFromParcel(Parcel in) {
- return new RecommendationRequest(in);
- }
-
- @Override
- public RecommendationRequest[] newArray(int size) {
- return new RecommendationRequest[size];
- }
- };
-}
diff --git a/core/java/android/net/RecommendationResult.java b/core/java/android/net/RecommendationResult.java
deleted file mode 100644
index d66dd22..0000000
--- a/core/java/android/net/RecommendationResult.java
+++ /dev/null
@@ -1,116 +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.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * The result of a network recommendation.
- *
- * @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
- * @hide
- * @deprecated to be removed.
- * @removed
- */
-public final class RecommendationResult implements Parcelable {
- private final WifiConfiguration mWifiConfiguration;
-
- /**
- * Create a {@link RecommendationResult} that indicates that no network connection should be
- * attempted at this time.
- *
- * @return a {@link RecommendationResult}
- */
- public static RecommendationResult createDoNotConnectRecommendation() {
- return new RecommendationResult((WifiConfiguration) null);
- }
-
- /**
- * Create a {@link RecommendationResult} that indicates that a connection attempt should be
- * made for the given Wi-Fi network.
- *
- * @param wifiConfiguration {@link WifiConfiguration} with at least SSID and BSSID set.
- * @return a {@link RecommendationResult}
- */
- public static RecommendationResult createConnectRecommendation(
- @NonNull WifiConfiguration wifiConfiguration) {
- Preconditions.checkNotNull(wifiConfiguration, "wifiConfiguration must not be null");
- Preconditions.checkNotNull(wifiConfiguration.SSID, "SSID must not be null");
- Preconditions.checkNotNull(wifiConfiguration.BSSID, "BSSID must not be null");
- return new RecommendationResult(wifiConfiguration);
- }
-
- private RecommendationResult(@Nullable WifiConfiguration wifiConfiguration) {
- mWifiConfiguration = wifiConfiguration;
- }
-
- private RecommendationResult(Parcel in) {
- mWifiConfiguration = in.readParcelable(WifiConfiguration.class.getClassLoader());
- }
-
- /**
- * @return {@code true} if a network recommendation exists. {@code false} indicates that
- * no connection should be attempted at this time.
- */
- public boolean hasRecommendation() {
- return mWifiConfiguration != null;
- }
-
- /**
- * @return The recommended {@link WifiConfiguration} to connect to. A {@code null} value
- * is returned if {@link #hasRecommendation} returns {@code false}.
- */
- @Nullable public WifiConfiguration getWifiConfiguration() {
- return mWifiConfiguration;
- }
-
- @Override
- public String toString() {
- return "RecommendationResult{" +
- "mWifiConfiguration=" + mWifiConfiguration +
- "}";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(mWifiConfiguration, flags);
- }
-
- public static final Creator<RecommendationResult> CREATOR =
- new Creator<RecommendationResult>() {
- @Override
- public RecommendationResult createFromParcel(Parcel in) {
- return new RecommendationResult(in);
- }
-
- @Override
- public RecommendationResult[] newArray(int size) {
- return new RecommendationResult[size];
- }
- };
-}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cabe24f..3eea72d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1189,7 +1189,6 @@
// Platform-level low power state stats
public String statPlatformIdleState;
- public String statSubsystemPowerState;
public HistoryStepDetails() {
clear();
@@ -1221,7 +1220,6 @@
out.writeInt(statSoftIrqTime);
out.writeInt(statIdlTime);
out.writeString(statPlatformIdleState);
- out.writeString(statSubsystemPowerState);
}
public void readFromParcel(Parcel in) {
@@ -1243,7 +1241,6 @@
statSoftIrqTime = in.readInt();
statIdlTime = in.readInt();
statPlatformIdleState = in.readString();
- statSubsystemPowerState = in.readString();
}
}
@@ -5390,10 +5387,6 @@
pw.print(", PlatformIdleStat ");
pw.print(rec.stepDetails.statPlatformIdleState);
pw.println();
-
- pw.print(", SubsystemPowerState ");
- pw.print(rec.stepDetails.statSubsystemPowerState);
- pw.println();
} else {
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
pw.print(HISTORY_DATA); pw.print(",0,Dcpu=");
@@ -5431,11 +5424,6 @@
pw.print(rec.stepDetails.statPlatformIdleState);
}
pw.println();
-
- if (rec.stepDetails.statSubsystemPowerState != null) {
- pw.print(rec.stepDetails.statSubsystemPowerState);
- }
- pw.println();
}
}
oldState = rec.states;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 86fcfc8..4bad7ab 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -758,7 +758,7 @@
/**
* O.
*/
- public static final int O = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
+ public static final int O = 26;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index e4cdbce..f9eaba9 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -20,6 +20,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.opengl.EGL14;
+import android.os.Build;
import android.os.SystemProperties;
import android.util.Log;
@@ -81,6 +82,12 @@
}
return;
}
+ if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+ // O drivers are restricted to the sphal linker namespace, so don't try to use
+ // packages unless they declare they're compatible with that restriction.
+ Log.w(TAG, "updated driver package is not known to be compatible with O");
+ return;
+ }
StringBuilder sb = new StringBuilder();
sb.append(driverInfo.nativeLibraryDir)
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 3212139..c091420 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -547,7 +547,8 @@
* Converts a string representing a file mode, such as "rw", into a bitmask suitable for use
* with {@link #open}.
* <p>
- * @param mode The string representation of the file mode.
+ * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw"
+ * or "rwt".
* @return A bitmask representing the given file mode.
* @throws IllegalArgumentException if the given string does not match a known file mode.
*/
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7a709ed..3074942 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -386,6 +386,12 @@
**/
public static final int THREAD_GROUP_TOP_APP = 5;
+ /**
+ * Thread group for RT app.
+ * @hide
+ **/
+ public static final int THREAD_GROUP_RT_APP = 6;
+
public static final int SIGNAL_QUIT = 3;
public static final int SIGNAL_KILL = 9;
public static final int SIGNAL_USR1 = 10;
diff --git a/core/java/android/os/ProxyFileDescriptorCallback.java b/core/java/android/os/ProxyFileDescriptorCallback.java
index e69fb55..9f56802 100644
--- a/core/java/android/os/ProxyFileDescriptorCallback.java
+++ b/core/java/android/os/ProxyFileDescriptorCallback.java
@@ -22,7 +22,23 @@
/**
* Callback that handles file system requests from ProxyFileDescriptor.
*
- * @see android.os.storage.StorageManager#openProxyFileDescriptor(int, ProxyFileDescriptorCallback)
+ * All callback methods except for onRelease should throw {@link android.system.ErrnoException}
+ * with proper errno on errors. See
+ * <a href="http://man7.org/linux/man-pages/man3/errno.3.html">errno(3)</a> and
+ * {@link android.system.OsConstants}.
+ *
+ * Typical errnos are
+ *
+ * <ul>
+ * <li>{@link android.system.OsConstants#EIO} for general I/O issues
+ * <li>{@link android.system.OsConstants#ENOENT} when the file is not found
+ * <li>{@link android.system.OsConstants#EBADF} if the file doesn't allow read/write operations
+ * based on how it was opened. (For example, trying to write a file that was opened read-only.)
+ * <li>{@link android.system.OsConstants#ENOSPC} if you cannot handle a write operation to
+ * space/quota limitations.
+ * </ul>
+ * @see android.os.storage.StorageManager#openProxyFileDescriptor(int, ProxyFileDescriptorCallback,
+ * Handler)
*/
public abstract class ProxyFileDescriptorCallback {
/**
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 6c01b36..fa96dd3 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -16,6 +16,8 @@
package android.os;
+import com.android.internal.os.Zygote;
+
import dalvik.annotation.optimization.FastNative;
/**
@@ -94,6 +96,8 @@
// Must be volatile to avoid word tearing.
private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
+ private static int sZygoteDebugFlags = 0;
+
private static native long nativeGetEnabledTags();
private static native void nativeSetAppTracingAllowed(boolean allowed);
private static native void nativeSetTracingEnabled(boolean allowed);
@@ -118,9 +122,10 @@
// The system provides ordering through a priority level. Callbacks made through
// SystemProperties.addChangeCallback currently have a negative priority, while
// our native code is using a priority of zero.
- SystemProperties.addChangeCallback(new Runnable() {
- @Override public void run() {
- cacheEnabledTags();
+ SystemProperties.addChangeCallback(() -> {
+ cacheEnabledTags();
+ if ((sZygoteDebugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
+ traceCounter(TRACE_TAG_ALWAYS, "java_debuggable", 1);
}
});
}
@@ -201,8 +206,9 @@
*
* @hide
*/
- public static void setTracingEnabled(boolean enabled) {
+ public static void setTracingEnabled(boolean enabled, int debugFlags) {
nativeSetTracingEnabled(enabled);
+ sZygoteDebugFlags = debugFlags;
// Setting whether tracing is enabled may change the tags, so we update the cached tags
// here.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f2df7da..7bd3bf6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.AccountManager;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -2129,7 +2130,7 @@
* @return the list of users that were created.
* @hide
*/
- public List<UserInfo> getUsers(boolean excludeDying) {
+ public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
try {
return mService.getUsers(excludeDying);
} catch (RemoteException re) {
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 97da588..17f00c2 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -167,4 +167,12 @@
* Remove user's running state
*/
public abstract void removeUserState(int userId);
+
+ /**
+ * Returns an array of user ids. This array is cached in UserManagerService and passed as a
+ * reference, so do not modify the returned array.
+ *
+ * @return the array of user ids.
+ */
+ public abstract int[] getUserIds();
}
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 2cc4b71..92f7f31 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -295,4 +295,5 @@
long getCacheSizeBytes(String volumeUuid, int uid) = 76;
long getAllocatableBytes(String volumeUuid, int flags) = 77;
void allocateBytes(String volumeUuid, long bytes, int flags) = 78;
+ void secdiscard(in String path) = 79;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index bd43d6a..f361c54 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1252,6 +1252,15 @@
}
/** {@hide} */
+ public void secdiscard(String path) {
+ try {
+ mStorageManager.secdiscard(path);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /** {@hide} */
public static boolean isUserKeyUnlocked(int userId) {
if (sStorageManager == null) {
sStorageManager = IStorageManager.Stub
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 2a83c4b..3eef31a 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -655,8 +655,12 @@
* <p>
* Your provider should return a reliable {@link ParcelFileDescriptor} to
* detect when the remote caller has finished reading or writing the
- * document. You may return a pipe or socket pair if the mode is exclusively
- * "r" or "w", but complex modes like "rw" imply a normal file on disk that
+ * document.
+ * <p>
+ * Mode "r" should always be supported. Provider should throw
+ * {@link UnsupportedOperationException} if the passing mode is not supported.
+ * You may return a pipe or socket pair if the mode is exclusively "r" or
+ * "w", but complex modes like "rw" imply a normal file on disk that
* supports seeking.
* <p>
* If you block while downloading content, you should periodically check
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 39f48df..52718fc 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6767,20 +6767,6 @@
public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity";
/**
- * Whether the assist gesture should be enabled during sleep
- *
- * @hide
- */
- public static final String ASSIST_GESTURE_ENABLED_SLEEP = "assist_gesture_enabled_sleep";
-
- /**
- * Whether assist gesture should be enabled in keyguard
- *
- * @hide
- */
- public static final String ASSIST_GESTURE_ENABLED_KEYGUARD = "assist_gesture_enabled_keyguard";
-
- /**
* Control whether Night display is currently activated.
* @hide
*/
@@ -7055,8 +7041,6 @@
NIGHT_DISPLAY_CUSTOM_END_TIME,
NIGHT_DISPLAY_COLOR_TEMPERATURE,
NIGHT_DISPLAY_AUTO_MODE,
- NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
- NIGHT_DISPLAY_ACTIVATED,
SYNC_PARENT_SOUNDS,
CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED,
CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED,
@@ -7652,6 +7636,21 @@
public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
/**
+ * The default SM-DP+ configured for this device.
+ *
+ * <p>An SM-DP+ is used by an LPA (see {@link android.service.euicc.EuiccService}) to
+ * download profiles. If this value is set, the LPA will query this server for any profiles
+ * available to this device. If any are available, they may be downloaded during device
+ * provisioning or in settings without needing the user to enter an activation code.
+ *
+ * @see android.service.euicc.EuiccService
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
+
+ /**
* Whether any activity can be resized. When this is true, any
* activity, regardless of manifest values, can be resized for multi-window.
* (0 = false, 1 = true)
@@ -9142,6 +9141,23 @@
public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
/**
+ * Battery anomaly detection specific settings
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "anomaly_detection_enabled=true,wakelock_threshold=2000"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * anomaly_detection_enabled (boolean)
+ * wakelock_enabled (boolean)
+ * wakelock_threshold (long)
+ * </pre>
+ * @hide
+ */
+ public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants";
+
+ /**
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/euicc/DeleteResult.aidl b/core/java/android/service/euicc/DeleteResult.aidl
new file mode 100644
index 0000000..3da8b49
--- /dev/null
+++ b/core/java/android/service/euicc/DeleteResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable DeleteResult;
diff --git a/core/java/android/service/euicc/DeleteResult.java b/core/java/android/service/euicc/DeleteResult.java
new file mode 100644
index 0000000..8be9ac9
--- /dev/null
+++ b/core/java/android/service/euicc/DeleteResult.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onDeleteSubscription} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class DeleteResult implements Parcelable {
+
+ public static final Creator<DeleteResult> CREATOR = new Creator<DeleteResult>() {
+ @Override
+ public DeleteResult createFromParcel(Parcel in) {
+ return new DeleteResult(in);
+ }
+
+ @Override
+ public DeleteResult[] newArray(int size) {
+ return new DeleteResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private DeleteResult(int result, int detailedCode) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ }
+
+ private DeleteResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the delete was successful. */
+ public static DeleteResult success() {
+ return new DeleteResult(RESULT_OK, 0);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implemenation-defined detailed error code for debugging purposes.
+ */
+ public static DeleteResult genericError(int detailedCode) {
+ return new DeleteResult(RESULT_GENERIC_ERROR, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/DownloadResult.java b/core/java/android/service/euicc/DownloadResult.java
index 4e2af53..ad75bff 100644
--- a/core/java/android/service/euicc/DownloadResult.java
+++ b/core/java/android/service/euicc/DownloadResult.java
@@ -23,7 +23,7 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Result of a {@link EuiccService#downloadSubscription} operation.
+ * Result of a {@link EuiccService#onDownloadSubscription} operation.
* @hide
*
* TODO(b/35851809): Make this a SystemApi.
diff --git a/core/java/android/service/euicc/EraseResult.aidl b/core/java/android/service/euicc/EraseResult.aidl
new file mode 100644
index 0000000..e28a097
--- /dev/null
+++ b/core/java/android/service/euicc/EraseResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable EraseResult;
diff --git a/core/java/android/service/euicc/EraseResult.java b/core/java/android/service/euicc/EraseResult.java
new file mode 100644
index 0000000..1cce5a9
--- /dev/null
+++ b/core/java/android/service/euicc/EraseResult.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onEraseSubscriptions} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class EraseResult implements Parcelable {
+
+ public static final Creator<EraseResult> CREATOR = new Creator<EraseResult>() {
+ @Override
+ public EraseResult createFromParcel(Parcel in) {
+ return new EraseResult(in);
+ }
+
+ @Override
+ public EraseResult[] newArray(int size) {
+ return new EraseResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private EraseResult(int result, int detailedCode) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ }
+
+ private EraseResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the erase was successful. */
+ public static EraseResult success() {
+ return new EraseResult(RESULT_OK, 0);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implemenation-defined detailed error code for debugging purposes.
+ */
+ public static EraseResult genericError(int detailedCode) {
+ return new EraseResult(RESULT_GENERIC_ERROR, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/core/java/android/service/euicc/EuiccProfileInfo.java
new file mode 100644
index 0000000..ba6c9a2
--- /dev/null
+++ b/core/java/android/service/euicc/EuiccProfileInfo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.UiccAccessRule;
+import android.text.TextUtils;
+
+/**
+ * Information about an embedded profile (subscription) on an eUICC.
+ *
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class EuiccProfileInfo implements Parcelable {
+
+ /** The iccid of the subscription. */
+ public final String iccid;
+
+ /**
+ * Optional access rules defining which apps can manage this subscription. If unset, only the
+ * platform can manage it.
+ */
+ public final @Nullable UiccAccessRule[] accessRules;
+
+ /** An optional nickname for the subscription. */
+ public final @Nullable String nickname;
+
+ public static final Creator<EuiccProfileInfo> CREATOR = new Creator<EuiccProfileInfo>() {
+ @Override
+ public EuiccProfileInfo createFromParcel(Parcel in) {
+ return new EuiccProfileInfo(in);
+ }
+
+ @Override
+ public EuiccProfileInfo[] newArray(int size) {
+ return new EuiccProfileInfo[size];
+ }
+ };
+
+ public EuiccProfileInfo(String iccid, @Nullable UiccAccessRule[] accessRules,
+ @Nullable String nickname) {
+ if (!TextUtils.isDigitsOnly(iccid)) {
+ throw new IllegalArgumentException("iccid contains invalid characters: " + iccid);
+ }
+ this.iccid = iccid;
+ this.accessRules = accessRules;
+ this.nickname = nickname;
+ }
+
+ private EuiccProfileInfo(Parcel in) {
+ iccid = in.readString();
+ accessRules = in.createTypedArray(UiccAccessRule.CREATOR);
+ nickname = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(iccid);
+ dest.writeTypedArray(accessRules, flags);
+ dest.writeString(nickname);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 03aa967..3734904 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -16,11 +16,13 @@
package android.service.euicc;
import android.annotation.CallSuper;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.euicc.DownloadableSubscription;
+import android.telephony.euicc.EuiccInfo;
import android.util.ArraySet;
/**
@@ -132,8 +134,8 @@
/**
* Populate {@link DownloadableSubscription} metadata for the given downloadable subscription.
*
- * @param slotId ID of the SIM slot to use when starting the download. This is currently not
- * populated but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
* @param subscription A subscription whose metadata needs to be populated.
* @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
* eUICC, perform this action automatically. Otherwise,
@@ -142,14 +144,29 @@
* @return The result of the operation.
* @see android.telephony.euicc.EuiccManager#getDownloadableSubscriptionMetadata
*/
- public abstract GetDownloadableSubscriptionMetadataResult getDownloadableSubscriptionMetadata(
+ public abstract GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(
int slotId, DownloadableSubscription subscription, boolean forceDeactivateSim);
/**
+ * Return metadata for subscriptions which are available for download for this device.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
+ * eUICC, perform this action automatically. Otherwise,
+ * {@link GetDefaultDownloadableSubscriptionListResult#mustDeactivateSim()} should be
+ * returned to allow the user to consent to this operation first.
+ * @return The result of the list operation.
+ * @see android.telephony.euicc.EuiccManager#getDefaultDownloadableSubscriptionList
+ */
+ public abstract GetDefaultDownloadableSubscriptionListResult
+ onGetDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim);
+
+ /**
* Download the given subscription.
*
- * @param slotId ID of the SIM slot onto which the subscription should be downloaded. This is
- * currently not populated but is here to future-proof the APIs.
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
* @param subscription The subscription to download.
* @param switchAfterDownload If true, the subscription should be enabled upon successful
* download.
@@ -160,11 +177,90 @@
* @return the result of the download operation.
* @see android.telephony.euicc.EuiccManager#downloadSubscription
*/
- public abstract DownloadResult downloadSubscription(int slotId,
+ public abstract DownloadResult onDownloadSubscription(int slotId,
DownloadableSubscription subscription, boolean switchAfterDownload,
boolean forceDeactivateSim);
/**
+ * Return a list of all @link EuiccProfileInfo}s.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @return The result of the operation.
+ * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList
+ * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList
+ */
+ public abstract GetEuiccProfileInfoListResult onGetEuiccProfileInfoList(int slotId);
+
+ /**
+ * Return info about the eUICC chip/device.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @return the {@link EuiccInfo} for the eUICC chip/device.
+ * @see android.telephony.euicc.EuiccManager#getEuiccInfo
+ */
+ public abstract EuiccInfo onGetEuiccInfo(int slotId);
+
+ /**
+ * Delete the given subscription.
+ *
+ * <p>If the subscription is currently active, it should be deactivated first (equivalent to a
+ * physical SIM being ejected).
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @param iccid the ICCID of the subscription to delete.
+ * @return the result of the delete operation.
+ * @see android.telephony.euicc.EuiccManager#deleteSubscription
+ */
+ public abstract DeleteResult onDeleteSubscription(int slotId, String iccid);
+
+ /**
+ * Switch to the given subscription.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @param iccid the ICCID of the subscription to enable. May be null, in which case the current
+ * profile should be deactivated and no profile should be activated to replace it - this is
+ * equivalent to a physical SIM being ejected.
+ * @param forceDeactivateSim If true, and if an active SIM must be deactivated to access the
+ * eUICC, perform this action automatically. Otherwise,
+ * {@link SwitchResult#mustDeactivateSim()} should be returned to allow the user to consent
+ * to this operation first.
+ * @return the result of the switch operation.
+ * @see android.telephony.euicc.EuiccManager#switchToSubscription
+ */
+ public abstract SwitchResult onSwitchToSubscription(int slotId, @Nullable String iccid,
+ boolean forceDeactivateSim);
+
+ /**
+ * Update the nickname of the given subscription.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @param iccid the ICCID of the subscription to update.
+ * @param nickname the new nickname to apply.
+ * @return the result of the update operation.
+ * @see android.telephony.euicc.EuiccManager#updateSubscriptionNickname
+ */
+ public abstract UpdateNicknameResult onUpdateSubscriptionNickname(int slotId, String iccid,
+ String nickname);
+
+ /**
+ * Erase all of the subscriptions on the device.
+ *
+ * <p>This is intended to be used for device resets. As such, the reset should be performed even
+ * if an active SIM must be deactivated in order to access the eUICC.
+ *
+ * @param slotId ID of the SIM slot to use for the operation. This is currently not populated
+ * but is here to future-proof the APIs.
+ * @return the result of the erase operation.
+ * @see android.telephony.euicc.EuiccManager#eraseSubscriptions
+ */
+ public abstract EraseResult onEraseSubscriptions(int slotId);
+
+ /**
* Wrapper around IEuiccService that forwards calls to implementations of {@link EuiccService}.
*/
private class IEuiccServiceWrapper extends IEuiccService.Stub {
@@ -172,7 +268,7 @@
public void downloadSubscription(int slotId, DownloadableSubscription subscription,
boolean switchAfterDownload, boolean forceDeactivateSim,
IDownloadSubscriptionCallback callback) {
- DownloadResult result = EuiccService.this.downloadSubscription(
+ DownloadResult result = EuiccService.this.onDownloadSubscription(
slotId, subscription, switchAfterDownload, forceDeactivateSim);
try {
callback.onComplete(result);
@@ -197,7 +293,7 @@
boolean forceDeactivateSim,
IGetDownloadableSubscriptionMetadataCallback callback) {
GetDownloadableSubscriptionMetadataResult result =
- EuiccService.this.getDownloadableSubscriptionMetadata(
+ EuiccService.this.onGetDownloadableSubscriptionMetadata(
slotId, subscription, forceDeactivateSim);
try {
callback.onComplete(result);
@@ -205,5 +301,84 @@
// Can't communicate with the phone process; ignore.
}
}
+
+ @Override
+ public void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim,
+ IGetDefaultDownloadableSubscriptionListCallback callback) {
+ GetDefaultDownloadableSubscriptionListResult result =
+ EuiccService.this.onGetDefaultDownloadableSubscriptionList(
+ slotId, forceDeactivateSim);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void getEuiccProfileInfoList(int slotId, IGetEuiccProfileInfoListCallback callback) {
+ GetEuiccProfileInfoListResult result =
+ EuiccService.this.onGetEuiccProfileInfoList(slotId);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void getEuiccInfo(int slotId, IGetEuiccInfoCallback callback) {
+ EuiccInfo euiccInfo = EuiccService.this.onGetEuiccInfo(slotId);
+ try {
+ callback.onSuccess(euiccInfo);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void deleteSubscription(int slotId, String iccid,
+ IDeleteSubscriptionCallback callback) {
+ DeleteResult result = EuiccService.this.onDeleteSubscription(slotId, iccid);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
+ ISwitchToSubscriptionCallback callback) {
+ SwitchResult result =
+ EuiccService.this.onSwitchToSubscription(slotId, iccid, forceDeactivateSim);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void updateSubscriptionNickname(int slotId, String iccid, String nickname,
+ IUpdateSubscriptionNicknameCallback callback) {
+ UpdateNicknameResult result =
+ EuiccService.this.onUpdateSubscriptionNickname(slotId, iccid, nickname);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
+
+ @Override
+ public void eraseSubscriptions(int slotId, IEraseSubscriptionsCallback callback) {
+ EraseResult result = EuiccService.this.onEraseSubscriptions(slotId);
+ try {
+ callback.onComplete(result);
+ } catch (RemoteException e) {
+ // Can't communicate with the phone process; ignore.
+ }
+ }
}
}
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
new file mode 100644
index 0000000..c2636a1
--- /dev/null
+++ b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable GetDefaultDownloadableSubscriptionListResult;
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
new file mode 100644
index 0000000..95569b2
--- /dev/null
+++ b/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.euicc.DownloadableSubscription;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onGetDefaultDownloadableSubscriptionList} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class GetDefaultDownloadableSubscriptionListResult implements Parcelable {
+
+ public static final Creator<GetDefaultDownloadableSubscriptionListResult> CREATOR =
+ new Creator<GetDefaultDownloadableSubscriptionListResult>() {
+ @Override
+ public GetDefaultDownloadableSubscriptionListResult createFromParcel(Parcel in) {
+ return new GetDefaultDownloadableSubscriptionListResult(in);
+ }
+
+ @Override
+ public GetDefaultDownloadableSubscriptionListResult[] newArray(int size) {
+ return new GetDefaultDownloadableSubscriptionListResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ RESULT_MUST_DEACTIVATE_SIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_MUST_DEACTIVATE_SIM = 1;
+ public static final int RESULT_GENERIC_ERROR = 2;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /**
+ * The available {@link DownloadableSubscription}s (with filled-in metadata).
+ *
+ * <p>Only non-null if {@link #result} is {@link #RESULT_OK}.
+ */
+ @Nullable
+ public final DownloadableSubscription[] subscriptions;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private GetDefaultDownloadableSubscriptionListResult(int result,
+ @Nullable DownloadableSubscription[] subscriptions, int detailedCode) {
+ this.result = result;
+ this.subscriptions = subscriptions;
+ this.detailedCode = detailedCode;
+ }
+
+ private GetDefaultDownloadableSubscriptionListResult(Parcel in) {
+ this.result = in.readInt();
+ this.subscriptions = in.createTypedArray(DownloadableSubscription.CREATOR);
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeTypedArray(subscriptions, flags);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the list operation was successful. */
+ public static GetDefaultDownloadableSubscriptionListResult success(
+ DownloadableSubscription[] subscriptions) {
+ return new GetDefaultDownloadableSubscriptionListResult(RESULT_OK, subscriptions,
+ 0 /* detailedCode */);
+ }
+
+ /**
+ * Return a result indicating that an active SIM must be deactivated to perform the operation.
+ */
+ public static GetDefaultDownloadableSubscriptionListResult mustDeactivateSim() {
+ return new GetDefaultDownloadableSubscriptionListResult(RESULT_MUST_DEACTIVATE_SIM,
+ null /* subscription */, 0 /* detailedCode */);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implementation-defined detailed error code for debugging purposes.
+ */
+ public static GetDefaultDownloadableSubscriptionListResult genericError(int detailedCode) {
+ return new GetDefaultDownloadableSubscriptionListResult(RESULT_GENERIC_ERROR,
+ null /* subscription */, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index ca3c159..99e7614 100644
--- a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -25,7 +25,7 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Result of a {@link EuiccService#getDownloadableSubscriptionMetadata} operation.
+ * Result of a {@link EuiccService#onGetDownloadableSubscriptionMetadata} operation.
* @hide
*
* TODO(b/35851809): Make this a SystemApi.
@@ -92,7 +92,7 @@
dest.writeInt(detailedCode);
}
- /** Return a result indicating that the download was successful. */
+ /** Return a result indicating that the lookup was successful. */
public static GetDownloadableSubscriptionMetadataResult success(
DownloadableSubscription subscription) {
return new GetDownloadableSubscriptionMetadataResult(RESULT_OK, subscription,
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
new file mode 100644
index 0000000..6003b79
--- /dev/null
+++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable GetEuiccProfileInfoListResult;
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
new file mode 100644
index 0000000..5ac10fe
--- /dev/null
+++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onGetEuiccProfileInfoList} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class GetEuiccProfileInfoListResult implements Parcelable {
+
+ public static final Creator<GetEuiccProfileInfoListResult> CREATOR =
+ new Creator<GetEuiccProfileInfoListResult>() {
+ @Override
+ public GetEuiccProfileInfoListResult createFromParcel(Parcel in) {
+ return new GetEuiccProfileInfoListResult(in);
+ }
+
+ @Override
+ public GetEuiccProfileInfoListResult[] newArray(int size) {
+ return new GetEuiccProfileInfoListResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ /** The profile list (only upon success). */
+ @Nullable
+ public final EuiccProfileInfo[] profiles;
+
+ /** Whether the eUICC is removable. */
+ public final boolean isRemovable;
+
+ private GetEuiccProfileInfoListResult(int result, int detailedCode, EuiccProfileInfo[] profiles,
+ boolean isRemovable) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ this.profiles = profiles;
+ this.isRemovable = isRemovable;
+ }
+
+ private GetEuiccProfileInfoListResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ this.profiles = in.createTypedArray(EuiccProfileInfo.CREATOR);
+ this.isRemovable = in.readBoolean();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ dest.writeTypedArray(profiles, flags);
+ dest.writeBoolean(isRemovable);
+ }
+
+ /**
+ * Return a result indicating that the listing was successful.
+ *
+ * @param profiles the list of profiles
+ * @param isRemovable whether the eUICC in this slot is removable. If true, the profiles
+ * returned here will only be considered accessible as long as this eUICC is present.
+ * Otherwise, they will remain accessible until the next time a response with isRemovable
+ * set to false is returned.
+ */
+ public static GetEuiccProfileInfoListResult success(
+ EuiccProfileInfo[] profiles, boolean isRemovable) {
+ return new GetEuiccProfileInfoListResult(
+ RESULT_OK, 0 /* detailedCode */, profiles, isRemovable);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implementation-defined detailed error code for debugging purposes.
+ * @param isRemovable whether the eUICC in this slot is removable. If true, only removable
+ * profiles will be made inaccessible. Otherwise, all embedded profiles will be
+ * considered inaccessible.
+ */
+ public static GetEuiccProfileInfoListResult genericError(
+ int detailedCode, boolean isRemovable) {
+ return new GetEuiccProfileInfoListResult(
+ RESULT_GENERIC_ERROR, detailedCode, null /* profiles */, isRemovable);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl b/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
new file mode 100644
index 0000000..224cbd3
--- /dev/null
+++ b/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.DeleteResult;
+
+/** @hide */
+oneway interface IDeleteSubscriptionCallback {
+ void onComplete(in DeleteResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl b/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
new file mode 100644
index 0000000..aa70e76
--- /dev/null
+++ b/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.EraseResult;
+
+/** @hide */
+oneway interface IEraseSubscriptionsCallback {
+ void onComplete(in EraseResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/core/java/android/service/euicc/IEuiccService.aidl
index 3658d9a..18ea915 100644
--- a/core/java/android/service/euicc/IEuiccService.aidl
+++ b/core/java/android/service/euicc/IEuiccService.aidl
@@ -16,9 +16,16 @@
package android.service.euicc;
+import android.service.euicc.IDeleteSubscriptionCallback;
import android.service.euicc.IDownloadSubscriptionCallback;
+import android.service.euicc.IEraseSubscriptionsCallback;
+import android.service.euicc.IGetDefaultDownloadableSubscriptionListCallback;
import android.service.euicc.IGetDownloadableSubscriptionMetadataCallback;
import android.service.euicc.IGetEidCallback;
+import android.service.euicc.IGetEuiccInfoCallback;
+import android.service.euicc.IGetEuiccProfileInfoListCallback;
+import android.service.euicc.ISwitchToSubscriptionCallback;
+import android.service.euicc.IUpdateSubscriptionNicknameCallback;
import android.telephony.euicc.DownloadableSubscription;
/** @hide */
@@ -29,4 +36,14 @@
void getDownloadableSubscriptionMetadata(int slotId, in DownloadableSubscription subscription,
boolean forceDeactivateSim, in IGetDownloadableSubscriptionMetadataCallback callback);
void getEid(int slotId, in IGetEidCallback callback);
+ void getEuiccProfileInfoList(int slotId, in IGetEuiccProfileInfoListCallback callback);
+ void getDefaultDownloadableSubscriptionList(int slotId, boolean forceDeactivateSim,
+ in IGetDefaultDownloadableSubscriptionListCallback callback);
+ void getEuiccInfo(int slotId, in IGetEuiccInfoCallback callback);
+ void deleteSubscription(int slotId, String iccid, in IDeleteSubscriptionCallback callback);
+ void switchToSubscription(int slotId, String iccid, boolean forceDeactivateSim,
+ in ISwitchToSubscriptionCallback callback);
+ void updateSubscriptionNickname(int slotId, String iccid, String nickname,
+ in IUpdateSubscriptionNicknameCallback callback);
+ void eraseSubscriptions(int slotId, in IEraseSubscriptionsCallback callback);
}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl b/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
new file mode 100644
index 0000000..0c5a0c6
--- /dev/null
+++ b/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.GetDefaultDownloadableSubscriptionListResult;
+
+/** @hide */
+oneway interface IGetDefaultDownloadableSubscriptionListCallback {
+ void onComplete(in GetDefaultDownloadableSubscriptionListResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl b/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl
new file mode 100644
index 0000000..6d28148
--- /dev/null
+++ b/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.telephony.euicc.EuiccInfo;
+
+/** @hide */
+oneway interface IGetEuiccInfoCallback {
+ void onSuccess(in EuiccInfo euiccInfo);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl b/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
new file mode 100644
index 0000000..761ec1f
--- /dev/null
+++ b/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.GetEuiccProfileInfoListResult;
+
+/** @hide */
+oneway interface IGetEuiccProfileInfoListCallback {
+ void onComplete(in GetEuiccProfileInfoListResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl b/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
new file mode 100644
index 0000000..970adcd
--- /dev/null
+++ b/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.SwitchResult;
+
+/** @hide */
+oneway interface ISwitchToSubscriptionCallback {
+ void onComplete(in SwitchResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl b/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
new file mode 100644
index 0000000..439759d
--- /dev/null
+++ b/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+import android.service.euicc.UpdateNicknameResult;
+
+/** @hide */
+oneway interface IUpdateSubscriptionNicknameCallback {
+ void onComplete(in UpdateNicknameResult result);
+}
\ No newline at end of file
diff --git a/core/java/android/service/euicc/SwitchResult.aidl b/core/java/android/service/euicc/SwitchResult.aidl
new file mode 100644
index 0000000..eb706a5
--- /dev/null
+++ b/core/java/android/service/euicc/SwitchResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable SwitchResult;
diff --git a/core/java/android/service/euicc/SwitchResult.java b/core/java/android/service/euicc/SwitchResult.java
new file mode 100644
index 0000000..f5dc4d3
--- /dev/null
+++ b/core/java/android/service/euicc/SwitchResult.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onSwitchToSubscription} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class SwitchResult implements Parcelable {
+
+ public static final Creator<SwitchResult> CREATOR = new Creator<SwitchResult>() {
+ @Override
+ public SwitchResult createFromParcel(Parcel in) {
+ return new SwitchResult(in);
+ }
+
+ @Override
+ public SwitchResult[] newArray(int size) {
+ return new SwitchResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ RESULT_MUST_DEACTIVATE_SIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+ public static final int RESULT_MUST_DEACTIVATE_SIM = 2;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private SwitchResult(int result, int detailedCode) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ }
+
+ private SwitchResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the switch was successful. */
+ public static SwitchResult success() {
+ return new SwitchResult(RESULT_OK, 0);
+ }
+
+ /**
+ * Return a result indicating that an active SIM must be deactivated to perform the operation.
+ */
+ public static SwitchResult mustDeactivateSim() {
+ return new SwitchResult(RESULT_MUST_DEACTIVATE_SIM, 0);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implemenation-defined detailed error code for debugging purposes.
+ */
+ public static SwitchResult genericError(int detailedCode) {
+ return new SwitchResult(RESULT_GENERIC_ERROR, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/service/euicc/UpdateNicknameResult.aidl b/core/java/android/service/euicc/UpdateNicknameResult.aidl
new file mode 100644
index 0000000..08b8491
--- /dev/null
+++ b/core/java/android/service/euicc/UpdateNicknameResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.euicc;
+
+parcelable UpdateNicknameResult;
diff --git a/core/java/android/service/euicc/UpdateNicknameResult.java b/core/java/android/service/euicc/UpdateNicknameResult.java
new file mode 100644
index 0000000..d871fc8
--- /dev/null
+++ b/core/java/android/service/euicc/UpdateNicknameResult.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.euicc;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Result of a {@link EuiccService#onUpdateSubscriptionNickname} operation.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+public final class UpdateNicknameResult implements Parcelable {
+
+ public static final Creator<UpdateNicknameResult> CREATOR =
+ new Creator<UpdateNicknameResult>() {
+ @Override
+ public UpdateNicknameResult createFromParcel(Parcel in) {
+ return new UpdateNicknameResult(in);
+ }
+
+ @Override
+ public UpdateNicknameResult[] newArray(int size) {
+ return new UpdateNicknameResult[size];
+ }
+ };
+
+ /** @hide */
+ @IntDef({
+ RESULT_OK,
+ RESULT_GENERIC_ERROR,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ public static final int RESULT_OK = 0;
+ public static final int RESULT_GENERIC_ERROR = 1;
+
+ /** Result of the operation - one of the RESULT_* constants. */
+ public final @ResultCode int result;
+
+ /** Implementation-defined detailed error code in case of a failure not covered here. */
+ public final int detailedCode;
+
+ private UpdateNicknameResult(int result, int detailedCode) {
+ this.result = result;
+ this.detailedCode = detailedCode;
+ }
+
+ private UpdateNicknameResult(Parcel in) {
+ this.result = in.readInt();
+ this.detailedCode = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(result);
+ dest.writeInt(detailedCode);
+ }
+
+ /** Return a result indicating that the update was successful. */
+ public static UpdateNicknameResult success() {
+ return new UpdateNicknameResult(RESULT_OK, 0);
+ }
+
+ /**
+ * Return a result indicating that an error occurred for which no other more specific error
+ * code has been defined.
+ *
+ * @param detailedCode an implemenation-defined detailed error code for debugging purposes.
+ */
+ public static UpdateNicknameResult genericError(int detailedCode) {
+ return new UpdateNicknameResult(RESULT_GENERIC_ERROR, detailedCode);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 585f882..3baadd4 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1943,6 +1943,16 @@
return charSequence;
}
+ /**
+ * Prepends {@code start} and appends {@code end} to a given {@link StringBuilder}
+ *
+ * @hide
+ */
+ public static void wrap(StringBuilder builder, String start, String end) {
+ builder.insert(0, start);
+ builder.append(end);
+ }
+
private static Object sLock = new Object();
private static char[] sTemp = null;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 0e06cd3..f987e4e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -639,6 +639,11 @@
}
}
+ Object lastContext = mConstructorArgs[0];
+ if (mConstructorArgs[0] == null) {
+ // Fill in the context if not already within inflation.
+ mConstructorArgs[0] = mContext;
+ }
Object[] args = mConstructorArgs;
args[1] = attrs;
@@ -648,6 +653,7 @@
final ViewStub viewStub = (ViewStub) view;
viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
}
+ mConstructorArgs[0] = lastContext;
return view;
} catch (NoSuchMethodException e) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2ade9b5..2c33b60 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -245,6 +245,7 @@
super.onAttachedToWindow();
getViewRootImpl().addWindowStoppedCallback(this);
+ mWindowStopped = false;
mParent.requestTransparentRegion(this);
mViewVisibility = getVisibility() == VISIBLE;
@@ -855,7 +856,7 @@
*/
@Deprecated
public void setWindowType(int type) {
- if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ if (getContext().getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
throw new UnsupportedOperationException(
"SurfaceView#setWindowType() has never been a public API.");
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c66bf874..4402fb1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -29,6 +29,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.Trace;
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
@@ -188,6 +189,11 @@
public static final String DEBUG_SHOW_NON_RECTANGULAR_CLIP_PROPERTY =
"debug.hwui.show_non_rect_clip";
+ static {
+ // Try to check OpenGL support early if possible.
+ isAvailable();
+ }
+
/**
* A process can set this flag to false to prevent the use of threaded
* rendering.
@@ -227,8 +233,7 @@
sTrimForeground = true;
}
- private static native boolean nSupportsOpenGL();
- private static boolean sSupportsOpenGL = nSupportsOpenGL();
+ private static Boolean sSupportsOpenGL;
/**
* Indicates whether threaded rendering is available under any form for
@@ -238,7 +243,24 @@
* false otherwise
*/
public static boolean isAvailable() {
- return sSupportsOpenGL;
+ if (sSupportsOpenGL != null) {
+ return sSupportsOpenGL.booleanValue();
+ }
+ if (SystemProperties.getInt("ro.kernel.qemu", 0) == 0) {
+ // Device is not an emulator.
+ sSupportsOpenGL = true;
+ return true;
+ }
+ int qemu_gles = SystemProperties.getInt("qemu.gles", -1);
+ if (qemu_gles == -1) {
+ // In this case, the value of the qemu.gles property is not ready
+ // because the SurfaceFlinger service may not start at this point.
+ return false;
+ }
+ // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
+ // enabled, 0 otherwise. On old emulator versions it will be undefined.
+ sSupportsOpenGL = qemu_gles > 0;
+ return sSupportsOpenGL.booleanValue();
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 64e8263..a59e0b5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2770,6 +2770,7 @@
* 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
* 1 PFLAG3_TEMPORARY_DETACH
* 1 PFLAG3_NO_REVEAL_ON_FOCUS
+ * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
* |-------|-------|-------|-------|
*/
@@ -2858,14 +2859,6 @@
*/
static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
- /**
- * Flag indicating that when layout is completed we should notify
- * that the view was entered for autofill purposes. To minimize
- * showing autofill for views not visible to the user we evaluate
- * user visibility which cannot be done until the view is laid out.
- */
- static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x4000;
-
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -3050,6 +3043,14 @@
*/
private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
+ /**
+ * Flag indicating that when layout is completed we should notify
+ * that the view was entered for autofill purposes. To minimize
+ * showing autofill for views not visible to the user we evaluate
+ * user visibility which cannot be done until the view is laid out.
+ */
+ static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
+
/* End of masks for mPrivateFlags3 */
/**
@@ -20505,6 +20506,9 @@
* @throws IllegalStateException if the drawable could not be found.
*/
@Nullable private Drawable getAutofilledDrawable() {
+ if (mAttachInfo == null) {
+ return null;
+ }
// Lazily load the isAutofilled drawable.
if (mAttachInfo.mAutofilledDrawable == null) {
Context rootContext = getRootView().getContext();
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index cc11cb8..572e69b 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -402,7 +402,7 @@
* descendants has changed and that the structure of the subtree is
* different.
* @param child The direct child whose subtree has changed.
- * @param source The descendant view that changed.
+ * @param source The descendant view that changed. May not be {@code null}.
* @param changeType A bit mask of the types of changes that occurred. One
* or more of:
* <ul>
@@ -412,7 +412,8 @@
* <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
* </ul>
*/
- public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType);
+ public void notifySubtreeAccessibilityStateChanged(
+ View child, @NonNull View source, int changeType);
/**
* Tells if this view parent can resolve the layout direction.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1f13220..28ded55 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -98,6 +98,7 @@
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.PhoneFallbackEventHandler;
+import com.android.internal.util.Preconditions;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.SurfaceCallbackHelper;
@@ -1560,16 +1561,6 @@
host.dispatchApplyWindowInsets(getWindowInsets(true /* forceConstruct */));
}
- /**
- * @return the last content insets for use in adjusting the source hint rect for the
- * picture-in-picture transition.
- *
- * @hide
- */
- public Rect getLastContentInsets() {
- return mAttachInfo.mContentInsets;
- }
-
private static boolean shouldUseDisplaySize(final WindowManager.LayoutParams lp) {
return lp.type == TYPE_STATUS_BAR_PANEL
|| lp.type == TYPE_INPUT_METHOD
@@ -2410,6 +2401,9 @@
}
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
+ if (mView == null) {
+ return;
+ }
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -7195,7 +7189,7 @@
@Override
public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
- postSendWindowContentChangedCallback(source, changeType);
+ postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
}
@Override
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index e4d4e7b..0973d0a 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -334,7 +334,7 @@
*/
ViewTreeObserver(Context context) {
sIllegalOnDrawModificationIsFatal =
- context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.N_MR1;
+ context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O;
}
/**
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 030c78b..a326327 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -589,6 +589,13 @@
* Notifies window manager that {@link #isKeyguardTrustedLw} has changed.
*/
void notifyKeyguardTrustedChanged();
+
+ /**
+ * Notifies the window manager that screen is being turned off.
+ *
+ * @param listener callback to call when display can be turned off
+ */
+ void screenTurningOff(ScreenOffListener listener);
}
public interface PointerEventListener {
@@ -1267,6 +1274,15 @@
public void screenTurnedOn();
/**
+ * Called when the display would like to be turned off. This gives policy a chance to do some
+ * things before the display power state is actually changed to off.
+ *
+ * @param screenOffListener Must be called to tell that the display power state can actually be
+ * changed now after policy has done its work.
+ */
+ public void screenTurningOff(ScreenOffListener screenOffListener);
+
+ /**
* Called when the device has turned the screen off.
*/
public void screenTurnedOff();
@@ -1276,6 +1292,13 @@
}
/**
+ * See {@link #screenTurnedOff}
+ */
+ public interface ScreenOffListener {
+ void onScreenOff();
+ }
+
+ /**
* Return whether the default display is on and not blocked by a black surface.
*/
public boolean isScreenOn();
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 8a13c0c..341386c 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -21,6 +21,8 @@
import android.text.TextUtils;
import android.util.Pools.SynchronizedPool;
+import com.android.internal.util.BitUtils;
+
import java.util.ArrayList;
import java.util.List;
@@ -852,6 +854,22 @@
return mContentChangeTypes;
}
+ private static String contentChangeTypesToString(int types) {
+ return BitUtils.flagsToString(types, AccessibilityEvent::singleContentChangeTypeToString);
+ }
+
+ private static String singleContentChangeTypeToString(int type) {
+ switch (type) {
+ case CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION: {
+ return "CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION";
+ }
+ case CONTENT_CHANGE_TYPE_SUBTREE: return "CONTENT_CHANGE_TYPE_SUBTREE";
+ case CONTENT_CHANGE_TYPE_TEXT: return "CONTENT_CHANGE_TYPE_TEXT";
+ case CONTENT_CHANGE_TYPE_UNDEFINED: return "CONTENT_CHANGE_TYPE_UNDEFINED";
+ default: return Integer.toHexString(type);
+ }
+ }
+
/**
* Sets the bit mask of node tree changes signaled by an
* {@link #TYPE_WINDOW_CONTENT_CHANGED} event.
@@ -1187,7 +1205,8 @@
builder.append(super.toString());
if (DEBUG) {
builder.append("\n");
- builder.append("; ContentChangeTypes: ").append(mContentChangeTypes);
+ builder.append("; ContentChangeTypes: ").append(
+ contentChangeTypesToString(mContentChangeTypes));
builder.append("; sourceWindowId: ").append(mSourceWindowId);
if (mSourceNode != null) {
builder.append("; mSourceNodeId: ").append(mSourceNode.getSourceNodeId());
@@ -1240,183 +1259,13 @@
while (eventType != 0) {
final int eventTypeFlag = 1 << Integer.numberOfTrailingZeros(eventType);
eventType &= ~eventTypeFlag;
- switch (eventTypeFlag) {
- case TYPE_VIEW_CLICKED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_CLICKED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_LONG_CLICKED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_LONG_CLICKED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_SELECTED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_SELECTED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_FOCUSED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_FOCUSED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_TEXT_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_TEXT_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_WINDOW_STATE_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_WINDOW_STATE_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_HOVER_ENTER: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_HOVER_ENTER");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_HOVER_EXIT: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_HOVER_EXIT");
- eventTypeCount++;
- } break;
- case TYPE_NOTIFICATION_STATE_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_NOTIFICATION_STATE_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_TOUCH_EXPLORATION_GESTURE_START: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_TOUCH_EXPLORATION_GESTURE_START");
- eventTypeCount++;
- } break;
- case TYPE_TOUCH_EXPLORATION_GESTURE_END: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_TOUCH_EXPLORATION_GESTURE_END");
- eventTypeCount++;
- } break;
- case TYPE_WINDOW_CONTENT_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_WINDOW_CONTENT_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_TEXT_SELECTION_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_TEXT_SELECTION_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_SCROLLED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_SCROLLED");
- eventTypeCount++;
- } break;
- case TYPE_ANNOUNCEMENT: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_ANNOUNCEMENT");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_ACCESSIBILITY_FOCUSED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY");
- eventTypeCount++;
- } break;
- case TYPE_GESTURE_DETECTION_START: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_GESTURE_DETECTION_START");
- eventTypeCount++;
- } break;
- case TYPE_GESTURE_DETECTION_END: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_GESTURE_DETECTION_END");
- eventTypeCount++;
- } break;
- case TYPE_TOUCH_INTERACTION_START: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_TOUCH_INTERACTION_START");
- eventTypeCount++;
- } break;
- case TYPE_TOUCH_INTERACTION_END: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_TOUCH_INTERACTION_END");
- eventTypeCount++;
- } break;
- case TYPE_WINDOWS_CHANGED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_WINDOWS_CHANGED");
- eventTypeCount++;
- } break;
- case TYPE_VIEW_CONTEXT_CLICKED: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_VIEW_CONTEXT_CLICKED");
- eventTypeCount++;
- } break;
- case TYPE_ASSIST_READING_CONTEXT: {
- if (eventTypeCount > 0) {
- builder.append(", ");
- }
- builder.append("TYPE_ASSIST_READING_CONTEXT");
- eventTypeCount++;
- } break;
+
+ if (eventTypeCount > 0) {
+ builder.append(", ");
}
+ builder.append(singleEventTypeToString(eventTypeFlag));
+
+ eventTypeCount++;
}
if (eventTypeCount > 1) {
builder.insert(0, '[');
@@ -1425,6 +1274,43 @@
return builder.toString();
}
+ private static String singleEventTypeToString(int eventType) {
+ switch (eventType) {
+ case TYPE_VIEW_CLICKED: return "TYPE_VIEW_CLICKED";
+ case TYPE_VIEW_LONG_CLICKED: return "TYPE_VIEW_LONG_CLICKED";
+ case TYPE_VIEW_SELECTED: return "TYPE_VIEW_SELECTED";
+ case TYPE_VIEW_FOCUSED: return "TYPE_VIEW_FOCUSED";
+ case TYPE_VIEW_TEXT_CHANGED: return "TYPE_VIEW_TEXT_CHANGED";
+ case TYPE_WINDOW_STATE_CHANGED: return "TYPE_WINDOW_STATE_CHANGED";
+ case TYPE_VIEW_HOVER_ENTER: return "TYPE_VIEW_HOVER_ENTER";
+ case TYPE_VIEW_HOVER_EXIT: return "TYPE_VIEW_HOVER_EXIT";
+ case TYPE_NOTIFICATION_STATE_CHANGED: return "TYPE_NOTIFICATION_STATE_CHANGED";
+ case TYPE_TOUCH_EXPLORATION_GESTURE_START: {
+ return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
+ }
+ case TYPE_TOUCH_EXPLORATION_GESTURE_END: return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
+ case TYPE_WINDOW_CONTENT_CHANGED: return "TYPE_WINDOW_CONTENT_CHANGED";
+ case TYPE_VIEW_TEXT_SELECTION_CHANGED: return "TYPE_VIEW_TEXT_SELECTION_CHANGED";
+ case TYPE_VIEW_SCROLLED: return "TYPE_VIEW_SCROLLED";
+ case TYPE_ANNOUNCEMENT: return "TYPE_ANNOUNCEMENT";
+ case TYPE_VIEW_ACCESSIBILITY_FOCUSED: return "TYPE_VIEW_ACCESSIBILITY_FOCUSED";
+ case TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+ return "TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED";
+ }
+ case TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY: {
+ return "TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY";
+ }
+ case TYPE_GESTURE_DETECTION_START: return "TYPE_GESTURE_DETECTION_START";
+ case TYPE_GESTURE_DETECTION_END: return "TYPE_GESTURE_DETECTION_END";
+ case TYPE_TOUCH_INTERACTION_START: return "TYPE_TOUCH_INTERACTION_START";
+ case TYPE_TOUCH_INTERACTION_END: return "TYPE_TOUCH_INTERACTION_END";
+ case TYPE_WINDOWS_CHANGED: return "TYPE_WINDOWS_CHANGED";
+ case TYPE_VIEW_CONTEXT_CLICKED: return "TYPE_VIEW_CONTEXT_CLICKED";
+ case TYPE_ASSIST_READING_CONTEXT: return "TYPE_ASSIST_READING_CONTEXT";
+ default: return Integer.toHexString(eventType);
+ }
+ }
+
/**
* @see Parcelable.Creator
*/
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 5148d92..3bf8d27 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -16,6 +16,9 @@
package android.view.accessibility;
+import static com.android.internal.util.BitUtils.bitAt;
+import static com.android.internal.util.BitUtils.isBitSet;
+
import static java.util.Collections.EMPTY_LIST;
import android.accessibilityservice.AccessibilityService;
@@ -41,10 +44,12 @@
import android.view.View;
import com.android.internal.R;
+import com.android.internal.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -636,7 +641,6 @@
* Bits that provide the id of a virtual descendant of a view.
*/
private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L;
-
/**
* Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a
* virtual descendant of a view. Such a descendant does not exist in the view
@@ -692,6 +696,8 @@
private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
new SynchronizedPool<>(MAX_POOL_SIZE);
+ private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo();
+
private boolean mSealed;
// Data.
@@ -1068,11 +1074,7 @@
* Gets the actions that can be performed on the node.
*/
public List<AccessibilityAction> getActionList() {
- if (mActions == null) {
- return Collections.emptyList();
- }
-
- return mActions;
+ return CollectionUtils.emptyIfNull(mActions);
}
/**
@@ -3050,127 +3052,227 @@
*/
@Override
public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeInt(isSealed() ? 1 : 0);
- parcel.writeLong(mSourceNodeId);
- parcel.writeInt(mWindowId);
- parcel.writeLong(mParentNodeId);
- parcel.writeLong(mLabelForId);
- parcel.writeLong(mLabeledById);
- parcel.writeLong(mTraversalBefore);
- parcel.writeLong(mTraversalAfter);
-
- parcel.writeInt(mConnectionId);
-
- final LongArray childIds = mChildNodeIds;
- if (childIds == null) {
- parcel.writeInt(0);
- } else {
- final int childIdsSize = childIds.size();
- parcel.writeInt(childIdsSize);
- for (int i = 0; i < childIdsSize; i++) {
- parcel.writeLong(childIds.get(i));
- }
+ // Write bit set of indices of fields with values differing from default
+ long nonDefaultFields = 0;
+ int fieldIndex = 0; // index of the current field
+ if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) {
+ nonDefaultFields |= bitAt(fieldIndex);
}
+ fieldIndex++;
+ if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mMovementGranularities != DEFAULT.mMovementGranularities) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mHintText, DEFAULT.mHintText)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (mTextSelectionStart != DEFAULT.mTextSelectionStart) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex);
+ fieldIndex++;
+ if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ fieldIndex++;
+ if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
+ int totalFields = fieldIndex;
+ parcel.writeLong(nonDefaultFields);
- parcel.writeInt(mBoundsInParent.top);
- parcel.writeInt(mBoundsInParent.bottom);
- parcel.writeInt(mBoundsInParent.left);
- parcel.writeInt(mBoundsInParent.right);
+ fieldIndex = 0;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter);
- parcel.writeInt(mBoundsInScreen.top);
- parcel.writeInt(mBoundsInScreen.bottom);
- parcel.writeInt(mBoundsInScreen.left);
- parcel.writeInt(mBoundsInScreen.right);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId);
- if (mActions != null && !mActions.isEmpty()) {
- final int actionCount = mActions.size();
-
- int nonLegacyActionCount = 0;
- int defaultLegacyStandardActions = 0;
- for (int i = 0; i < actionCount; i++) {
- AccessibilityAction action = mActions.get(i);
- if (isDefaultLegacyStandardAction(action)) {
- defaultLegacyStandardActions |= action.getId();
- } else {
- nonLegacyActionCount++;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ final LongArray childIds = mChildNodeIds;
+ if (childIds == null) {
+ parcel.writeInt(0);
+ } else {
+ final int childIdsSize = childIds.size();
+ parcel.writeInt(childIdsSize);
+ for (int i = 0; i < childIdsSize; i++) {
+ parcel.writeLong(childIds.get(i));
}
}
- parcel.writeInt(defaultLegacyStandardActions);
- parcel.writeInt(nonLegacyActionCount);
+ }
- for (int i = 0; i < actionCount; i++) {
- AccessibilityAction action = mActions.get(i);
- if (!isDefaultLegacyStandardAction(action)) {
- parcel.writeInt(action.getId());
- parcel.writeCharSequence(action.getLabel());
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeInt(mBoundsInParent.top);
+ parcel.writeInt(mBoundsInParent.bottom);
+ parcel.writeInt(mBoundsInParent.left);
+ parcel.writeInt(mBoundsInParent.right);
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeInt(mBoundsInScreen.top);
+ parcel.writeInt(mBoundsInScreen.bottom);
+ parcel.writeInt(mBoundsInScreen.left);
+ parcel.writeInt(mBoundsInScreen.right);
+ }
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ if (mActions != null && !mActions.isEmpty()) {
+ final int actionCount = mActions.size();
+
+ int nonLegacyActionCount = 0;
+ int defaultLegacyStandardActions = 0;
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (isDefaultLegacyStandardAction(action)) {
+ defaultLegacyStandardActions |= action.getId();
+ } else {
+ nonLegacyActionCount++;
+ }
}
+ parcel.writeInt(defaultLegacyStandardActions);
+ parcel.writeInt(nonLegacyActionCount);
+
+ for (int i = 0; i < actionCount; i++) {
+ AccessibilityAction action = mActions.get(i);
+ if (!isDefaultLegacyStandardAction(action)) {
+ parcel.writeInt(action.getId());
+ parcel.writeCharSequence(action.getLabel());
+ }
+ }
+ } else {
+ parcel.writeInt(0);
+ parcel.writeInt(0);
}
- } else {
- parcel.writeInt(0);
- parcel.writeInt(0);
}
- parcel.writeInt(mMaxTextLength);
- parcel.writeInt(mMovementGranularities);
- parcel.writeInt(mBooleanProperties);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties);
- parcel.writeCharSequence(mPackageName);
- parcel.writeCharSequence(mClassName);
- parcel.writeCharSequence(mText);
- parcel.writeCharSequence(mHintText);
- parcel.writeCharSequence(mError);
- parcel.writeCharSequence(mContentDescription);
- parcel.writeString(mViewIdResourceName);
-
- parcel.writeInt(mTextSelectionStart);
- parcel.writeInt(mTextSelectionEnd);
- parcel.writeInt(mInputType);
- parcel.writeInt(mLiveRegion);
- parcel.writeInt(mDrawingOrderInParent);
- if (mExtraDataKeys != null) {
- parcel.writeInt(1);
- parcel.writeStringList(mExtraDataKeys);
- } else {
- parcel.writeInt(0);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ parcel.writeCharSequence(mContentDescription);
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName);
- if (mExtras != null) {
- parcel.writeInt(1);
- parcel.writeBundle(mExtras);
- } else {
- parcel.writeInt(0);
- }
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent);
- if (mRangeInfo != null) {
- parcel.writeInt(1);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys);
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras);
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
parcel.writeInt(mRangeInfo.getType());
parcel.writeFloat(mRangeInfo.getMin());
parcel.writeFloat(mRangeInfo.getMax());
parcel.writeFloat(mRangeInfo.getCurrent());
- } else {
- parcel.writeInt(0);
}
- if (mCollectionInfo != null) {
- parcel.writeInt(1);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
parcel.writeInt(mCollectionInfo.getRowCount());
parcel.writeInt(mCollectionInfo.getColumnCount());
parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
parcel.writeInt(mCollectionInfo.getSelectionMode());
- } else {
- parcel.writeInt(0);
}
- if (mCollectionItemInfo != null) {
- parcel.writeInt(1);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
parcel.writeInt(mCollectionItemInfo.getRowIndex());
parcel.writeInt(mCollectionItemInfo.getRowSpan());
parcel.writeInt(mCollectionItemInfo.getColumnIndex());
parcel.writeInt(mCollectionItemInfo.getColumnSpan());
parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
- } else {
- parcel.writeInt(0);
+ }
+
+ if (DEBUG) {
+ fieldIndex--;
+ if (totalFields != fieldIndex) {
+ throw new IllegalStateException("Number of fields mismatch: " + totalFields
+ + " vs " + fieldIndex);
+ }
}
// Since instances of this class are fetched via synchronous i.e. blocking
@@ -3203,12 +3305,12 @@
mContentDescription = other.mContentDescription;
mViewIdResourceName = other.mViewIdResourceName;
+ if (mActions != null) mActions.clear();
final ArrayList<AccessibilityAction> otherActions = other.mActions;
if (otherActions != null && otherActions.size() > 0) {
if (mActions == null) {
mActions = new ArrayList(otherActions);
} else {
- mActions.clear();
mActions.addAll(other.mActions);
}
}
@@ -3217,12 +3319,13 @@
mMaxTextLength = other.mMaxTextLength;
mMovementGranularities = other.mMovementGranularities;
+
+ if (mChildNodeIds != null) mChildNodeIds.clear();
final LongArray otherChildNodeIds = other.mChildNodeIds;
if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
if (mChildNodeIds == null) {
mChildNodeIds = otherChildNodeIds.clone();
} else {
- mChildNodeIds.clear();
mChildNodeIds.addAll(otherChildNodeIds);
}
}
@@ -3232,17 +3335,18 @@
mInputType = other.mInputType;
mLiveRegion = other.mLiveRegion;
mDrawingOrderInParent = other.mDrawingOrderInParent;
+
mExtraDataKeys = other.mExtraDataKeys;
- if (other.mExtras != null) {
- mExtras = new Bundle(other.mExtras);
- } else {
- mExtras = null;
- }
+ mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
+
+ if (mRangeInfo != null) mRangeInfo.recycle();
mRangeInfo = (other.mRangeInfo != null)
? RangeInfo.obtain(other.mRangeInfo) : null;
+ if (mCollectionInfo != null) mCollectionInfo.recycle();
mCollectionInfo = (other.mCollectionInfo != null)
? CollectionInfo.obtain(other.mCollectionInfo) : null;
+ if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = (other.mCollectionItemInfo != null)
? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
}
@@ -3253,103 +3357,117 @@
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
*/
private void initFromParcel(Parcel parcel) {
- final boolean sealed = (parcel.readInt() == 1);
- mSourceNodeId = parcel.readLong();
- mWindowId = parcel.readInt();
- mParentNodeId = parcel.readLong();
- mLabelForId = parcel.readLong();
- mLabeledById = parcel.readLong();
- mTraversalBefore = parcel.readLong();
- mTraversalAfter = parcel.readLong();
+ // Bit mask of non-default-valued field indices
+ long nonDefaultFields = parcel.readLong();
+ int fieldIndex = 0;
+ final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++)
+ ? (parcel.readInt() == 1)
+ : DEFAULT.mSealed;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong();
- mConnectionId = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt();
- final int childrenSize = parcel.readInt();
- if (childrenSize <= 0) {
- mChildNodeIds = null;
- } else {
- mChildNodeIds = new LongArray(childrenSize);
- for (int i = 0; i < childrenSize; i++) {
- final long childId = parcel.readLong();
- mChildNodeIds.add(childId);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ final int childrenSize = parcel.readInt();
+ if (childrenSize <= 0) {
+ mChildNodeIds = null;
+ } else {
+ mChildNodeIds = new LongArray(childrenSize);
+ for (int i = 0; i < childrenSize; i++) {
+ final long childId = parcel.readLong();
+ mChildNodeIds.add(childId);
+ }
}
}
- mBoundsInParent.top = parcel.readInt();
- mBoundsInParent.bottom = parcel.readInt();
- mBoundsInParent.left = parcel.readInt();
- mBoundsInParent.right = parcel.readInt();
-
- mBoundsInScreen.top = parcel.readInt();
- mBoundsInScreen.bottom = parcel.readInt();
- mBoundsInScreen.left = parcel.readInt();
- mBoundsInScreen.right = parcel.readInt();
-
- final int legacyStandardActions = parcel.readInt();
- addLegacyStandardActions(legacyStandardActions);
- final int nonLegacyActionCount = parcel.readInt();
- for (int i = 0; i < nonLegacyActionCount; i++) {
- final AccessibilityAction action = new AccessibilityAction(
- parcel.readInt(), parcel.readCharSequence());
- addActionUnchecked(action);
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mBoundsInParent.top = parcel.readInt();
+ mBoundsInParent.bottom = parcel.readInt();
+ mBoundsInParent.left = parcel.readInt();
+ mBoundsInParent.right = parcel.readInt();
}
- mMaxTextLength = parcel.readInt();
- mMovementGranularities = parcel.readInt();
- mBooleanProperties = parcel.readInt();
-
- mPackageName = parcel.readCharSequence();
- mClassName = parcel.readCharSequence();
- mText = parcel.readCharSequence();
- mHintText = parcel.readCharSequence();
- mError = parcel.readCharSequence();
- mContentDescription = parcel.readCharSequence();
- mViewIdResourceName = parcel.readString();
-
- mTextSelectionStart = parcel.readInt();
- mTextSelectionEnd = parcel.readInt();
-
- mInputType = parcel.readInt();
- mLiveRegion = parcel.readInt();
- mDrawingOrderInParent = parcel.readInt();
-
- if (parcel.readInt() == 1) {
- mExtraDataKeys = parcel.createStringArrayList();
- } else {
- mExtraDataKeys = null;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mBoundsInScreen.top = parcel.readInt();
+ mBoundsInScreen.bottom = parcel.readInt();
+ mBoundsInScreen.left = parcel.readInt();
+ mBoundsInScreen.right = parcel.readInt();
}
- if (parcel.readInt() == 1) {
- mExtras = parcel.readBundle();
- } else {
- mExtras = null;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ final int legacyStandardActions = parcel.readInt();
+ addLegacyStandardActions(legacyStandardActions);
+ final int nonLegacyActionCount = parcel.readInt();
+ for (int i = 0; i < nonLegacyActionCount; i++) {
+ final AccessibilityAction action = new AccessibilityAction(
+ parcel.readInt(), parcel.readCharSequence());
+ addActionUnchecked(action);
+ }
}
- if (parcel.readInt() == 1) {
- mRangeInfo = RangeInfo.obtain(
- parcel.readInt(),
- parcel.readFloat(),
- parcel.readFloat(),
- parcel.readFloat());
- }
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt();
- if (parcel.readInt() == 1) {
- mCollectionInfo = CollectionInfo.obtain(
- parcel.readInt(),
- parcel.readInt(),
- parcel.readInt() == 1,
- parcel.readInt());
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mContentDescription = parcel.readCharSequence();
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString();
- if (parcel.readInt() == 1) {
- mCollectionItemInfo = CollectionItemInfo.obtain(
- parcel.readInt(),
- parcel.readInt(),
- parcel.readInt(),
- parcel.readInt(),
- parcel.readInt() == 1,
- parcel.readInt() == 1);
- }
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt();
+
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt();
+ if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt();
+
+ mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++)
+ ? parcel.createStringArrayList()
+ : null;
+
+ mExtras = isBitSet(nonDefaultFields, fieldIndex++)
+ ? parcel.readBundle()
+ : null;
+
+ if (mRangeInfo != null) mRangeInfo.recycle();
+ mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++)
+ ? RangeInfo.obtain(
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readFloat())
+ : null;
+
+ if (mCollectionInfo != null) mCollectionInfo.recycle();
+ mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++)
+ ? CollectionInfo.obtain(
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt() == 1,
+ parcel.readInt())
+ : null;
+
+ if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
+ mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++)
+ ? CollectionItemInfo.obtain(
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt() == 1,
+ parcel.readInt() == 1)
+ : null;
mSealed = sealed;
}
@@ -3358,50 +3476,7 @@
* Clears the state of this instance.
*/
private void clear() {
- mSealed = false;
- mSourceNodeId = UNDEFINED_NODE_ID;
- mParentNodeId = UNDEFINED_NODE_ID;
- mLabelForId = UNDEFINED_NODE_ID;
- mLabeledById = UNDEFINED_NODE_ID;
- mTraversalBefore = UNDEFINED_NODE_ID;
- mTraversalAfter = UNDEFINED_NODE_ID;
- mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
- mConnectionId = UNDEFINED_CONNECTION_ID;
- mMaxTextLength = -1;
- mMovementGranularities = 0;
- if (mChildNodeIds != null) {
- mChildNodeIds.clear();
- }
- mBoundsInParent.set(0, 0, 0, 0);
- mBoundsInScreen.set(0, 0, 0, 0);
- mBooleanProperties = 0;
- mDrawingOrderInParent = 0;
- mExtraDataKeys = null;
- mPackageName = null;
- mClassName = null;
- mText = null;
- mHintText = null;
- mError = null;
- mContentDescription = null;
- mViewIdResourceName = null;
- removeAllActions();
- mTextSelectionStart = UNDEFINED_SELECTION_INDEX;
- mTextSelectionEnd = UNDEFINED_SELECTION_INDEX;
- mInputType = InputType.TYPE_NULL;
- mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE;
- mExtras = null;
- if (mRangeInfo != null) {
- mRangeInfo.recycle();
- mRangeInfo = null;
- }
- if (mCollectionInfo != null) {
- mCollectionInfo.recycle();
- mCollectionInfo = null;
- }
- if (mCollectionItemInfo != null) {
- mCollectionItemInfo.recycle();
- mCollectionItemInfo = null;
- }
+ init(DEFAULT);
}
private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 68c74da..39ac399 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -804,9 +804,26 @@
+ ", value=" + value + ", action=" + action + ", flags=" + flags);
}
+ boolean restartIfNecessary = (flags & FLAG_MANUAL_REQUEST) != 0;
+
try {
- mService.updateSession(mSessionId, id, bounds, value, action, flags,
- mContext.getUserId());
+ if (restartIfNecessary) {
+ final int newId = mService.updateOrRestartSession(mContext.getActivityToken(),
+ mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
+ mCallback != null, flags, mContext.getOpPackageName(), mSessionId, action);
+ if (newId != mSessionId) {
+ if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
+ mSessionId = newId;
+ final AutofillClient client = getClientLocked();
+ if (client != null) {
+ client.autofillCallbackResetableStateAvailable();
+ }
+ }
+ } else {
+ mService.updateSession(mSessionId, id, bounds, value, action, flags,
+ mContext.getUserId());
+ }
+
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index a12e956..627afa7 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -39,6 +39,9 @@
boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
void updateSession(int sessionId, in AutofillId id, in Rect bounds,
in AutofillValue value, int action, int flags, int userId);
+ int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
+ in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
+ boolean hasCallback, int flags, String packageName, int sessionId, int action);
void finishSession(int sessionId, int userId);
void cancelSession(int sessionId, int userId);
void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5f72fc7..290d811 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -624,8 +624,14 @@
return new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
case TextClassifier.TYPE_URL:
- if (!text.startsWith("https://") && !text.startsWith("http://")) {
- text = "http://" + text;
+ final String httpPrefix = "http://";
+ final String httpsPrefix = "https://";
+ if (text.toLowerCase().startsWith(httpPrefix)) {
+ text = httpPrefix + text.substring(httpPrefix.length());
+ } else if (text.toLowerCase().startsWith(httpsPrefix)) {
+ text = httpsPrefix + text.substring(httpsPrefix.length());
+ } else {
+ text = httpPrefix + text;
}
return new Intent(Intent.ACTION_VIEW, Uri.parse(text))
.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index f53b5d6..8920089 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -83,8 +83,7 @@
* supported by the current framework version.
*/
public static boolean hasCorrectTargetSdkVersion(PackageInfo packageInfo) {
- // TODO(gsennton) use Build.VERSION_CODES.O when that has been updated.
- return packageInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1;
+ return packageInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O;
}
public UserInfo getUserInfo() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 71db6b1..1b6b392 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -107,6 +107,7 @@
// error for namespace lookup
public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10;
+
private static String getWebViewPreparationErrorReason(int error) {
switch (error) {
case LIBLOAD_FAILED_WAITING_FOR_RELRO:
@@ -119,10 +120,7 @@
return "Unknown";
}
- /**
- * @hide
- */
- public static class MissingWebViewPackageException extends AndroidRuntimeException {
+ private static class MissingWebViewPackageException extends Exception {
public MissingWebViewPackageException(String message) { super(message); }
public MissingWebViewPackageException(Exception e) { super(e); }
}
@@ -184,11 +182,16 @@
return LIBLOAD_WRONG_PACKAGE_NAME;
}
- int loadNativeRet = loadNativeLibrary(clazzLoader, packageInfo);
- // If we failed waiting for relro we want to return that fact even if we successfully load
- // the relro file.
- if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
- return loadNativeRet;
+ try {
+ int loadNativeRet = loadNativeLibrary(clazzLoader, packageInfo);
+ // If we failed waiting for relro we want to return that fact even if we successfully
+ // load the relro file.
+ if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
+ return loadNativeRet;
+ } catch (MissingWebViewPackageException e) {
+ Log.e(LOGTAG, "Couldn't load native library: " + e);
+ return LIBLOAD_FAILED_TO_LOAD_LIBRARY;
+ }
}
static WebViewFactoryProvider getProvider() {
@@ -259,7 +262,8 @@
}
// Throws MissingWebViewPackageException on failure
- private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse) {
+ private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse)
+ throws MissingWebViewPackageException {
if (!chosen.packageName.equals(toUse.packageName)) {
throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+ "packageName mismatch, expected: "
@@ -285,7 +289,8 @@
* required values from the donor package. If the ApplicationInfo is for a full WebView,
* leave it alone. Throws MissingWebViewPackageException if the donor is missing.
*/
- private static void fixupStubApplicationInfo(ApplicationInfo ai, PackageManager pm) {
+ private static void fixupStubApplicationInfo(ApplicationInfo ai, PackageManager pm)
+ throws MissingWebViewPackageException {
String donorPackageName = null;
if (ai.metaData != null) {
donorPackageName = ai.metaData.getString("com.android.webview.WebViewDonorPackage");
@@ -318,7 +323,7 @@
}
}
- private static Context getWebViewContextAndSetProvider() {
+ private static Context getWebViewContextAndSetProvider() throws MissingWebViewPackageException {
Application initialApplication = AppGlobals.getInitialApplication();
try {
WebViewProviderResponse response = null;
@@ -549,10 +554,10 @@
return prepareWebViewInSystemServer(nativeLibs);
}
- // throws MissingWebViewPackageException
private static String getLoadFromApkPath(String apkPath,
String[] abiList,
- String nativeLibFileName) {
+ String nativeLibFileName)
+ throws MissingWebViewPackageException {
// Search the APK for a native library conforming to a listed ABI.
try (ZipFile z = new ZipFile(apkPath)) {
for (String abi : abiList) {
@@ -569,8 +574,8 @@
return "";
}
- // throws MissingWebViewPackageException
- private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) {
+ private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo)
+ throws MissingWebViewPackageException {
ApplicationInfo ai = packageInfo.applicationInfo;
final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
@@ -695,7 +700,8 @@
}
// Assumes that we have waited for relro creation
- private static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo) {
+ private static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo)
+ throws MissingWebViewPackageException {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index be0967f..cfd1445 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -16,7 +16,7 @@
package android.widget;
-import static android.os.Build.VERSION_CODES.N_MR1;
+import static android.os.Build.VERSION_CODES.O;
import android.annotation.Nullable;
import android.content.Context;
@@ -302,7 +302,7 @@
getTempCalendarForTime(timeInMillis);
final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion > N_MR1) {
+ if (targetSdkVersion >= O) {
if (mTempCalendar.before(mMinDate) || mTempCalendar.after(mMaxDate)) {
throw new IllegalArgumentException("timeInMillis must be between the values of "
+ "getMinDate() and getMaxDate()");
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index bb658c1..1fef7cb 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2016,7 +2016,7 @@
/**
* Asynchronously invalidates an action mode using the TextClassifier.
*/
- private void invalidateActionModeAsync() {
+ void invalidateActionModeAsync() {
getSelectionActionModeHelper().invalidateActionModeAsync();
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 59fb02d..8464c6e 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1667,32 +1667,17 @@
int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
int displayFrameBottom, boolean allowResize) {
final int winOffsetY = screenLocationY - drawingLocationY;
- final int popupScreenTop = outParams.y + winOffsetY;
- final int spaceBelow = displayFrameBottom - popupScreenTop;
- if (popupScreenTop >= 0 && height <= spaceBelow) {
+ final int anchorTopInScreen = outParams.y + winOffsetY;
+ final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+ if (anchorTopInScreen >= 0 && height <= spaceBelow) {
return true;
}
- final int popupScreenBottom;
- if (mOverlapAnchor) {
- // popupScreenTop equals the anchor's top at this point.
- // When shown above the anchor, an overlapping popup's bottom should be aligned with
- // the anchor's bottom.
- popupScreenBottom = popupScreenTop + anchorHeight;
- } else {
- // popupScreenTop equals the anchor's bottom at this point.
- // When shown above the anchor, a non-overlapping popup's bottom is aligned with
- // the anchor's top.
- popupScreenBottom = popupScreenTop - anchorHeight;
- }
- final int spaceAbove = popupScreenBottom - displayFrameTop;
+ final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
if (height <= spaceAbove) {
// Move everything up.
if (mOverlapAnchor) {
- // Add one anchorHeight to compensate for the correction made at the start of
- // findDropDownPosition, and another to account for being aligned to the anchor's
- // bottom, not top.
- yOffset += anchorHeight * 2;
+ yOffset += anchorHeight;
}
outParams.y = drawingLocationY - height + yOffset;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 89182b0..3d54fe7 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -400,6 +400,7 @@
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
+ mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1f54c84..8542bec0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1639,12 +1639,21 @@
boolean canInputOrMove = (mMovement != null || getKeyListener() != null);
boolean clickable = canInputOrMove || isClickable();
boolean longClickable = canInputOrMove || isLongClickable();
+ int focusable = getFocusable();
n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
+ case com.android.internal.R.styleable.View_focusable:
+ TypedValue val = new TypedValue();
+ if (a.getValue(attr, val)) {
+ focusable = (val.type == TypedValue.TYPE_INT_BOOLEAN)
+ ? (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE)
+ : val.data;
+ }
+
case com.android.internal.R.styleable.View_clickable:
clickable = a.getBoolean(attr, clickable);
break;
@@ -1656,6 +1665,13 @@
}
a.recycle();
+ // Some apps were relying on the undefined behavior of focusable winning over
+ // focusableInTouchMode != focusable in TextViews if both were specified in XML (usually
+ // when starting with EditText and setting only focusable=false). To keep those apps from
+ // breaking, re-apply the focusable attribute here.
+ if (focusable != getFocusable()) {
+ setFocusable(focusable);
+ }
setClickable(clickable);
setLongClickable(longClickable);
@@ -10756,7 +10772,11 @@
switch (id) {
case ID_SELECT_ALL:
+ final boolean hadSelection = hasSelection();
selectAllText();
+ if (mEditor != null && hadSelection) {
+ mEditor.invalidateActionModeAsync();
+ }
return true;
case ID_UNDO:
@@ -11207,8 +11227,10 @@
return true;
case DragEvent.ACTION_DRAG_LOCATION:
- final int offset = getOffsetForPosition(event.getX(), event.getY());
- Selection.setSelection((Spannable) mText, offset);
+ if (mText instanceof Spannable) {
+ final int offset = getOffsetForPosition(event.getX(), event.getY());
+ Selection.setSelection((Spannable) mText, offset);
+ }
return true;
case DragEvent.ACTION_DROP:
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 3605585..05d0f96 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -248,7 +248,7 @@
mRadialTimePickerHeader.setVisibility(View.GONE);
mTextInputPickerHeader.setVisibility(View.VISIBLE);
mTextInputPickerView.setVisibility(View.VISIBLE);
- mRadialTimePickerModeButton.setImageResource(R.drawable.btn_event_material);
+ mRadialTimePickerModeButton.setImageResource(R.drawable.btn_clock_material);
mRadialTimePickerModeButton.setContentDescription(
mRadialTimePickerModeEnabledDescription);
mRadialPickerModeEnabled = false;
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 13ebe5c..d807120 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -449,6 +449,11 @@
public void handleShow(IBinder windowToken) {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
+ // If a cancel/hide is pending - no need to show - at this point
+ // the window token is already invalid and no need to do any work.
+ if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {
+ return;
+ }
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
@@ -483,8 +488,16 @@
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
- mWM.addView(mView, mParams);
- trySendAccessibilityEvent();
+ // Since the notification manager service cancels the token right
+ // after it notifies us to cancel the toast there is an inherent
+ // race and we may attempt to add a window after the token has been
+ // invalidated. Let us hedge against that.
+ try {
+ mWM.addView(mView, mParams);
+ trySendAccessibilityEvent();
+ } catch (WindowManager.BadTokenException e) {
+ /* ignore */
+ }
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 373f4bb..78566df 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -132,7 +132,7 @@
void noteBleScanStarted(in WorkSource ws);
void noteBleScanStopped(in WorkSource ws);
void noteResetBleScan();
- void noteBleScanResult(in WorkSource ws);
+ void noteBleScanResults(in WorkSource ws, int numNewResults);
HealthStatsParceler takeUidSnapshot(int uid);
HealthStatsParceler[] takeUidSnapshots(in int[] uid);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index b596678..9c6f1d0 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1341,6 +1341,8 @@
mPlaceholderCount = count;
}
+ public int getPlaceholderCount() { return mPlaceholderCount; }
+
@Nullable
public DisplayResolveInfo getFilteredItem() {
if (mFilterLastUsed && mLastChosenPosition >= 0) {
@@ -1447,7 +1449,11 @@
}
if (currentResolveList.size() > 1) {
- setPlaceholderCount(currentResolveList.size());
+ int placeholderCount = currentResolveList.size();
+ if (useLayoutWithDefault()) {
+ --placeholderCount;
+ }
+ setPlaceholderCount(placeholderCount);
AsyncTask<List<ResolvedComponentInfo>,
Void,
List<ResolvedComponentInfo>> sortingTask =
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 797cf2b..d279746 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -47,6 +47,7 @@
public static String RETAIL_MODE = "RETAIL_MODE";
public static String USB = "USB";
public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
+ public static String ALERT_WINDOW = "ALERT_WINDOW";
public static void createAll(Context context) {
final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -137,6 +138,11 @@
context.getString(R.string.notification_channel_foreground_service),
NotificationManager.IMPORTANCE_MIN));
+ channelsList.add(new NotificationChannel(
+ ALERT_WINDOW,
+ context.getString(R.string.alert_windows_notification_channel_name),
+ NotificationManager.IMPORTANCE_MIN));
+
nm.createNotificationChannels(channelsList);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5c6a1b2..25d5fae 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -169,7 +169,6 @@
public interface PlatformIdleStateCallback {
public String getPlatformLowPowerStats();
- public String getSubsystemLowPowerStats();
}
private final PlatformIdleStateCallback mPlatformIdleStateCallback;
@@ -936,6 +935,10 @@
mCount.incrementAndGet();
}
+ void addAtomic(int delta) {
+ mCount.addAndGet(delta);
+ }
+
/**
* Clear state of this counter.
*/
@@ -964,14 +967,15 @@
}
}
+ @VisibleForTesting
public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs {
final TimeBase mTimeBase;
- long[] mCounts;
- long[] mLoadedCounts;
- long[] mUnpluggedCounts;
- long[] mPluggedCounts;
+ public long[] mCounts;
+ public long[] mLoadedCounts;
+ public long[] mUnpluggedCounts;
+ public long[] mPluggedCounts;
- LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
+ private LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mPluggedCounts = in.createLongArray();
mCounts = copyArray(mPluggedCounts, mCounts);
@@ -980,12 +984,12 @@
timeBase.add(this);
}
- LongSamplingCounterArray(TimeBase timeBase) {
+ public LongSamplingCounterArray(TimeBase timeBase) {
mTimeBase = timeBase;
timeBase.add(this);
}
- public void writeToParcel(Parcel out) {
+ private void writeToParcel(Parcel out) {
out.writeLongArray(mCounts);
out.writeLongArray(mLoadedCounts);
out.writeLongArray(mUnpluggedCounts);
@@ -1021,7 +1025,7 @@
+ " mPluggedCounts=" + Arrays.toString(mPluggedCounts));
}
- void addCountLocked(long[] counts) {
+ public void addCountLocked(long[] counts) {
if (counts == null) {
return;
}
@@ -1036,7 +1040,7 @@
/**
* Clear state of this counter.
*/
- void reset(boolean detachIfReset) {
+ public void reset(boolean detachIfReset) {
fillArray(mCounts, 0);
fillArray(mLoadedCounts, 0);
fillArray(mPluggedCounts, 0);
@@ -1046,21 +1050,60 @@
}
}
- void detach() {
+ public void detach() {
mTimeBase.remove(this);
}
- void writeSummaryFromParcelLocked(Parcel out) {
+ private void writeSummaryToParcelLocked(Parcel out) {
out.writeLongArray(mCounts);
}
- void readSummaryFromParcelLocked(Parcel in) {
+ private void readSummaryFromParcelLocked(Parcel in) {
mCounts = in.createLongArray();
mLoadedCounts = copyArray(mCounts, mLoadedCounts);
mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
mPluggedCounts = copyArray(mCounts, mPluggedCounts);
}
+ public static void writeToParcel(Parcel out, LongSamplingCounterArray counterArray) {
+ if (counterArray != null) {
+ out.writeInt(1);
+ counterArray.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ public static LongSamplingCounterArray readFromParcel(Parcel in, TimeBase timeBase) {
+ if (in.readInt() != 0) {
+ return new LongSamplingCounterArray(timeBase, in);
+ } else {
+ return null;
+ }
+ }
+
+ public static void writeSummaryToParcelLocked(Parcel out,
+ LongSamplingCounterArray counterArray) {
+ if (counterArray != null) {
+ out.writeInt(1);
+ counterArray.writeSummaryToParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ public static LongSamplingCounterArray readSummaryFromParcelLocked(Parcel in,
+ TimeBase timeBase) {
+ if (in.readInt() != 0) {
+ final LongSamplingCounterArray counterArray
+ = new LongSamplingCounterArray(timeBase);
+ counterArray.readSummaryFromParcelLocked(in);
+ return counterArray;
+ } else {
+ return null;
+ }
+ }
+
private void fillArray(long[] a, long val) {
if (a != null) {
Arrays.fill(a, val);
@@ -2839,12 +2882,6 @@
mPlatformIdleStateCallback.getPlatformLowPowerStats();
if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" +
mCurHistoryStepDetails.statPlatformIdleState);
-
- mCurHistoryStepDetails.statSubsystemPowerState =
- mPlatformIdleStateCallback.getSubsystemLowPowerStats();
- if (DEBUG) Slog.i(TAG, "WRITE SubsystemPowerState:" +
- mCurHistoryStepDetails.statSubsystemPowerState);
-
}
computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
if (includeStepDetails != 0) {
@@ -4842,11 +4879,11 @@
}
}
- public void noteBluetoothScanResultFromSourceLocked(WorkSource ws) {
+ public void noteBluetoothScanResultsFromSourceLocked(WorkSource ws, int numNewResults) {
final int N = ws.size();
for (int i = 0; i < N; i++) {
int uid = mapUid(ws.get(i));
- getUidStatsLocked(uid).noteBluetoothScanResultLocked();
+ getUidStatsLocked(uid).noteBluetoothScanResultsLocked(numNewResults);
}
}
@@ -6057,8 +6094,8 @@
return mBluetoothScanResultCounter;
}
- public void noteBluetoothScanResultLocked() {
- createBluetoothScanResultCounterLocked().stepAtomic();
+ public void noteBluetoothScanResultsLocked(int numNewResults) {
+ createBluetoothScanResultCounterLocked().addAtomic(numNewResults);
}
@Override
@@ -6930,18 +6967,8 @@
out.writeInt(0);
}
- if (mCpuFreqTimeMs != null) {
- out.writeInt(1);
- mCpuFreqTimeMs.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- if (mScreenOffCpuFreqTimeMs != null) {
- out.writeInt(1);
- mScreenOffCpuFreqTimeMs.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
+ LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
+ LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
if (mMobileRadioApWakeupCount != null) {
out.writeInt(1);
@@ -7190,17 +7217,9 @@
mCpuClusterSpeed = null;
}
- if (in.readInt() != 0) {
- mCpuFreqTimeMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
- } else {
- mCpuFreqTimeMs = null;
- }
- if (in.readInt() != 0) {
- mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
- mBsi.mOnBatteryScreenOffTimeBase, in);
- } else {
- mScreenOffCpuFreqTimeMs = null;
- }
+ mCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(in, mBsi.mOnBatteryTimeBase);
+ mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
+ in, mBsi.mOnBatteryScreenOffTimeBase);
if (in.readInt() != 0) {
mMobileRadioApWakeupCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
@@ -10132,7 +10151,7 @@
@Override
public void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs) {
- final Uid u = getUidStatsLocked(uid);
+ final Uid u = getUidStatsLocked(mapUid(uid));
if (u.mCpuFreqTimeMs == null) {
u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
@@ -11358,19 +11377,10 @@
u.mCpuClusterSpeed = null;
}
- if (in.readInt() != 0) {
- u.mCpuFreqTimeMs = new LongSamplingCounterArray(mOnBatteryTimeBase);
- u.mCpuFreqTimeMs.readSummaryFromParcelLocked(in);
- } else {
- u.mCpuFreqTimeMs = null;
- }
- if (in.readInt() != 0) {
- u.mScreenOffCpuFreqTimeMs = new LongSamplingCounterArray(
- mOnBatteryScreenOffTimeBase);
- u.mScreenOffCpuFreqTimeMs.readSummaryFromParcelLocked(in);
- } else {
- u.mScreenOffCpuFreqTimeMs = null;
- }
+ u.mCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
+ in, mOnBatteryTimeBase);
+ u.mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readSummaryFromParcelLocked(
+ in, mOnBatteryScreenOffTimeBase);
if (in.readInt() != 0) {
u.mMobileRadioApWakeupCount = new LongSamplingCounter(mOnBatteryTimeBase);
@@ -11768,18 +11778,8 @@
out.writeInt(0);
}
- if (u.mCpuFreqTimeMs != null) {
- out.writeInt(1);
- u.mCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
- }
- if (u.mScreenOffCpuFreqTimeMs != null) {
- out.writeInt(1);
- u.mScreenOffCpuFreqTimeMs.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
- }
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mCpuFreqTimeMs);
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, u.mScreenOffCpuFreqTimeMs);
if (u.mMobileRadioApWakeupCount != null) {
out.writeInt(1);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e065843..5eca496 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -107,7 +107,7 @@
fdsToIgnore, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
- Trace.setTracingEnabled(true);
+ Trace.setTracingEnabled(true, debugFlags);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -152,7 +152,7 @@
uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
- Trace.setTracingEnabled(true);
+ Trace.setTracingEnabled(true, debugFlags);
}
VM_HOOKS.postForkCommon();
return pid;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a9bec41..2013ac0 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -762,14 +762,6 @@
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
String property = "wrap." + args.niceName;
- if (property.length() > 31) {
- // Properties with a trailing "." are illegal.
- if (property.charAt(30) != '.') {
- property = property.substring(0, 31);
- } else {
- property = property.substring(0, 30);
- }
- }
args.invokeWith = SystemProperties.get(property);
if (args.invokeWith != null && args.invokeWith.length() == 0) {
args.invokeWith = null;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 4ce6ec5..9e61a99 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -745,7 +745,7 @@
bootTimingsTraceLog.traceEnd(); // ZygoteInit
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
- Trace.setTracingEnabled(false);
+ Trace.setTracingEnabled(false, 0);
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1b83708..9823431 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -296,7 +296,11 @@
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
- mBackgroundFallback.draw(mContentRoot, c, mWindow.mContentParent);
+
+ // When we are resizing, we need the fallback background to cover the area where we have our
+ // system bar background views as the navigation bar will be hidden during resizing.
+ mBackgroundFallback.draw(isResizing() ? this : mContentRoot, mContentRoot, c,
+ mWindow.mContentParent);
}
@Override
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index 1b354d0..28f12eb 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -18,12 +18,14 @@
package com.android.internal.util;
import android.annotation.Nullable;
+import android.text.TextUtils;
import libcore.util.Objects;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;
+import java.util.function.IntFunction;
/**
* A utility class for handling unsigned integers and unsigned arithmetics, as well as syntactic
@@ -124,4 +126,26 @@
buffer.put(bytes);
buffer.position(original);
}
+
+ public static boolean isBitSet(long flags, int bitIndex) {
+ return (flags & bitAt(bitIndex)) != 0;
+ }
+
+ public static long bitAt(int bitIndex) {
+ return 1L << bitIndex;
+ }
+
+ public static String flagsToString(int flags, IntFunction<String> getFlagName) {
+ StringBuilder builder = new StringBuilder();
+ int count = 0;
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ if (count > 0) builder.append(", ");
+ builder.append(getFlagName.apply(flag));
+ count++;
+ }
+ TextUtils.wrap(builder, "[", "]");
+ return builder.toString();
+ }
}
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index cd41f9e..1ba92bf 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -533,6 +533,10 @@
return ColorUtilsFromCompat.calculateContrast(foregroundColor, backgroundColor);
}
+ public static boolean satisfiesTextContrast(int backgroundColor, int foregroundColor) {
+ return NotificationColorUtil.calculateContrast(backgroundColor, foregroundColor) >= 4.5;
+ }
+
/**
* Composite two potentially translucent colors over each other and returns the result.
*/
@@ -540,6 +544,10 @@
return ColorUtilsFromCompat.compositeColors(foreground, background);
}
+ public static boolean isColorLight(int backgroundColor) {
+ return calculateLuminance(backgroundColor) > 0.5f;
+ }
+
/**
* Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
*/
diff --git a/core/java/com/android/internal/widget/BackgroundFallback.java b/core/java/com/android/internal/widget/BackgroundFallback.java
index 4adba4d..309f80c 100644
--- a/core/java/com/android/internal/widget/BackgroundFallback.java
+++ b/core/java/com/android/internal/widget/BackgroundFallback.java
@@ -39,14 +39,22 @@
return mBackgroundFallback != null;
}
- public void draw(ViewGroup root, Canvas c, View content) {
+ /**
+ * Draws the fallback background.
+ *
+ * @param boundsView The view determining with which bounds the background should be drawn.
+ * @param root The view group containing the content.
+ * @param c The canvas to draw the background onto.
+ * @param content The view where the actual app content is contained in.
+ */
+ public void draw(ViewGroup boundsView, ViewGroup root, Canvas c, View content) {
if (!hasFallback()) {
return;
}
// Draw the fallback in the padding.
- final int width = root.getWidth();
- final int height = root.getHeight();
+ final int width = boundsView.getWidth();
+ final int height = boundsView.getHeight();
int left = width;
int top = height;
int right = 0;
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index e86932c..6b53368 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -169,4 +169,8 @@
}
return false;
}
+
+ public int getLayoutHeight() {
+ return getLayout().getHeight();
+ }
}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 1104318..70473a0 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -138,7 +138,7 @@
first = false;
boolean measuredTooSmall = false;
if (textChild != null) {
- measuredTooSmall = childHeight < textChild.getLayout().getHeight()
+ measuredTooSmall = childHeight < textChild.getLayoutHeight()
+ textChild.getPaddingTop() + textChild.getPaddingBottom();
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index bc23b16..b0a2e11 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -277,12 +277,18 @@
],
local_include_dirs: ["android/graphics"],
- export_include_dirs: ["include"],
+ export_include_dirs: [
+ ".",
+ "include",
+ ],
export_shared_lib_headers: [
// AndroidRuntime.h depends on nativehelper/jni.h
"libnativehelper",
// our headers include libnativewindow's public headers
"libnativewindow",
+
+ // GraphicsJNI.h includes hwui headers
+ "libhwui",
],
}
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index b529e37..214d97c 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -60,17 +60,14 @@
static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
jint tileModeX, jint tileModeY) {
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- sk_sp<SkImage> image;
+ SkBitmap bitmap;
if (jbitmap) {
// Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
- image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr);
+ android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
}
- if (!image.get()) {
- SkBitmap bitmap;
- image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- }
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
sk_sp<SkShader> baseShader = image->makeShader(
(SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
diff --git a/core/jni/android_app_ApplicationLoaders.cpp b/core/jni/android_app_ApplicationLoaders.cpp
index 3e7c039..8bbf24a 100644
--- a/core/jni/android_app_ApplicationLoaders.cpp
+++ b/core/jni/android_app_ApplicationLoaders.cpp
@@ -32,7 +32,7 @@
loader_data.layer_path = layerPathChars.c_str();
loader_data.app_namespace = ns;
} else {
- ALOGD("ignored Vulkan layer search path %s for namespace %p",
+ ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'",
layerPathChars.c_str(), ns);
}
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e1c0a21..aa1893c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -570,18 +570,6 @@
mObserver->decStrong(nullptr);
}
-static jboolean android_view_ThreadedRenderer_supportsOpenGL(JNIEnv* env, jobject clazz) {
- char prop[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", prop, NULL) == 0) {
- // not in the emulator
- return JNI_TRUE;
- }
- // In the emulator this property will be set > 0 when OpenGL ES 2.0 is
- // enabled, 0 otherwise. On old emulator versions it will be undefined.
- property_get("qemu.gles", prop, "0");
- return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
-}
-
static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) {
RenderProxy::rotateProcessStatsBuffer();
}
@@ -898,7 +886,6 @@
const char* const kClassPathName = "android/view/ThreadedRenderer";
static const JNINativeMethod gMethods[] = {
- { "nSupportsOpenGL", "()Z", (void*) android_view_ThreadedRenderer_supportsOpenGL },
{ "nRotateProcessStatsBuffer", "()V", (void*) android_view_ThreadedRenderer_rotateProcessStatsBuffer },
{ "nSetProcessStatsBuffer", "(I)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
{ "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 6000fb5..d73e7dd 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -27,6 +27,7 @@
#include <fcntl.h>
#include <grp.h>
#include <inttypes.h>
+#include <malloc.h>
#include <mntent.h>
#include <paths.h>
#include <signal.h>
@@ -519,6 +520,9 @@
// The child process.
gMallocLeakZygoteChild = 1;
+ // Set the jemalloc decay time to 1.
+ mallopt(M_DECAY_TIME, 1);
+
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fdsToClose);
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 2042bf62..0ee71bd 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -22,7 +22,6 @@
import "frameworks/base/libs/incident/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
import "frameworks/base/core/proto/android/service/battery.proto";
-import "frameworks/base/core/proto/android/service/graphicsstats.proto";
import "frameworks/base/core/proto/android/service/fingerprint.proto";
import "frameworks/base/core/proto/android/service/diskstats.proto";
import "frameworks/base/core/proto/android/service/netstats.proto";
@@ -66,5 +65,4 @@
android.service.notification.NotificationServiceDumpProto notification = 3004;
android.service.pm.PackageServiceDumpProto package = 3008;
android.service.power.PowerServiceDumpProto power = 3009;
- android.service.GraphicsStatsServiceDumpProto graphicsstats = 3005;
}
diff --git a/core/proto/android/service/fingerprint.proto b/core/proto/android/service/fingerprint.proto
index 79dba86..f88b762 100644
--- a/core/proto/android/service/fingerprint.proto
+++ b/core/proto/android/service/fingerprint.proto
@@ -54,4 +54,7 @@
// Total number of lockouts.
int32 lockout = 4;
+
+ // Total number of permanent lockouts.
+ int32 lockout_permanent = 5;
}
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index 6dbfe48..b8679b0 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -20,6 +20,7 @@
option java_multiple_files = true;
option java_outer_classname = "GraphicsStatsServiceProto";
+option optimize_for = LITE_RUNTIME;
message GraphicsStatsServiceDumpProto {
repeated GraphicsStatsProto stats = 1;
diff --git a/core/res/res/anim/lock_screen_behind_enter.xml b/core/res/res/anim/lock_screen_behind_enter.xml
index c96e280..c1d26e3 100644
--- a/core/res/res/anim/lock_screen_behind_enter.xml
+++ b/core/res/res/anim/lock_screen_behind_enter.xml
@@ -17,8 +17,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:detachWallpaper="true"
- android:shareInterpolator="false"
- android:startOffset="100">
+ android:shareInterpolator="false">
<translate android:fromYDelta="110%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
diff --git a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
index 94e40a8..e9475f5 100644
--- a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
+++ b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml
@@ -22,6 +22,5 @@
android:interpolator="@interpolator/linear"
android:fromAlpha="0" android:toAlpha="1"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
- android:duration="250"
- android:startOffset="100">
+ android:duration="250">
</alpha>
\ No newline at end of file
diff --git a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
index 660b662..50156fb 100644
--- a/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
+++ b/core/res/res/anim/lock_screen_behind_enter_wallpaper.xml
@@ -16,12 +16,12 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:shareInterpolator="false" android:startOffset="100">
+ android:detachWallpaper="true" android:shareInterpolator="false" >
<alpha
android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true"
android:interpolator="@interpolator/decelerate_quint"
- android:duration="400"/>
+ android:duration="300"/>
<translate android:fromYDelta="11%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
diff --git a/core/res/res/anim/lock_screen_wallpaper_exit.xml b/core/res/res/anim/lock_screen_wallpaper_exit.xml
index 49d0327..ba8741a 100644
--- a/core/res/res/anim/lock_screen_wallpaper_exit.xml
+++ b/core/res/res/anim/lock_screen_wallpaper_exit.xml
@@ -16,12 +16,12 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false" android:startOffset="100">
+ android:shareInterpolator="false">
<alpha
android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/fast_out_linear_in"
- android:duration="150"/>
+ android:duration="200"/>
<!-- Empty animation so the animation has same duration as lock_screen_behind_enter animation
-->
diff --git a/core/res/res/drawable/btn_event_material.xml b/core/res/res/drawable/btn_clock_material.xml
similarity index 73%
rename from core/res/res/drawable/btn_event_material.xml
rename to core/res/res/drawable/btn_clock_material.xml
index 47c49cf..f785ebf 100644
--- a/core/res/res/drawable/btn_event_material.xml
+++ b/core/res/res/drawable/btn_clock_material.xml
@@ -18,12 +18,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
-
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
android:fillColor="#90ffffff"
- android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0-1.99 .9 -1.99 2L3 19c0 1.1 .89 2 2
-2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2h-1V1h-2zm3 18H5V8h14v11z" />
- <path android:pathData="M0 0h24v24H0z" />
-</vector>
\ No newline at end of file
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
+</vector>
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index 8b95f9f..863efef 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -20,11 +20,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <LinearLayout
+ <RelativeLayout
android:id="@+id/time_header"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:orientation="vertical"
android:gravity="center"
android:paddingStart="?attr/dialogPreferredPadding"
android:paddingEnd="?attr/dialogPreferredPadding">
@@ -112,7 +111,7 @@
android:includeFontPadding="false"
android:button="@null" />
</RadioGroup>
- </LinearLayout>
+ </RelativeLayout>
<TextView
android:visibility="gone"
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index 76ce826..2bef027 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -37,7 +37,8 @@
android:layout_width="50dp"
android:layout_height="wrap_content"
android:inputType="number"
- android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+ android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField"
+ android:imeOptions="actionNext"/>
<TextView
android:id="@+id/label_hour"
android:layout_width="wrap_content"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index fefd523..5e52de9 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Opdaterings"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Netwerkstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Netwerkwaarskuwings"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Netwerk is beskikbaar"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Toesteladministrasie"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Opletberigte"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Vingerafdrukhandeling is gekanselleer."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Te veel pogings. Probeer later weer."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probeer weer."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Oop Wi-Fi-netwerke beskikbaar</item>
+ <item quantity="one">Oop Wi-Fi-netwerk beskikbaar</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Meld aan by Wi-Fi-netwerk"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Meld by netwerk aan"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index c79c3d3..3cde574 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"ዝማኔዎች"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"የአውታረ መረብ ሁኔታ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"የአውታረ መረብ ማንቂያዎች"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"አውታረ መረብ ይገኛል"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"የቪፒኤን ሁኔታ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"የመሣሪያ አስተዳደር"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ማንቂያዎች"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"የጣት አሻራ ማብቂያ ጊዜ ደርሷል። እንደገና ይሞክሩ።"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"የጣት አሻራ ስርዓተ ክወና ተትቷል።"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"እንደገና ይሞክሩ።"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
+ <item quantity="other">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f89a51d..14cec4c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -272,6 +272,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"التحديثات"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"حالة الشبكة"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"تنبيهات الشبكة"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"الشبكة متوفرة"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"حالة الشبكة الظاهرية الخاصة"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"إدارة الجهاز"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
@@ -502,6 +503,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"تم بلوغ مهلة إدخال بصمة الإصبع. أعد المحاولة."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"تم إلغاء تشغيل بصمة الإصبع."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"تم إجراء عدد كبير من المحاولات. أعد المحاولة لاحقًا."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"أعد المحاولة."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1179,6 +1182,22 @@
<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>
+ <item quantity="few">تتوفر شبكات Wi-Fi</item>
+ <item quantity="many">تتوفر شبكات Wi-Fi</item>
+ <item quantity="other">تتوفر شبكات Wi-Fi</item>
+ <item quantity="one">تتوفر شبكة Wi-Fi واحدة</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="zero">لا تتوفر أية شبكات Wi-Fi مفتوحة</item>
+ <item quantity="two">تتوفر شبكتا Wi-Fi مفتوحتان</item>
+ <item quantity="few">تتوفر شبكات Wi-Fi مفتوحة</item>
+ <item quantity="many">تتوفر شبكات Wi-Fi مفتوحة</item>
+ <item quantity="other">تتوفر شبكات Wi-Fi مفتوحة</item>
+ <item quantity="one">تتوفر شبكة Wi-Fi واحدة مفتوحة</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"تسجيل الدخول إلى شبكة Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"تسجيل الدخول إلى الشبكة"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 6faf2d7..ae1d5fd 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Güncəlləmələr"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Şəbəkə statusu"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Şəbəkə siqnalları"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Şəbəkə əlçatandır"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN statusu"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Cihaz administrasiyası"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Siqnallar"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmaq izinin vaxtı başa çatdı. Yenidən cəhd edin."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Barmaq izi əməliyyatı ləğv edildi."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Cəhdlər çox oldu. Sonraya saxlayın."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Yenidən cəhd edin."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Əlçatan açıq Wi-Fi şəbəkələri</item>
+ <item quantity="one">Əlçatan açıq Wi-Fi şəbəkəsi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi şəbəkəsinə daxil ol"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Şəbəkəyə daxil olun"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b76c727..c7e3f49 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ažuriranja"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status mreže"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Obaveštenja u vezi sa mrežom"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status VPN-a"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administriranje uređaja"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Obaveštenja"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Probajte ponovo kasnije."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probajte ponovo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1119,6 +1122,16 @@
<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>
+ <item quantity="other">Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index df33683..2fbbc20 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Абнаўленні"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Стан сеткі"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Абвесткі сеткі"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Сетка даступная"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Стан VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Адміністраванне прылады"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Абвесткi"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час чакання адбіткаў пальцаў выйшаў. Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Аперацыя з адбіткамі пальцаў скасавана."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Паспрабуйце яшчэ раз."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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>
+ <item quantity="many">сетак Wi-Fi даступна</item>
+ <item quantity="other">сеткі Wi-Fi даступна</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">адкрытая сетка Wi-Fi даступная</item>
+ <item quantity="few">адкрытыя сеткі Wi-Fi даступныя</item>
+ <item quantity="many">адкрытых сетак Wi-Fi даступна</item>
+ <item quantity="other">адкрытай сеткі Wi-Fi даступна</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Увайдзіце ў сетку"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 3aee61c..8272e45 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Актуализации"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Състояние на мрежата"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Сигнали за мрежата"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"Състояние на VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Администриране на устройство"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Сигнали"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Времето за изчакване за отпечатък изтече. Опитайте отново."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Операцията за отпечатък е анулирана."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Твърде много опити. Пробвайте отново по-късно."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Опитайте отново."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Има достъпни отворени Wi-Fi мрежи</item>
+ <item quantity="one">Има достъпна отворена Wi-Fi мрежа</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Влизане в Wi-Fi мрежа"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Вход в мрежата"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 0bf2aa4..edbac70 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"আপডেটগুলি"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"নেটওয়ার্কের স্থিতি"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"নেটওয়ার্ক সক্রান্ত অ্যালার্ট"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN এর স্থিতি"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ডিভাইস প্রশাসন"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"সতর্কতাগুলি"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"আঙ্গুলের ছাপ নেওয়ার সময়সীমা শেষ হযেছে৷ আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"আঙ্গুলের ছাপ অপারেশন বাতিল করা হয়েছে৷"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"অনেকবার প্রচেষ্টা করা হয়েছে৷ পরে আবার চেষ্টা করুন৷"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"আবার চেষ্টা করুন৷"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"অ্যালার্মের শব্দ"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"বিজ্ঞপ্তির শব্দ"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"অজানা"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+ <item quantity="other">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+ <item quantity="other">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ওয়াই-ফাই নেটওয়ার্কে প্রবেশ করুন"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"নেটওয়ার্কে প্রবেশ করুন"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c1fb65d..8743cf8 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ažuriranja"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status mreže"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Mrežna upozorenja"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status VPN-a"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administracija uređaja"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1121,6 +1124,16 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvukovi alarma"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvukovi 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>
+ <item quantity="other">Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e7481e1..4b8b84b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Actualitzacions"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Estat de la xarxa"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertes de xarxa"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Hi ha una xarxa disponible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Estat de la VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administració del dispositiu"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"S\'ha esgotat el temps d\'espera per a l\'empremta digital. Torna-ho a provar."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"S\'ha cancel·lat l\'operació d\'empremta digital."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"S\'han produït massa intents. Torna-ho a provar més tard."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Torna-ho a provar."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -984,7 +987,7 @@
<string name="editTextMenuTitle" msgid="4909135564941815494">"Accions de text"</string>
<string name="email" msgid="4560673117055050403">"Correu electrònic"</string>
<string name="dial" msgid="4204975095406423102">"Truca"</string>
- <string name="map" msgid="6068210738233985748">"Google Maps"</string>
+ <string name="map" msgid="6068210738233985748">"Mapes"</string>
<string name="browse" msgid="6993590095938149861">"Navegador"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"L\'espai d\'emmagatzematge s\'està esgotant"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"És possible que algunes funcions del sistema no funcionin"</string>
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Xarxes Wi-Fi obertes disponibles</item>
+ <item quantity="one">Xarxa Wi-Fi oberta disponible</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia la sessió a la xarxa Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Inicia la sessió a la xarxa"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 78ef99d..38276ce 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Aktualizace"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Stav sítě"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Síťová upozornění"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"K dispozici je síť"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stav sítě VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administrace zařízení"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornění"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit sejmutí otisku prstu vypršel. Zkuste to znovu."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operace otisku prstu byla zrušena."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Příliš mnoho pokusů. Zkuste to později."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Zkuste to znovu."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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>
+ <item quantity="other">K dispozici jsou sítě Wi-Fi</item>
+ <item quantity="one">K dispozici je síť Wi-Fi</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="few">K dispozici jsou veřejné sítě Wi-Fi</item>
+ <item quantity="many">K dispozici jsou veřejné sítě Wi-Fi</item>
+ <item quantity="other">K dispozici jsou veřejné sítě Wi-Fi</item>
+ <item quantity="one">K dispozici je veřejná síť Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Přihlásit se k síti Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Přihlásit se k síti"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9f09729..ee5ba79 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Opdateringer"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Netværksstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Netværksunderretninger"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Tilgængeligt netværk"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhedsadministration"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
@@ -299,7 +300,7 @@
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"observere tekst, du skriver"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Dette omfatter personlige data såsom kreditkortnumre og adgangskoder."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"administrere skærmforstørrelsen"</string>
- <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrollér skærmens zoomniveau og position."</string>
+ <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Tjek skærmens zoomniveau og position."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Udfør bevægelser"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Kan trykke, stryge, knibe sammen og udføre andre bevægelser."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingeraftryksbevægelser"</string>
@@ -406,8 +407,8 @@
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Tillader, at appen sender kommandoer til SIM-kortet. Dette er meget farligt."</string>
<string name="permlab_camera" msgid="3616391919559751192">"tage billeder og optage video"</string>
<string name="permdesc_camera" msgid="5392231870049240670">"Med denne app kan du tage billeder og optage video med kameraet når som helst."</string>
- <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string>
- <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"administrere vibration"</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan administrere vibratoren."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string>
@@ -470,7 +471,7 @@
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Tillader, at appen kan læse konfigurationen af Bluetooth på tabletten samt kan oprette og acceptere forbindelser med parrede enheder."</string>
<string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Giver appen lov til at se fjernsynets Bluetooth-konfiguration og til at oprette og acceptere forbindelser til parrede enheder."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Tillader, at appen kan læse konfigurationen af Bluetooth på telefonen samt kan oprette og acceptere forbindelser med parrede enheder."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"kontrollere Near Field Communication"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"administrere Near Field Communication"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Tillader, at appen kan kommunikere med NFC-tags (Near Field Communication), -kort og -læsere."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"deaktivere din skærmlås"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Tillader, at appen kan deaktivere tastaturlåsen og anden form for tilknyttet adgangskodesikkerhed. Telefonen deaktiverer f.eks. tastaturlåsen ved indgående telefonopkald og aktiverer tastaturlåsen igen, når opkaldet er afsluttet."</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Registrering af fingeraftryk fik timeout. Prøv igen."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingeraftrykshandlingen blev annulleret."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Du har prøvet for mange gange. Prøv igen senere."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Prøv igen."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -556,7 +559,7 @@
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"have adgang til Forstyr ikke"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Forstyr ikke."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Angiv regler for adgangskoder"</string>
- <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
+ <string name="policydesc_limitPassword" msgid="2502021457917874968">"Tjek længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
<string name="policylab_watchLogin" msgid="5091404125971980158">"Overvåg forsøg på oplåsning af skærm"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Overvåg antallet af forkert indtastede adgangskoder, når du låser skærmen op, og lås din tablet, eller slet alle data i den, hvis der er indtastet for mange forkerte adgangskoder."</string>
<string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Overvåg antallet af forkert indtastede adgangskoder ved oplåsning af skærmen, og lås tv\'et eller slet alle dets data, hvis der indtastes for mange forkerte adgangskoder."</string>
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meddelelseslyde"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
+ <item quantity="other">Tilgængelige Wi-Fi-netværk</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Åbne Wi-Fi-netværk er tilgængelige</item>
+ <item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Log ind på Wi-Fi-netværk"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Log ind på netværk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1283,7 +1294,7 @@
<string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
<string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Opretter forbindelse til altid aktiveret VPN…"</string>
- <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Always-on VPN er forbundet"</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altid aktiveret VPN er forbundet"</string>
<string name="vpn_lockdown_disconnected" msgid="4532298952570796327">"Forbindelsen til altid aktiveret VPN er afbrudt"</string>
<string name="vpn_lockdown_error" msgid="6009249814034708175">"Fejl i altid aktiveret VPN"</string>
<string name="vpn_lockdown_config" msgid="5099330695245008680">"Tryk for at konfigurere"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d1d43eb..e4202ce 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Updates"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Netzwerkstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Netzwerkwarnungen"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Netzwerk verfügbar"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-Status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Geräteverwaltung"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Warnmeldungen"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Zeitüberschreitung für Fingerabdruck. Versuche es erneut."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerabdruckvorgang abgebrochen"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zu viele Versuche. Versuche es später erneut."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bitte versuche es erneut."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Weckertöne"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Benachrichtigungstöne"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Unbekannt"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">WLAN-Netzwerke verfügbar</item>
+ <item quantity="one">WLAN-Netzwerk verfügbar</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Verfügbare WLAN-Netzwerke öffnen</item>
+ <item quantity="one">Verfügbares WLAN-Netzwerk öffnen</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN-Netzwerk anmelden"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Im Netzwerk anmelden"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 74a4961..a602d03 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ενημερώσεις"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Κατάσταση δικτύου"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Ειδοποιήσεις δικτύου"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Το δίκτυο είναι διαθέσιμο"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Κατάσταση VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Διαχείριση συσκευής"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Ειδοποιήσεις"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Λήξη χρονικού ορίου μοναδικού χαρακτηριστικού. Δοκιμάστε ξανά."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Η λειτουργία μοναδικού χαρακτηριστικού ακυρώθηκε."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Δοκιμάστε ξανά."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi</item>
+ <item quantity="one">Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Σύνδεση στο δίκτυο"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 370f1be..60fd79d 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Updates"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Network status"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Network alerts"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Network available"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Device administration"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Too many attempts. Try again later."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Try again."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Open Wi-Fi networks available</item>
+ <item quantity="one">Open Wi-Fi network available</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 370f1be..60fd79d 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Updates"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Network status"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Network alerts"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Network available"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Device administration"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Too many attempts. Try again later."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Try again."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Open Wi-Fi networks available</item>
+ <item quantity="one">Open Wi-Fi network available</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 370f1be..60fd79d 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Updates"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Network status"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Network alerts"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Network available"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Device administration"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Fingerprint timeout reached. Try again."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingerprint operation cancelled."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Too many attempts. Try again later."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Try again."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Open Wi-Fi networks available</item>
+ <item quantity="one">Open Wi-Fi network available</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 79f4b8c..cc706fa 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Actualizaciones"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Estado de la red"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas de red"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Red disponible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Estado de VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administración del dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Finalizó el tiempo de espera para la huella digital. Vuelve a intentarlo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Se canceló la operación de huella digital."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Vuelve a intentarlo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Abrir redes de Wi-Fi disponibles</item>
+ <item quantity="one">Abrir red de Wi-Fi disponible</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Accede a una red Wi-Fi."</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Acceder a la red"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1746,7 +1757,7 @@
<string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Opciones de autocompletar"</string>
<string name="autofill_save_accessibility_title" msgid="7244365268417107822">"Guardar para Autocompletar"</string>
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"El contenido no puede autocompletarse"</string>
- <string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"Sin sugerencias de Autocompletar"</string>
+ <string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"No hay sugerencias de Autocompletar"</string>
<plurals name="autofill_picker_some_suggestions" formatted="false" msgid="5506565809835815274">
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> sugerencias de Autocompletar</item>
<item quantity="one">Una sugerencia de Autocompletar</item>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1beb004..c96e4c3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Actualizaciones"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Estado de la red"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas de la red"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Red disponible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Estado de la VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administración del dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Se ha alcanzado el tiempo de espera de la huella digital. Vuelve a intentarlo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Se ha cancelado la operación de huella digital."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Demasiados intentos. Vuelve a intentarlo más tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Vuelve a intentarlo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Redes Wi-Fi abiertas disponibles</item>
+ <item quantity="one">Red Wi-Fi abierta disponible</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sesión en red Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Iniciar sesión en la red"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 134540f..0a1b9bc 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Värskendused"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Võrgu olek"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Võrguteavitused"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Võrk on saadaval"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-i olek"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Seadme haldamine"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Teatised"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sõrmejälje riistvara taimeri ajalõpp. Proovige uuesti."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Sõrmejälje toiming tühistati."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Liiga palju katseid. Proovige hiljem uuesti."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Proovige uuesti."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Sõrm <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Äratuse helid"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Märguannete helid"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Teadmata"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">WiFi-võrgud on saadaval</item>
+ <item quantity="one">WiFi-võrk on saadaval</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Avatud WiFi-võrgud on saadaval</item>
+ <item quantity="one">Avatud WiFi-võrk on saadaval</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Võrku sisselogimine"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2d520df..5b598c6 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Eguneratzeak"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Sarearen egoera"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Sarearen alertak"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Sare bat erabilgarri dago"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN egoera"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Gailuen administrazioa"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Abisuak"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Hatz-marka digitalak prozesatzeko denbora-muga gainditu da. Saiatu berriro."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Hatz-markaren eragiketa bertan behera utzi da."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Saiatu berriro."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> hatza"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Wi-Fi sare irekiak erabilgarri</item>
+ <item quantity="one">Wi-Fi sare irekia erabilgarri</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Hasi saioa Wi-Fi sarean"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 36e6652..859f514 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"بهروزرسانیها"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"وضعیت شبکه"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"هشدارهای شبکه"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"وضعیت VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"سرپرست دستگاه"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"هشدارها"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"مهلت زمانی ثبت اثر انگشت به پایان رسید. دوباره امتحان کنید."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"عملکرد اثر انگشت لغو شد."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"تلاشهای زیادی انجام شده است. بعداً دوباره امتحان کنید."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"دوباره امتحان کنید."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">شبکه Wi-Fi باز در دسترس</item>
+ <item quantity="other">شبکه Wi-Fi باز در دسترس</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ورود به شبکه Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ورود به سیستم شبکه"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 0123f4a..ce14371 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Päivitykset"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Verkon tila"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Verkkoilmoitukset"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Verkko käytettävissä"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-tila"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Laitteen järjestelmänvalvonta"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Ilmoitukset"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Sormenjälkitunnistimen toiminta aikakatkaistiin. Yritä uudelleen."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Sormenjälkitoiminto peruutettiin."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Yritä uudelleen."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Avoimia Wi-Fi-verkkoja käytettävissä</item>
+ <item quantity="one">Avoin Wi-Fi-verkko käytettävissä</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Kirjaudu Wi-Fi-verkkoon"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Kirjaudu verkkoon"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 23bc0f8..a0b3667 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Mises à jour"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"État du réseau"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertes réseau"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"État du RPV"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administration d\'appareils"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Le temps attribué pour lire l\'empreinte est écoulé. Veuillez essayer de nouveau."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Opération d\'empreinte numérique annulée."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Trop de tentatives. Veuillez réessayer plus tard."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Réessayer."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons d\'alarme"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Inconnu"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Réseau Wi-Fi à proximité</item>
+ <item quantity="other">Réseaux Wi-Fi à proximité</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Réseau Wi-Fi ouvert à proximité</item>
+ <item quantity="other">Réseaux Wi-Fi ouverts à proximité</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Connectez-vous au réseau"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7c9a1f8..d6204b0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Mises à jour"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"État du réseau"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertes réseau"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Réseau disponible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"État du VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Gestion de l\'appareil"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Délai de détection de l\'empreinte numérique expiré. Veuillez réessayer."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Opération d\'empreinte numérique annulée."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Trop de tentatives. Veuillez réessayer plus tard."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Veuillez réessayer."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de l\'alarme"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Inconnue"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Réseau Wi-Fi disponible</item>
+ <item quantity="other">Réseaux Wi-Fi disponibles</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Réseau Wi-Fi ouvert disponible</item>
+ <item quantity="other">Réseaux Wi-Fi ouverts disponibles</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Se connecter au réseau"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 3f0ee27..e4a83bf 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Actualizacións"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Estado da rede"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas de rede"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"A rede está dispoñible"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Estado da VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administración de dispositivos"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Esgotouse o tempo de espera da impresión dixital. Téntao de novo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Cancelouse a operación da impresión dixital."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Demasiados intentos. Téntao de novo máis tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Téntao de novo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Abrir redes wifi dispoñibles</item>
+ <item quantity="one">Abrir rede wifi dispoñible</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia sesión na rede wifi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Inicia sesión na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4a35d70..ef09de4 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"અપડેટ્સ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"નેટવર્ક સ્થિતિ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"નેટવર્ક ચેતવણીઓ"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"નેટવર્ક ઉપલબ્ધ છે"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN સ્થિતિ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ઉપકરણ વ્યવસ્થાપન"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ચેતવણીઓ"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ફિંગરપ્રિન્ટનો સમય બાહ્ય થયો. ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ફિંગરપ્રિન્ટ ઓપરેશન રદ કર્યું."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ઘણા બધા પ્રયત્નો. પછીથી ફરી પ્રયાસ કરો."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ફરી પ્રયાસ કરો."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">ખુલ્લા Wi-Fi નેટવર્ક્સ ઉપલબ્ધ છે</item>
+ <item quantity="other">ખુલ્લા Wi-Fi નેટવર્ક્સ ઉપલબ્ધ છે</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi નેટવર્ક પર સાઇન ઇન કરો"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"નેટવર્ક પર સાઇન ઇન કરો"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5ce1cc1..611fa40 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"अपडेट"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"नेटवर्क की स्थिति"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"नेटवर्क संबंधी सूचनाएं"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"नेटवर्क उपलब्ध है"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN की स्थिति"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"डिवाइस का व्यवस्थापन"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"सूचनाएं"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"फ़िंगरप्रिंट का समय समाप्त हो गया. पुनः प्रयास करें."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"फ़िंगरप्रिंट क्रियान्वयन रोक दिया गया."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"बहुत अधिक प्रयास कर लिए गए हैं. बाद में पुन: प्रयास करें."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"पुन: प्रयास करें."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"अंगुली <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनियां"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"नोटिफ़िकेशन ध्वनि"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">वाई-फ़ाई नेटवर्क उपलब्ध</item>
+ <item quantity="other">वाई-फ़ाई नेटवर्क उपलब्ध</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">खुले वाई-फ़ाई नेटवर्क उपलब्ध</item>
+ <item quantity="other">खुले वाई-फ़ाई नेटवर्क उपलब्ध</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"वाई-फ़ाई नेटवर्क में प्रवेश करें"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्क में प्रवेश करें"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1687,7 +1698,7 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
</plurals>
- <string name="default_notification_channel_label" msgid="5929663562028088222">"वर्गीकृत नहीं"</string>
+ <string name="default_notification_channel_label" msgid="5929663562028088222">"अवर्गीकृत"</string>
<string name="importance_from_user" msgid="7318955817386549931">"आपने इन नोटिफिकेशन का महत्व सेट किया है."</string>
<string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के द्वारा एक नया उपयोगकर्ता बनाने दें?"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e92db84..5fae34d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ažuriranja"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Mrežni status"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Mrežna upozorenja"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Mreža je dostupna"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status VPN-a"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administracija uređaja"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Isteklo je vrijeme čekanja za otisak prsta. Pokušajte ponovo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja otiska prsta otkazana je."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1119,6 +1122,16 @@
<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>
+ <item quantity="other">Dostupne su Wi-Fi mreže</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Dostupne su otvorene Wi-Fi mreže</item>
+ <item quantity="few">Dostupne su otvorene Wi-Fi mreže</item>
+ <item quantity="other">Dostupne su otvorene Wi-Fi mreže</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijava na Wi-Fi mrežu"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 1a370a4..437fac8 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Frissítések"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Hálózati állapot"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Hálózati értesítések"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-állapot"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Eszközfelügyelet"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Értesítések"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Az ujjlenyomat-beolvasási műveletkor időtúllépés történt. Próbálkozzon újra."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Ujjlenyomattal kapcsolatos művelet megszakítva"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Túl sok próbálkozás. Próbálja újra később."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Próbálkozzon újra."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Nyílt Wi-Fi hálózatok érhetők el</item>
+ <item quantity="one">Nyílt Wi-Fi hálózat érhető el</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Bejelentkezés Wi-Fi hálózatba"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Bejelentkezés a hálózatba"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 3035378..90ef155 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Թարմացումներ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Ցանցի կարգավիճակ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Ցանցային զգուշացումներ"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Ցանցը հասանելի է"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN կարգավիճակ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Սարքի կառավարում"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Մատնահետքի գրանցման ժամանակը սպառվել է: Փորձեք նորից:"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Իսկորոշումը մատնահետքի միջոցով չեղարկվեց:"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Չափից շատ փորձ եք կատարել: Փորձեք նորից քիչ հետո:"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Փորձեք նորից:"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
+ <item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Մուտք գործեք Wi-Fi ցանց"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Մուտք գործեք ցանց"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e10075c..4d6a98c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Update"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status jaringan"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Notifikasi jaringan"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Jaringan tersedia"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administrasi perangkat"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikasi"</string>
@@ -474,10 +475,10 @@
<string name="permdesc_nfc" msgid="7120611819401789907">"Mengizinkan apl berkomunikasi dengan tag, kartu, dan alat pembaca Komunikasi Nirkabel Jarak Dekat (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"nonaktifkan kunci layar Anda"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Memungkinkan aplikasi menonaktifkan kunci tombol dan keamanan sandi apa pun yang terkait. Misalnya, ponsel menonaktifkan kunci tombol saat menerima panggilan telepon masuk, kemudian mengaktifkan kembali kunci tombol ketika panggilan selesai."</string>
- <string name="permlab_manageFingerprint" msgid="5640858826254575638">"kelola perangkat keras sidik jari"</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"kelola hardware sidik jari"</string>
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Mengizinkan aplikasi memanggil metode untuk menambahkan dan menghapus template sidik jari untuk digunakan."</string>
- <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan perangkat keras sidik jari"</string>
- <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Mengizinkan aplikasi untuk menggunakan perangkat keras sidik jari untuk otentikasi"</string>
+ <string name="permlab_useFingerprint" msgid="3150478619915124905">"gunakan hardware sidik jari"</string>
+ <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Mengizinkan aplikasi untuk menggunakan hardware sidik jari untuk otentikasi"</string>
<string name="fingerprint_acquired_partial" msgid="735082772341716043">"Sebagian sidik jari terdeteksi. Coba lagi."</string>
<string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Tidak dapat memproses sidik jari. Coba lagi."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Sensor sidik jari kotor. Bersihkan dan coba lagi."</string>
@@ -485,11 +486,13 @@
<string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Jari digerakkan terlalu lambat. Coba lagi."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
- <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Perangkat keras sidik jari tidak tersedia."</string>
+ <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardware sidik jari tidak tersedia."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Sidik jari tidak dapat disimpan. Hapus sidik jari yang ada."</string>
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Waktu sidik jari habis. Coba lagi."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operasi sidik jari dibatalkan."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Terlalu banyak upaya. Coba lagi nanti."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Coba lagi."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Jaringan Wi-Fi terbuka tersedia</item>
+ <item quantity="one">Jaringan Wi-Fi terbuka tersedia</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Masuk ke jaringan Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Masuk ke jaringan"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index c370074..abde513 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Uppfærslur"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Staða netkerfis"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Viðvaranir netkerfis"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Net í boði"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Staða VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Stjórnun tækis"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Tilkynningar"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tímamörk runnu út fyrir fingrafar. Reyndu aftur."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Hætt við fingrafarsaðgerð."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Of margar tilraunir. Reyndu aftur síðar."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Reyndu aftur."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Opin Wi-Fi net í boði</item>
+ <item quantity="other">Opin Wi-Fi net í boði</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Skrá inn á Wi-Fi net"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Skrá inn á net"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8eec4cb..bfa43da 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Aggiornamenti"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Stato della rete"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Avvisi di rete"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Rete disponibile"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stato della VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Amministrazione dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Avvisi"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timeout impronta digitale. Riprova."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operazione associata all\'impronta digitale annullata."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Troppi tentativi. Riprova più tardi."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Riprova."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Apri reti Wi-Fi disponibili</item>
+ <item quantity="one">Apri rete Wi-Fi disponibile</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Accedi a rete Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Accedi alla rete"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 3a9fa55..8fa27fc 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"עדכונים"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"סטטוס הרשת"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"התראות רשת"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"יש רשת זמינה"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"סטטוס ה-VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ניהול מכשירים"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"התראות"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"פעולת טביעת האצבע בוטלה."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"יותר מדי ניסיונות. נסה שוב מאוחר יותר."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"נסה שוב."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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="two">יש רשתות Wi-Fi זמינות</item>
+ <item quantity="many">יש רשתות Wi-Fi זמינות</item>
+ <item quantity="other">יש רשתות Wi-Fi זמינות</item>
+ <item quantity="one">יש רשת Wi-Fi זמינה</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="two">יש רשתות Wi-Fi פתוחות וזמינות</item>
+ <item quantity="many">יש רשתות Wi-Fi פתוחות וזמינות</item>
+ <item quantity="other">יש רשתות Wi-Fi פתוחות וזמינות</item>
+ <item quantity="one">יש רשת Wi-Fi פתוחה וזמינה</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"היכנס לרשת Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"היכנס לרשת"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index c974c3a..7b8316f4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"アップデート"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ネットワークのステータス"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ネットワーク通知"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"ネットワークを利用できます"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN のステータス"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"端末管理"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋の読み取りがタイムアウトになりました。もう一度お試しください。"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"指紋の操作をキャンセルしました。"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"所定の回数以上間違えました。しばらくしてからもう一度お試しください。"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"もう一度お試しください。"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"指紋<xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">複数のWi-Fiオープンネットワークが利用できます</item>
+ <item quantity="one">Wi-Fiオープンネットワークが利用できます</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fiネットワークにログイン"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ネットワークにログインしてください"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 47027c4..54ac190 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"განახლებები"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ქსელის სტატუსი"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ქსელის გაფრთხილებები"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-ის სტატუსი"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"მოწყობილობის ადმინისტრირება"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"გაფრთხილებები"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"თითის ანაბეჭდის ლოდინის დრო ამოიწურა. სცადეთ ხელახლა."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"თითის ანაბეჭდის აღების ოპერაცია გაუქმდა."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ძალიან ბევრი მცდელობა იყო. სცადეთ მოგვიანებით."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ხელახლა სცადეთ"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">ხელმისაწვდომია ღია Wi-Fi ქსელები</item>
+ <item quantity="one">ხელმისაწვდომია ღია Wi-Fi ქსელი</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ქსელთან დაკავშირება"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ქსელში შესვლა"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index bb500a5..c44a28f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Жаңартылған нұсқалар"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Желі күйі"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Желі дабылдары"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Желі қолжетімді"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN күйі"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Құрылғыны басқару"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Дабылдар"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Саусақ ізін күту уақыты бітті. Әрекетті қайталаңыз."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Саусақ ізі операциясынан бас тартылған."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Талпыныстар тым көп. Кейінірек қайталап көріңіз."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Әрекетті қайталаңыз."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> саусағы"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Ашық Wi-Fi желілері қол жетімді</item>
+ <item quantity="one">Ашық Wi-Fi желісі қол жетімді</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi желісіне кіру"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Желіге кіру"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 714d35a..73422bd 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"បច្ចុប្បន្នភាព"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ស្ថានភាពបណ្តាញ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ការជូនដំណឹងអំពីបណ្តាញ"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"មានបណ្តាញ"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"ស្ថានភាព VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ការគ្រប់គ្រងឧបករណ៍"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ការជូនដំណឹង"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ការផ្តិតម្រាមដៃបានអស់ពេល។ សូមព្យាយាមម្តងទៀត។"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"បានបោះបង់ប្រតិបត្តិការស្នាមម្រាមដៃ។"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ព្យាយាមម្ដងទៀត។"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1101,6 +1104,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
+ <item quantity="one">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ចូលបណ្ដាញវ៉ាយហ្វាយ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ចូលទៅបណ្តាញ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 44064e7..da777b6 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"ಅಪ್ಡೇಟ್ಗಳು"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ನೆಟ್ವರ್ಕ್ ಸ್ಥಿತಿ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ನೆಟ್ವರ್ಕ್ ಎಚ್ಚರಿಕೆಗಳು"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN ಸ್ಥಿತಿ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ಸಾಧನ ನಿರ್ವಹಣೆ"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ಎಚ್ಚರಿಕೆಗಳು"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ಬೆರಳಚ್ಚು ಅವಧಿ ಮೀರಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ಬೆರಳಚ್ಚು ಕಾರ್ಯಾಚರಣೆಯನ್ನು ರದ್ದುಮಾಡಲಾಗಿದೆ."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ಹಲವಾರು ಪ್ರಯತ್ನಗಳು. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"ಅಲಾರಮ್ ಧ್ವನಿಗಳು"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ಅಧಿಸೂಚನೆ ಧ್ವನಿಗಳು"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"ಅಪರಿಚಿತ"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item>
+ <item quantity="other">ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item>
+ <item quantity="other">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿವೆ</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1d57301..a16b766 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"업데이트"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"네트워크 상태"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"네트워크 알림"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN 상태"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"기기 관리"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"알림"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"지문 인식 작업이 취소되었습니다."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"다시 시도해 보세요."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">개방형 Wi-Fi 네트워크 사용 가능</item>
+ <item quantity="one">개방형 Wi-Fi 네트워크 사용 가능</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi 네트워크에 로그인"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"네트워크에 로그인"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 526f2cc..2dd273b 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Жаңыртуулар"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Тармактын абалы"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Тармактын эскертүүлөрү"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Жеткиликтүү тармактар"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN абалы"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Түзмөктү администрациялоо"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Эскертүүлөр"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Манжа изин күтүү мөөнөтү бүттү. Кайра аракет кылыңыз."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Манжа изи иш-аракети жокко чыгарылды."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Аракеттер өтө көп болду. Кийинчерээк кайра аракет кылыңыз."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Кайра бир аракеттениңиз."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> манжасы"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Ачык Wi-Fi тармагы жеткиликтүү</item>
+ <item quantity="one">Ачык Wi-Fi тармагы жеткиликтүү</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi түйүнүнө кирүү"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Тармакка кирүү"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 5ad444d..14f9056 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"ອັບເດດ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ສະຖານະເຄືອຂ່າຍ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ແຈ້ງເຕືອນເຄືອຂ່າຍ"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"ສະຖານະ VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ການເບິ່ງແຍງອຸປະກອນ"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ການເຕືອນ"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ເວລາລາຍນີ້ວມືບໍ່ເຂົ້າເຖິງໄດ້. ລອງໃໝ່ອີກ."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ຍົກເລີກການດຳເນີນການລາຍນີ້ວມືແລ້ວ."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ລອງໃໝ່ພາຍຫຼັງ."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ລອງໃໝ່ອີກຄັ້ງ."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ນີ້ວມື <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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">"ບໍ່ຮູ້ຈັກ"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+ <item quantity="one">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">ເປີດເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+ <item quantity="one">ເປີດເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 009afa9..a044747 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Naujiniai"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Tinklo būsena"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Tinklo įspėjimai"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Tinklas pasiekiamas"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN būsena"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Įrenginio administravimas"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Įspėjimai"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Baigėsi kontrolinio kodo nustatymo skirtasis laikas. Bandykite dar kartą."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Kontrolinio kodo operacija atšaukta."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Bandykite dar kartą."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Įspėjimų garsai"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Pranešimų garsai"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Nežinoma"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Pasiekiami „Wi-Fi“ tinklai</item>
+ <item quantity="few">Pasiekiami „Wi-Fi“ tinklai</item>
+ <item quantity="many">Pasiekiami „Wi-Fi“ tinklai</item>
+ <item quantity="other">Pasiekiami „Wi-Fi“ tinklai</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+ <item quantity="few">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+ <item quantity="many">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+ <item quantity="other">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prisijungti prie „Wi-Fi“ tinklo"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prisijungti prie tinklo"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 291a7a2..d8df849 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Atjauninājumi"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Tīkla statuss"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Tīkla brīdinājumi"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Tīkls ir pieejams"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN statuss"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Ierīces administrēšana"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Brīdinājumi"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Pirkstu nospiedumu nolasīšanas aparatūras noildze. Mēģiniet vēlreiz."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Nospieduma darbība neizdevās."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Mēģiniet vēlreiz."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string>
<string-array name="fingerprint_error_vendor">
@@ -1119,6 +1122,16 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Modinātāja signāla skaņas"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Paziņojumu skaņas"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Nezināms"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="zero">Pieejami Wi-Fi tīkli</item>
+ <item quantity="one">Pieejami Wi-Fi tīkli</item>
+ <item quantity="other">Pieejami Wi-Fi tīkli</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="zero">Ir pieejami atvērti Wi-Fi tīkli</item>
+ <item quantity="one">Ir pieejami atvērti Wi-Fi tīkli</item>
+ <item quantity="other">Ir pieejami atvērti Wi-Fi tīkli</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Pierakstieties Wi-Fi tīklā"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Pierakstīšanās tīklā"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mcc505-mnc11/config.xml b/core/res/res/values-mcc505-mnc11/config.xml
new file mode 100644
index 0000000..6d085c1
--- /dev/null
+++ b/core/res/res/values-mcc505-mnc11/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!--Thresholds for LTE dbm in status bar-->
+ <integer-array translatable="false" name="config_lteDbmThresholds">
+ <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
+ <item>-120</item> <!-- SIGNAL_STRENGTH_POOR -->
+ <item>-115</item> <!-- SIGNAL_STRENGTH_MODERATE -->
+ <item>-100</item> <!-- SIGNAL_STRENGTH_GOOD -->
+ <item>-90</item> <!-- SIGNAL_STRENGTH_GREAT -->
+ <item>-44</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-mcc505-mnc71/config.xml b/core/res/res/values-mcc505-mnc71/config.xml
new file mode 100644
index 0000000..6d085c1
--- /dev/null
+++ b/core/res/res/values-mcc505-mnc71/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!--Thresholds for LTE dbm in status bar-->
+ <integer-array translatable="false" name="config_lteDbmThresholds">
+ <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
+ <item>-120</item> <!-- SIGNAL_STRENGTH_POOR -->
+ <item>-115</item> <!-- SIGNAL_STRENGTH_MODERATE -->
+ <item>-100</item> <!-- SIGNAL_STRENGTH_GOOD -->
+ <item>-90</item> <!-- SIGNAL_STRENGTH_GREAT -->
+ <item>-44</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-mcc505-mnc72/config.xml b/core/res/res/values-mcc505-mnc72/config.xml
new file mode 100644
index 0000000..6d085c1
--- /dev/null
+++ b/core/res/res/values-mcc505-mnc72/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!--Thresholds for LTE dbm in status bar-->
+ <integer-array translatable="false" name="config_lteDbmThresholds">
+ <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN -->
+ <item>-120</item> <!-- SIGNAL_STRENGTH_POOR -->
+ <item>-115</item> <!-- SIGNAL_STRENGTH_MODERATE -->
+ <item>-100</item> <!-- SIGNAL_STRENGTH_GOOD -->
+ <item>-90</item> <!-- SIGNAL_STRENGTH_GREAT -->
+ <item>-44</item>
+ </integer-array>
+</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0b14d37..15ad6f5 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ажурирања"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Статус на мрежа"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Известувања на мрежа"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Има достапна мрежа"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-статус"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Управување со уред"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Предупредувања"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Се достигна времето на истекување на отпечатокот. Обидете се повторно."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Операцијата со отпечаток од прст се откажа."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Премногу обиди. Обидете се повторно подоцна."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Обидете се повторно."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Отворени Wi-Fi мрежи се достапни</item>
+ <item quantity="other">Отворени Wi-Fi мрежи се достапни</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Најавете се на мрежа на Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Најавете се на мрежа"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 46ecc09..6d37c1e 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"അപ്ഡേറ്റുകൾ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"നെറ്റ്വർക്ക് നില"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"നെറ്റ്വർക്ക് അലേർട്ടുകൾ"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN നില"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ഉപകരണ അഡ്മിനിസ്ട്രേഷൻ"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"അലേർട്ടുകൾ"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"വിരലടയാളം നൽകേണ്ട സമയം കഴിഞ്ഞു. വീണ്ടും ശ്രമിക്കുക."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ഫിംഗർപ്രിന്റ് പ്രവർത്തനം റദ്ദാക്കി."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"വീണ്ടും ശ്രമിക്കൂ."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"കൈവിരൽ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"അലാറം ശബ്ദങ്ങൾ"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"അറിയിപ്പ് ശബ്ദങ്ങൾ"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"അറിഞ്ഞുകൂടാത്തത്"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">വൈഫൈ നെറ്റ്വർക്കുകൾ ലഭ്യമാണ്</item>
+ <item quantity="one">വൈഫൈ നെറ്റ്വർക്ക് ലഭ്യമാണ്</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">ലഭ്യമായ വൈഫൈ നെറ്റ്വർക്കുകൾ തുറക്കുക</item>
+ <item quantity="one">ലഭ്യമായ വൈഫൈ നെറ്റ്വർക്ക് തുറക്കുക</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"വൈഫൈ നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 0664499..81fc2d1 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Шинэчлэлтүүд"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Сүлжээний төлөв"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Сүлжээний сануулга"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Сүлжээ боломжтой"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN төлөв"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Төхөөрөмжийн удирдлага"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Сануулга"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Хурууны хээ оруулах хугацаа өнгөрсөн байна. Дахин оруулна уу."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Хурууны хээний бүртгэл амжилтгүй боллоо."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Хэтэрхий олон оролдлоо. Түр хүлээгээд дахин оролдоно уу."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Дахин оролдно уу."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
+ <item quantity="one">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Сүлжээнд нэвтэрнэ үү"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 5b732f7..34b0179 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"अद्यतने"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"नेटवर्क स्थिती"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"नेटवर्क सूचना"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"नेटवर्क उपलब्ध"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN स्थिती"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"डिव्हाइस प्रशासन"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"सूचना"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"फिंगरप्रिंट कालबाह्य झाले. पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"फिंगरप्रिंट ऑपरेशन रद्द झाले."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"खूप प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"पुन्हा प्रयत्न करा."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g> बोट"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनी"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना ध्वनी"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">वाय-फाय नेटवर्क उपलब्ध</item>
+ <item quantity="other">वाय-फाय नेटवर्क उपलब्ध</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">खुले वाय-फाय नेटवर्क उपलब्ध</item>
+ <item quantity="other">खुले वाय-फाय नेटवर्क उपलब्ध</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"वाय-फाय नेटवर्कमध्ये साइन इन करा"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 822df5f..4f18074 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Kemas kini"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status rangkaian"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Makluman rangkaian"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Pentadbiran peranti"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Makluman"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tamat masa cap jari dicapai. Cuba lagi."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Pengendalian cap jari dibatalkan."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Cuba lagi."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Bunyi penggera"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bunyi pemberitahuan"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">Rangkaian Wi-Fi tersedia</item>
+ <item quantity="one">Rangkaian Wi-Fi tersedia</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Rangkaian Wi-Fi terbuka tersedia</item>
+ <item quantity="one">Rangkaian Wi-Fi terbuka tersedia</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Log masuk ke rangkaian Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Log masuk ke rangkaian"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 08a9213..fe6d1dc 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"အပ်ဒိတ်များ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ကွန်ရက် အခြေအနေ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ကွန်ရက် သတိပေးချက်များ"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"ကွန်ရက်ချိတ်ဆက်မှု ရရှိနိုင်ပါသည်"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN အခြေအနေ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"စက်ပစ္စည်း စီမံခန့်ခွဲမှု"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"သတိပေးချက်များ"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"လက်ဗွေရာအချိန်ကုန် သွားပါသည်။ ထပ်မံကြိုးစားပါ။"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"လက်ဗွေရာ လုပ်ငန်း ဖျက်သိမ်းခဲ့၏။"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ကြိုးစာမှု အကြိမ်များနေ၏။ နောက်မှ ထပ်မံကြိုးစားပါ။"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ပြန်ကြိုးစားပါ"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်အား ဖွင့်ပါ</item>
+ <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်အား ဖွင့်ပါ</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index bff57a5..578c6c4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Oppdateringer"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Nettverksstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Nettverksvarsler"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhetsadministrasjon"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Varsler"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsavbrudd for fingeravtrykk er nådd. Prøv på nytt."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingeravtrykk-operasjonen ble avbrutt."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"For mange forsøk. Prøve på nytt senere."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Prøv igjen."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Åpne Wi-Fi-nettverk er tilgjengelig</item>
+ <item quantity="one">Åpent Wi-Fi-nettverk er tilgjengelig</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Logg på Wi-Fi-nettverket"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Logg på nettverk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index fb449a3..53dfeb7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"अद्यावधिकहरू"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"नेटवर्कको स्थिति"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"नेटवर्कका अलर्टहरू"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN को स्थिति"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"यन्त्रको प्रशासन"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"अलर्टहरू"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"औँठाछाप सञ्चालन रद्द गरियो।"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"धेरै प्रयासहरू। केहि समय पछि पुन: प्रयास गर्नुहोला"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"पुन: प्रयास गर्नुहोला।"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1105,6 +1109,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other"> खुल्ला Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
+ <item quantity="one">खुल्ला Wi-Fi सञ्जाल उपलब्ध छ</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"सञ्जालमा साइन इन गर्नुहोस्"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index a7794b3..77e54bc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Updates"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Netwerkstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Netwerkmeldingen"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Netwerk beschikbaar"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Apparaatbeheer"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Time-out bereikt voor vingerafdruk. Probeer het opnieuw."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Vingerafdrukbewerking geannuleerd."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Te veel pogingen. Probeer het later opnieuw."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probeer het opnieuw."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Open wifi-netwerken beschikbaar</item>
+ <item quantity="one">Open wifi-netwerk beschikbaar</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Inloggen bij wifi-netwerk"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Inloggen bij netwerk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 559cd34..8d511da 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"ਅੱਪਡੇਟ"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ਨੈੱਟਵਰਕ ਅਵਸਥਾ"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ਨੈੱਟਵਰਕ ਸੁਚੇਤਨਾਵਾਂ"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN ਅਵਸਥਾ"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"ਡੀਵਾਈਸ ਪ੍ਰਸ਼ਾਸਨ"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ਸੁਚੇਤਨਾਵਾਂ"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਾ ਸਮਾਂ ਸਮਾਪਤ ਹੋ ਗਿਆ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ਫਿੰਗਰ"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ. ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ਉਂਗਲ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
+ <item quantity="other">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ਨੈੱਟਵਰਕ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ਨੈੱਟਵਰਕ ਤੇ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c9e6f2b..3a8f7c5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Aktualizacje"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Stan sieci"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alerty dotyczące sieci"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Sieć dostępna"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stan sieci VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administracja urządzeniem"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alerty"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Osiągnięto limit czasu odczytu linii papilarnych. Spróbuj ponownie."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Odczyt odcisku palca został anulowany."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zbyt wiele prób. Spróbuj ponownie później."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Spróbuj ponownie."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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>
+ <item quantity="other">Dostępne są sieci Wi-Fi</item>
+ <item quantity="one">Dostępna jest sieć Wi-Fi</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="few">Dostępne są otwarte sieci Wi-Fi</item>
+ <item quantity="many">Dostępne są otwarte sieci Wi-Fi</item>
+ <item quantity="other">Dostępne są otwarte sieci Wi-Fi</item>
+ <item quantity="one">Dostępna jest otwarta sieć Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Zaloguj się w sieci Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Zaloguj się do sieci"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 1cca43d..421a12e 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Atualizações"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status de rede"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas de rede"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status de VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administração do dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Excesso de tentativas. Tente novamente mais tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Tente novamente."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
+ <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5511917..463b684 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Atualizações"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Estado da rede"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas da rede"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Rede disponível"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Estado da VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administração do dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Foi atingido o limite de tempo da impressão digital. Tente novamente."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Demasiadas tentativas. Tente novamente mais tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Tente novamente."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Redes Wi-Fi abertas disponíveis</item>
+ <item quantity="one">Rede Wi-Fi aberta disponível</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sessão na rede Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Início de sessão na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1cca43d..421a12e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Atualizações"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status de rede"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alertas de rede"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status de VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administração do dispositivo"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tempo máximo para captura da impressão digital atingido. Tente novamente."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operação de impressão digital cancelada."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Excesso de tentativas. Tente novamente mais tarde."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Tente novamente."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
+ <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8ba99cd..4f8f047 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Actualizări"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Starea rețelei"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Alerte privind rețeaua"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Rețea disponibilă"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stare VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administrarea dispozitivului"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Alerte"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Timpul pentru amprentare a expirat. Încercați din nou."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operațiunea privind amprenta a fost anulată."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Prea multe încercări. Încercați din nou mai târziu."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Încercați din nou."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1119,6 +1122,16 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sunete de alarmă"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sunete pentru notificare"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Necunoscut"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="few">Rețele Wi-Fi disponibile</item>
+ <item quantity="other">Rețele Wi-Fi disponibile</item>
+ <item quantity="one">Rețea Wi-Fi disponibilă</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="few">Rețele Wi-Fi deschise disponibile</item>
+ <item quantity="other">Rețele Wi-Fi deschise disponibile</item>
+ <item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la rețeaua Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ab1b85b..4a0ef0c 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Обновления"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Статус сети"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Оповещения сети"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Сеть доступна"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Статус VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Управление устройством"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Уведомления"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Операция с отпечатком отменена."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Слишком много попыток. Повторите позже."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Повторите попытку."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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>
+ <item quantity="many">Есть доступные сети Wi-Fi</item>
+ <item quantity="other">Есть доступные сети Wi-Fi</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Есть открытые сети Wi-Fi</item>
+ <item quantity="few">Есть открытые сети Wi-Fi</item>
+ <item quantity="many">Есть открытые сети Wi-Fi</item>
+ <item quantity="other">Есть открытые сети Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Подключение к Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Регистрация в сети"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index e3f72d9..a738032 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"යාවත්කාලීන කිරීම්"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"ජාල තත්ත්වය"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"ජාල ඇඟවීම්"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"ජාලය ලබා ගැනීමට හැකිය"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN තත්ත්වය"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"උපාංග පරිපාලනය"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"ඇඟවීම්"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"ඇඟිලි සලකුණු කාල නිමාව ළඟා විය. නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ඇඟිලි සලකුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"උත්සාහයන් ඉතා වැඩි ගණනකි. කරුණාකර පසුව නැවත උත්සාහ කරන්න."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"නැවත උත්සාහ කරන්න."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1101,6 +1104,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">විවෘත Wi-Fi ජාල තිබේ</item>
+ <item quantity="other">විවෘත Wi-Fi ජාල තිබේ</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ජාලයට පුරනය වන්න"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ජාලයට පුරනය වන්න"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index fa725e4..e942b95 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -266,6 +266,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Aktualizácie"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Stav siete"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Upozornenia týkajúce sa siete"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stav pripojenia VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Správa zariadenia"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornenia"</string>
@@ -496,6 +498,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Časový limit rozpoznania odtlačku vypršal. Skúste to znova."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operácia týkajúca sa odtlačku prsta bola zrušená"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Príliš veľa pokusov. Skúste to znova neskôr."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Skúste to znova"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1143,18 @@
<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>
+ <item quantity="other">K dispozícii sú siete Wi-Fi</item>
+ <item quantity="one">K dispozícii je sieť Wi-Fi</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="few">K dispozícii sú verejné siete Wi-Fi</item>
+ <item quantity="many">K dispozícii sú verejné siete Wi-Fi</item>
+ <item quantity="other">K dispozícii sú verejné siete Wi-Fi</item>
+ <item quantity="one">K dispozícii je verejná sieť Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prihlásiť sa do siete Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prihlásenie do siete"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9b9b4a3..646eba1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Posodobitve"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Stanje omrežja"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Opozorila omrežja"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Omrežje je na voljo"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Stanje omrežja VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Skrbništvo naprave"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Opozorila"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Dosežena časovna omejitev za prstni odtis. Poskusite znova."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Dejanje s prstnim odtisom je bilo preklicano."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Preveč poskusov. Poskusite znova pozneje."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Poskusite znova."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvoki alarma"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvoki obvestil"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Neznano"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Na voljo so omrežja Wi-Fi</item>
+ <item quantity="two">Na voljo so omrežja Wi-Fi</item>
+ <item quantity="few">Na voljo so omrežja Wi-Fi</item>
+ <item quantity="other">Na voljo so omrežja Wi-Fi</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Na voljo so odprta omrežja Wi-Fi</item>
+ <item quantity="two">Na voljo so odprta omrežja Wi-Fi</item>
+ <item quantity="few">Na voljo so odprta omrežja Wi-Fi</item>
+ <item quantity="other">Na voljo so odprta omrežja Wi-Fi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavite se v omrežje Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Prijava v omrežje"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cc37389..283ec35 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Përditësimet"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Statusi i rrjetit"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Sinjalizimet e rrjetit"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Ka rrjet të disponueshëm"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Statusi i VPN-së"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Administrimi i pajisjes"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Sinjalizimet"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Koha e veprimit për gjurmën e gishtit skadoi. Provo përsëri."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Operacioni i gjurmës së gishtit u anulua."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Keni bërë shumë tentativa. Provo përsëri më vonë."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Provo përsëri."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Tingujt e alarmeve"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tingujt e njoftimeve"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"E panjohur"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">Rrjete Wi-Fi ofrohen për përdorim</item>
+ <item quantity="one">Një rrjet Wi-Fi ofrohet për përdorim</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Rrjete të hapura Wi-Fi në përdorim</item>
+ <item quantity="one">Rrjet i hapur Wi-Fi në përdorim</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Identifikohu në rrjetin Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Identifikohu në rrjet"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index fafd4f7..3b4d194 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -263,6 +263,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Ажурирања"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Статус мреже"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Обавештења у вези са мрежом"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Мрежа је доступна"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Статус VPN-а"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Администрирање уређаја"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Обавештења"</string>
@@ -493,6 +494,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Радња са отиском прста је отказана."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Пробајте поново касније."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Пробајте поново."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1119,6 +1122,16 @@
<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>
+ <item quantity="other">Wi-Fi мреже су доступне</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Отворене Wi-Fi мреже су доступне</item>
+ <item quantity="few">Отворене Wi-Fi мреже су доступне</item>
+ <item quantity="other">Отворене Wi-Fi мреже су доступне</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Пријављивање на Wi-Fi мрежу"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Пријавите се на мрежу"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e3f0f2a..8c6071c 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Uppdateringar"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Nätverksstatus"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Nätverksvarningar"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN-status"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Enhetsadministration"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Varningar"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Tidsgränsen för fingeravtrycket har uppnåtts. Försök igen."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Fingeravtrycksåtgärden avbröts."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Du har gjort för många försök. Försök igen senare."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Försök igen."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Öppna Wi-Fi-nätverk är tillgängliga</item>
+ <item quantity="one">Öppet Wi-Fi-nätverk är tillgängligt</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Logga in på ett Wi-Fi-nätverk"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Logga in på nätverket"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cff69f2..21a5271 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -164,7 +164,7 @@
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Ukurasa unajumlisha mielekezo mingi ya seva."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Itifaki haiauniwi."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Haikuweza kuanzisha muunganisho salama."</string>
- <string name="httpErrorBadUrl" msgid="3636929722728881972">"Haikuweza kufungua ukurasa kwa sababu URL ni batili."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"Ukurasa haukuweza kufunguka kwa sababu URL si sahihi."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"Haikuweza kufikia faili."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Haikuweza kupata faili inayohitajika."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Maombi mengi sana yanashughulikiwa. Jaribu tena baadaye."</string>
@@ -207,7 +207,7 @@
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"Inajiandaa kusasisha..."</string>
<string name="reboot_to_update_package" msgid="3871302324500927291">"Inachakata kifurushi cha kusasisha…"</string>
<string name="reboot_to_update_reboot" msgid="6428441000951565185">"Inazima na kuwasha upya..."</string>
- <string name="reboot_to_reset_title" msgid="4142355915340627490">"Rejesha data ya mwanzo"</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"Rejesha mipangilio ya kiwandani"</string>
<string name="reboot_to_reset_message" msgid="2432077491101416345">"Inazima na kuwasha upya..."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Inafunga..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Kompyuta kibao yako itazima."</string>
@@ -258,6 +258,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Taarifa"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Hali ya mtandao"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Arifa za mtandao"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Mtandao unapatikana"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Hali ya VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Udhibiti wa kifaa"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Arifa"</string>
@@ -488,6 +489,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Muda wa kitambulisho umekwisha. Jaribu tena."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Utendaji wa kitambulisho imeghairiwa."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Majaribio mengi mno. Jaribu tena baadaye."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Jaribu tena."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Kitambulisho <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -567,7 +570,7 @@
<string name="policylab_forceLock" msgid="2274085384704248431">"Kufunga skrini"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Kudhibiti jinsi na wakati skrini inapofunga."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Kufuta data yote"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Futa data ya kompyuta kibao bila ilani kwa kurejesha mipangilio ya mwanzo."</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Futa data ya kompyuta kibao bila ilani kwa kurejesha mipangilio ambayo kompyuta ilitoka nayo kiwandani."</string>
<string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Futa data ya runinga bila onyo kwa kurejesha katika hali iliyotoka nayo kiwandani."</string>
<string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Kufuta data ya simu bila ilani kwa kurejesha data ambayo kifaa kilitoka nayo kiwandani"</string>
<string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Futa data yote ya mtumiaji"</string>
@@ -747,9 +750,9 @@
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> bila kufaulu, utaulizwa kufungua kompyuta yako ndogo kwa kuingia kwa Google.\n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Umekosea kuchora mchoro wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, utaombwa ufungue runinga yako ukitumia Google.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, utaulizwa kufungua simu kupitia kuingia Google.\n\n Jaribu tena katika sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya zaidi ya <xliff:g id="NUMBER_1">%2$d</xliff:g> majaribio yasiyofanikiwa, kompyuta ndogo itawekwa upya kwa kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Umejaribu kufungua kompyuta kibao kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukijaribu tena mara <xliff:g id="NUMBER_1">%2$d</xliff:g> bila mafanikio, kompyuta ndogo itarejeshwa kwenye mipangilio iliyotoka nayo kiwandani na data yote iliyomo itafutwa."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi, runinga itarejeshwa katika hali iliyotoka nayo kiwandani na data yote ya watumiaji itafutwa."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> zaidi yasiyofanikiwa, simu itawekwa upya kwa kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukijaribu tena mara <xliff:g id="NUMBER_1">%2$d</xliff:g> bila mafanikio, simu itarejeshwa kwenye mipangilio iliyotoka nayo kiwandani na data yote iliyomo itafutwa."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguo-msingi."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Umekosea majaribio ya kufungua runinga mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa runinga itarejeshwa katika mipangilio iliyotoka nayo kiwandani."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Kompyuta ndogo haitaweza kuwekwa upya kwa kiwanda chaguo-msingi."</string>
@@ -1097,6 +1100,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Fungua mitandao ya Wi-Fi inayopatikana</item>
+ <item quantity="one">Fungua mtandao wa Wi-Fi unaopatikana</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Ingia kwa mtandao wa Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Ingia katika mtandao"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1741,13 +1752,13 @@
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Andika wakati"</string>
<string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Badilisha iwe katika hali ya maandishi wakati wa kuweka muda."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Badilisha umbo liwe la saa ya mishale wakati wa kuweka muda."</string>
- <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Chaguo za kujaza otomatiki"</string>
+ <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Chaguo za kujaza kiotomatiki"</string>
<string name="autofill_save_accessibility_title" msgid="7244365268417107822">"Hifadhi kwa ajili ya Kujaza Kiotomatiki"</string>
<string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"Maudhui hayawezi kujazwa kiotomatiki"</string>
- <string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"Hakuna mapendekezo ya kujaza otomatiki"</string>
+ <string name="autofill_picker_no_suggestions" msgid="3908514303773350735">"Hakuna mapendekezo ya kujaza kiotomatiki"</string>
<plurals name="autofill_picker_some_suggestions" formatted="false" msgid="5506565809835815274">
- <item quantity="other">Mapendekezo <xliff:g id="COUNT">%1$s</xliff:g> ya kujaza otomatiki</item>
- <item quantity="one">Pendekezo moja la kujaza otomatiki</item>
+ <item quantity="other">Mapendekezo <xliff:g id="COUNT">%1$s</xliff:g> ya kujaza kiotomatiki</item>
+ <item quantity="one">Pendekezo moja la kujaza kiotomatiki</item>
</plurals>
<string name="autofill_save_title" msgid="3345527308992082601">"Ungependa kuhifadhi kwenye <b><xliff:g id="LABEL">%1$s</xliff:g></b>?"</string>
<string name="autofill_save_title_with_type" msgid="8637809388029313305">"Ungependa kuhifadhi <xliff:g id="TYPE">%1$s</xliff:g> kwenye <b><xliff:g id="LABEL">%2$s</xliff:g></b>?"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 5b3eb5d2..0c9a263 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"புதுப்பிப்புகள்"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"நெட்வொர்க்கின் நிலை"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"நெட்வொர்க் விழிப்பூட்டல்கள்"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"நெட்வொர்க் உள்ளது"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN நிலை"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"சாதன நிர்வாகம்"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"விழிப்பூட்டல்கள்"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"கைரேகைக்கான நேரம் முடிந்தது. மீண்டும் முயலவும்."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"கைரேகை செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"அதிகமான முயற்சிகள். பிறகு முயற்சிக்கவும்."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"மீண்டும் முயற்சிக்கவும்."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"அலார ஒலிகள்"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"அறிவிப்பு ஒலிகள்"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"தெரியாதது"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
+ <item quantity="one">வைஃபை நெட்வொர்க் உள்ளது</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">பொது வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
+ <item quantity="one">பொது வைஃபை நெட்வொர்க் உள்ளது</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index dac485c..adfe2c4 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"నవీకరణలు"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"నెట్వర్క్ స్థితి"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"నెట్వర్క్ హెచ్చరికలు"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN స్థితి"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"పరికర నిర్వాహణ"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"హెచ్చరికలు"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"వేలిముద్ర కార్యాచరణ రద్దయింది."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">ఓపెన్ Wi-Fi నెట్వర్క్లు అందుబాటులో ఉన్నాయి</item>
+ <item quantity="one">ఓపెన్ Wi-Fi నెట్వర్క్ అందుబాటులో ఉంది</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e34d1e0..a1d7faa 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"การอัปเดต"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"สถานะเครือข่าย"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"การแจ้งเตือนเครือข่าย"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"มีเครือข่ายพร้อมใช้งาน"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"สถานะ VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"การดูแลระบบอุปกรณ์"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"การแจ้งเตือน"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"หมดเวลาใช้ลายนิ้วมือแล้ว โปรดลองอีกครั้ง"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"ยกเลิกการทำงานของลายนิ้วมือ"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"ลองอีกครั้ง"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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">มี 1 เครือข่าย Wi-Fi ที่ใช้งานได้</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">มีหลายเครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
+ <item quantity="one">มี 1 เครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ลงชื่อเข้าใช้เครือข่าย"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index dea07be..a28050f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Mga Update"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Status ng network"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Mga alerto sa network"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Available ang network"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Status ng VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Pamamahala ng device"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Mga Alerto"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Nag-time out ang fingerprint. Subukang muli."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Nakansela ang operasyong ginagamitan ng fingerprint."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Masyadong maraming beses sumubok. Subukang muli sa ibang pagkakataon."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Subukang muli."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Mga tunog ng alarm"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Mga tunog ng notification"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Hindi Alam"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Available ang mga Wi-Fi network</item>
+ <item quantity="other">Available ang mga Wi-Fi network</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Available ang mga bukas na Wi-Fi network</item>
+ <item quantity="other">Available ang mga bukas na Wi-Fi network</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Mag-sign in sa Wi-Fi network"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Mag-sign in sa network"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 55acdac..e447d73 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Güncellemeler"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Ağ durumu"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Ağ uyarıları"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN durumu"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Cihaz yönetimi"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Uyarılar"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Parmak izi için zaman aşımı oluştu. Tekrar deneyin."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Parmak izi işlemi iptal edildi."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Tekrar deneyin."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm sesleri"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirim sesleri"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Bilinmiyor"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">Kablosuz ağlar var</item>
+ <item quantity="one">Kablosuz ağ var</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Kullanılabilir Kablosuz ağları aç</item>
+ <item quantity="one">Kullanılabilir Kablosuz ağı aç</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Kablosuz ağda oturum açın"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Ağda oturum açın"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 60e2cc0..f7942ac 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -266,6 +266,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Оновлення"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Статус мережі"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Сповіщення мережі"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Мережа доступна"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Статус мережі VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Адміністрування пристрою"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Сповіщення"</string>
@@ -496,6 +497,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Час очікування відбитка минув. Повторіть спробу."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Дію з відбитком скасовано."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Забагато спроб. Спробуйте пізніше."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Повторіть спробу."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1139,6 +1142,18 @@
<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>
+ <item quantity="many">Мережі Wi-Fi доступні</item>
+ <item quantity="other">Мережі Wi-Fi доступні</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Відкриті мережі Wi-Fi доступні</item>
+ <item quantity="few">Відкриті мережі Wi-Fi доступні</item>
+ <item quantity="many">Відкриті мережі Wi-Fi доступні</item>
+ <item quantity="other">Відкриті мережі Wi-Fi доступні</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Вхід у мережу Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Вхід у мережу"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 9719836..1c1b2a8 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"اپ ڈیٹس"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"نیٹ ورک اسٹیٹس"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"نیٹ ورک الرٹس"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN اسٹیٹس"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"آلہ کا نظم و نسق"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"الرٹس"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"فنگر پرنٹ کی کارروائی منسوخ ہوگئی۔"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوبارہ کوشش کریں۔"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"دوبارہ کوشش کریں۔"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">عوامی Wi-Fi نیٹ ورکس دستیاب ہیں</item>
+ <item quantity="one">عوامی Wi-Fi نیٹ ورک دستیاب ہے</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"نیٹ ورک میں سائن ان کریں"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a7c3be7..52f7d79 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Yangilanishlar"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Tarmoq holati"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Tarmoqqa oid bildirgilar"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Tarmoq mavjud"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN holati"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Qurilma boshqaruvi"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Ogohlantirishlar"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmoq izini aniqlash vaqti tugab qoldi. Qayta urinib ko‘ring."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Barmoq izi tekshiruvi bekor qilindi."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Urinishlar soni ko‘payib ketdi. Keyinroq qayta urinib ko‘ring."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Qayta urinib ko‘ring."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -768,7 +771,7 @@
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Tekshirilmoqda…"</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Qulfdan chiqarish"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Ovozni yoqish"</string>
- <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Ovozni o‘chirish"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Ovozsiz qilish"</string>
<string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Grafik kalitni chizish boshlandi"</string>
<string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Grafik kalit tozalandi"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Katak qo‘shildi"</string>
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Ochiq Wi-Fi tarmoqlari aniqlandi</item>
+ <item quantity="one">Ochiq Wi-Fi tarmog‘i aniqlandi</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi tarmoqqa kirish"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 97e27d4..db8df0d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Cập nhật"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Trạng thái mạng"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Cảnh báo mạng"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Có mạng"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Trạng thái VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Quản lý thiết bị"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Cảnh báo"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Đã hết thời gian chờ vân tay. Hãy thử lại."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Thao tác dùng dấu vân tay bị hủy."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Quá nhiều lần thử. Hãy thử lại sau."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Thử lại."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Âm thanh báo thức"</string>
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Âm thanh thông báo"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"Không xác định"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="other">Các mạng Wi-Fi khả dụng</item>
+ <item quantity="one">Mạng Wi-Fi khả dụng</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">Mở các mạng Wi-Fi khả dụng</item>
+ <item quantity="one">Mở mạng Wi-Fi khả dụng</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Đăng nhập vào mạng Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Đăng nhập vào mạng"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cf703dd..89b2e57 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"更新"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"网络状态"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"网络提醒"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN 状态"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"设备管理"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"提醒"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"指纹操作已取消。"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"尝试次数过多,请稍后重试。"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"请重试。"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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">有可用的 WLAN 网络</item>
+ <item quantity="one">有可用的 WLAN 网络</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">有可用的开放 WLAN 网络</item>
+ <item quantity="one">有可用的开放 WLAN 网络</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"登录到WLAN网络"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"登录到网络"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0cecfb9..c5ec77c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"更新"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"網絡狀態"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"網絡通知"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN 狀態"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"裝置管理"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋已逾時。請再試一次。"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"指紋操作已取消。"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"嘗試次數過多,請稍後再試。"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"再試一次。"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">有可用的公開 Wi-Fi 網絡</item>
+ <item quantity="one">有可用的公開 Wi-Fi 網絡</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網絡"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"登入網絡"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 43782c3..6e63cee 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -260,6 +260,8 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"更新"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"網路狀態"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"網路警示"</string>
+ <!-- no translation found for notification_channel_network_available (4531717914138179517) -->
+ <skip />
<string name="notification_channel_vpn" msgid="8330103431055860618">"VPN 狀態"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"裝置管理"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"快訊"</string>
@@ -490,6 +492,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"指紋作業已取消。"</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"嘗試次數過多,請稍後再試。"</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"請再試一次。"</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1103,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="other">有多個可用的開放 Wi-Fi 網路</item>
+ <item quantity="one">有多個可用的開放 Wi-Fi 網路</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網路"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"登入網路"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a8dfd47..1900f8b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -260,6 +260,7 @@
<string name="notification_channel_updates" msgid="4794517569035110397">"Izibuyekezo"</string>
<string name="notification_channel_network_status" msgid="5025648583129035447">"Isimo senethiwekhi"</string>
<string name="notification_channel_network_alerts" msgid="2895141221414156525">"Izexwayiso zenethiwekhi"</string>
+ <string name="notification_channel_network_available" msgid="4531717914138179517">"Inethiwekhi iyatholakala"</string>
<string name="notification_channel_vpn" msgid="8330103431055860618">"Isimo se-VPN"</string>
<string name="notification_channel_device_admin" msgid="1568154104368069249">"Ukulawula idivayisi"</string>
<string name="notification_channel_alerts" msgid="4496839309318519037">"Izexwayiso"</string>
@@ -490,6 +491,8 @@
<string name="fingerprint_error_timeout" msgid="3927186043737732875">"Kufinyelelwe isikhathi sokuvala sezigxivizo zeminwe. Zama futhi"</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Ukusebenza kwezingxivizo zeminwe kukhanseliwe."</string>
<string name="fingerprint_error_lockout" msgid="5536934748136933450">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
+ <!-- no translation found for fingerprint_error_lockout_permanent (5033251797919508137) -->
+ <skip />
<string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Zama futhi."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
@@ -1099,6 +1102,14 @@
<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>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
+ <item quantity="other">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
+ </plurals>
<string name="wifi_available_sign_in" msgid="9157196203958866662">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"Ngena ngemvume kunethiwekhi"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index be53f2c..c7b0b35 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2908,6 +2908,11 @@
<!-- Default data warning level in mb -->
<integer name="default_data_warning_level_mb">2048</integer>
+ <!-- When true, indicates that the vendor's IMS implementation requires a workaround when
+ sending a request to enable or disable the camera while the video session is also
+ paused. -->
+ <bool name="config_useVideoPauseWorkaround">false</bool>
+
<!-- Whether to send a custom package name with the PSD.-->
<bool name="config_sendPackageName">false</bool>
@@ -2947,4 +2952,10 @@
<!-- Volume level of in-call notification tone playback,
relative to the overall voice call stream volume [0..100] -->
<integer name="config_inCallNotificationVolumeRelative">67</integer>
+
+ <!-- The OEM specified sensor type for the lift trigger to launch the camera app. -->
+ <integer name="config_cameraLiftTriggerSensorType">-1</integer>
+ <!-- The OEM specified sensor string type for the gesture to launch camera app, this value
+ must match the value of config_cameraLiftTriggerSensorType in OEM's HAL -->
+ <string translatable="false" name="config_cameraLiftTriggerSensorStringType"></string>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 42d3f27..4868774 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2761,81 +2761,80 @@
<eat-comment />
<public type="attr" name="visibleToInstantApps" id="0x01010531" />
+ <public type="attr" name="font" id="0x01010532" />
+ <public type="attr" name="fontWeight" id="0x01010533" />
+ <public type="attr" name="tooltipText" id="0x01010534" />
+ <public type="attr" name="autoSizeTextType" id="0x01010535" />
+ <public type="attr" name="autoSizeStepGranularity" id="0x01010536" />
+ <public type="attr" name="autoSizePresetSizes" id="0x01010537" />
+ <public type="attr" name="autoSizeMinTextSize" id="0x01010538" />
+ <public type="attr" name="min" id="0x01010539" />
+ <public type="attr" name="rotationAnimation" id="0x0101053a" />
+ <public type="attr" name="layout_marginHorizontal" id="0x0101053b" />
+ <public type="attr" name="layout_marginVertical" id="0x0101053c" />
+ <public type="attr" name="paddingHorizontal" id="0x0101053d" />
+ <public type="attr" name="paddingVertical" id="0x0101053e" />
+ <public type="attr" name="fontStyle" id="0x0101053f" />
+ <public type="attr" name="keyboardNavigationCluster" id="0x01010540" />
+ <public type="attr" name="targetProcesses" id="0x01010541" />
+ <public type="attr" name="nextClusterForward" id="0x01010542" />
+ <public type="attr" name="colorError" id="0x01010543" />
+ <public type="attr" name="focusedByDefault" id="0x01010544" />
+ <public type="attr" name="appCategory" id="0x01010545" />
+ <public type="attr" name="autoSizeMaxTextSize" id="0x01010546" />
+ <public type="attr" name="recreateOnConfigChanges" id="0x01010547" />
+ <public type="attr" name="certDigest" id="0x01010548" />
+ <public type="attr" name="splitName" id="0x01010549" />
+ <public type="attr" name="colorMode" id="0x0101054a" />
+ <public type="attr" name="isolatedSplits" id="0x0101054b" />
+ <public type="attr" name="targetSandboxVersion" id="0x0101054c" />
+ <public type="attr" name="canRequestFingerprintGestures" id="0x0101054d" />
+ <public type="attr" name="alphabeticModifiers" id="0x0101054e" />
+ <public type="attr" name="numericModifiers" id="0x0101054f" />
+ <public type="attr" name="fontProviderAuthority" id="0x01010550" />
+ <public type="attr" name="fontProviderQuery" id="0x01010551" />
+ <public type="attr" name="primaryContentAlpha" id="0x01010552" />
+ <public type="attr" name="secondaryContentAlpha" id="0x01010553" />
+ <public type="attr" name="requiredFeature" id="0x01010554" />
+ <public type="attr" name="requiredNotFeature" id="0x01010555" />
+ <public type="attr" name="autofillHints" id="0x01010556" />
+ <public type="attr" name="fontProviderPackage" id="0x01010557" />
+ <public type="attr" name="importantForAutofill" id="0x01010558" />
+ <public type="attr" name="recycleEnabled" id="0x01010559"/>
+ <public type="attr" name="isStatic" id="0x0101055a" />
+ <public type="attr" name="isFeatureSplit" id="0x0101055b" />
+ <public type="attr" name="singleLineTitle" id="0x0101055c" />
+ <public type="attr" name="fontProviderCerts" id="0x0101055d" />
+ <public type="attr" name="iconTint" id="0x0101055e" />
+ <public type="attr" name="iconTintMode" id="0x0101055f" />
+ <public type="attr" name="maxAspectRatio" id="0x01010560"/>
+ <public type="attr" name="iconSpaceReserved" id="0x01010561"/>
+ <public type="attr" name="defaultFocusHighlightEnabled" id="0x01010562" />
+ <public type="attr" name="persistentWhenFeatureAvailable" id="0x01010563"/>
+ <public type="attr" name="windowSplashscreenContent" id="0x01010564" />
+ <!-- @hide @SystemApi -->
+ <public type="attr" name="requiredSystemPropertyName" id="0x01010565" />
+ <!-- @hide @SystemApi -->
+ <public type="attr" name="requiredSystemPropertyValue" id="0x01010566" />
+ <public type="attr" name="justificationMode" id="0x01010567" />
+ <public type="attr" name="autofilledHighlight" id="0x01010568" />
- <public-group type="attr" first-id="0x01010532">
- <public name="font" />
- <public name="fontWeight" />
- <public name="tooltipText" />
- <public name="autoSizeTextType" />
- <public name="autoSizeStepGranularity" />
- <public name="autoSizePresetSizes" />
- <public name="autoSizeMinTextSize" />
- <public name="min" />
- <public name="rotationAnimation" />
- <public name="layout_marginHorizontal" />
- <public name="layout_marginVertical" />
- <public name="paddingHorizontal" />
- <public name="paddingVertical" />
- <public name="fontStyle" />
- <public name="keyboardNavigationCluster" />
- <public name="targetProcesses" />
- <public name="nextClusterForward" />
- <public name="__removed1" />
- <public name="colorError" />
- <public name="focusedByDefault" />
- <public name="appCategory" />
- <public name="autoSizeMaxTextSize" />
- <public name="__removed2" />
- <public name="recreateOnConfigChanges" />
- <public name="certDigest" />
- <public name="splitName" />
- <public name="colorMode" />
- <public name="isolatedSplits" />
- <public name="targetSandboxVersion" />
- <public name="canRequestFingerprintGestures" />
- <public name="alphabeticModifiers" />
- <public name="numericModifiers" />
- <public name="fontProviderAuthority" />
- <public name="fontProviderQuery" />
- <public name="__removed3" />
- <public name="primaryContentAlpha" />
- <public name="secondaryContentAlpha" />
- <public name="requiredFeature" />
- <public name="requiredNotFeature" />
- <public name="autofillHints" />
- <public name="fontProviderPackage" />
- <public name="importantForAutofill" />
- <public name="recycleEnabled"/>
- <public name="isStatic" />
- <public name="isFeatureSplit" />
- <public name="singleLineTitle" />
- <public name="fontProviderCerts" />
- <public name="iconTint" />
- <public name="iconTintMode" />
- <public name="maxAspectRatio"/>
- <public name="iconSpaceReserved"/>
- <public name="defaultFocusHighlightEnabled" />
- <public name="persistentWhenFeatureAvailable"/>
- <public name="windowSplashscreenContent" />
- <!-- @hide @SystemApi -->
- <public name="requiredSystemPropertyName" />
- <!-- @hide @SystemApi -->
- <public name="requiredSystemPropertyValue" />
- <public name="justificationMode" />
- <public name="autofilledHighlight" />
+ <public type="id" name="textAssist" id="0x01020041" />
+ <public type="id" name="accessibilityActionMoveWindow" id="0x01020042" />
+ <public type="id" name="autofill" id="0x01020043" />
+
+ <public type="string" name="paste_as_plain_text" id="0x01040019" />
+
+ <public-group type="attr" first-id="0x01010569">
</public-group>
<public-group type="style" first-id="0x010302e0">
</public-group>
- <public-group type="id" first-id="0x01020041">
- <public name="textAssist" />
- <public name="accessibilityActionMoveWindow" />
- <public name="autofill" />
+ <public-group type="id" first-id="0x01020044">
</public-group>
- <public-group type="string" first-id="0x01040019">
- <public name="paste_as_plain_text" />
+ <public-group type="string" first-id="0x0104001a">
</public-group>
<!-- ===============================================================
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 21ab4c3..cf4af9a 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1335,6 +1335,8 @@
<string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
<!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
<string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+ <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
+ <string name="fingerprint_error_lockout_permanent">Too many attempts. Fingerprint sensor disabled.</string>
<!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
<string name="fingerprint_error_unable_to_process">Try again.</string>
@@ -3228,7 +3230,7 @@
<skip />
<!-- Name of notification channel the system post notification to inform the use about apps
that are drawing ui on-top of other apps (alert-windows) [CHAR LIMIT=NONE] -->
- <string name="alert_windows_notification_channel_name"><xliff:g id="name" example="Google Maps">%s</xliff:g> displaying over other apps</string>
+ <string name="alert_windows_notification_channel_name">App activity</string>
<!-- Notification title when an application is displaying ui on-top of other apps
[CHAR LIMIT=30] -->
<string name="alert_windows_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is displaying over other apps</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 16e933a..aa586b7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2289,6 +2289,7 @@
<java-symbol type="array" name="fingerprint_acquired_vendor" />
<java-symbol type="string" name="fingerprint_error_canceled" />
<java-symbol type="string" name="fingerprint_error_lockout" />
+ <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
<java-symbol type="string" name="fingerprint_name_template" />
<!-- Fingerprint config -->
@@ -2522,6 +2523,8 @@
<java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
<java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
<java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
+ <java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
+ <java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
<java-symbol type="drawable" name="platlogo_m" />
@@ -2952,7 +2955,7 @@
<java-symbol type="id" name="label_error"/>
<java-symbol type="layout" name="time_picker_text_input_material"/>
<java-symbol type="drawable" name="btn_keyboard_key_material"/>
- <java-symbol type="drawable" name="btn_event_material"/>
+ <java-symbol type="drawable" name="btn_clock_material"/>
<java-symbol type="string" name="time_picker_text_input_mode_description"/>
<java-symbol type="string" name="time_picker_radial_mode_description"/>
@@ -3017,7 +3020,7 @@
<java-symbol type="bool" name="enable_pbap_pce_profile" />
<java-symbol type="integer" name="default_data_warning_level_mb" />
-
+ <java-symbol type="bool" name="config_useVideoPauseWorkaround" />
<java-symbol type="bool" name="config_sendPackageName" />
<java-symbol type="string" name="config_helpPackageNameKey" />
<java-symbol type="string" name="config_helpPackageNameValue" />
diff --git a/core/tests/coretests/res/layout/messaging_linear_layout_test.xml b/core/tests/coretests/res/layout/messaging_linear_layout_test.xml
index 8ba3e07..9e70ca3 100644
--- a/core/tests/coretests/res/layout/messaging_linear_layout_test.xml
+++ b/core/tests/coretests/res/layout/messaging_linear_layout_test.xml
@@ -19,7 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:maxHeight="300px"
android:spacing="5px">
</com.android.internal.widget.MessagingLinearLayout>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
index 1850d57..c83e798 100644
--- a/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
+++ b/core/tests/coretests/src/android/app/LoaderLifecycleTest.java
@@ -17,6 +17,13 @@
package android.app;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertNotSame;
+import static junit.framework.TestCase.assertSame;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.content.Context;
import android.os.Handler;
import android.os.Parcelable;
@@ -24,14 +31,11 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import static junit.framework.TestCase.assertNotNull;
-import static junit.framework.TestCase.assertNotSame;
-import static junit.framework.TestCase.assertSame;
-
@RunWith(AndroidJUnit4.class)
public class LoaderLifecycleTest {
@Rule
@@ -203,6 +207,16 @@
// Test that the fragments are in the configuration we expect
final Fragment restoredOne = fm2.findFragmentByTag("one");
+ try {
+ restoredOne.getLoaderManager();
+ fail("A restored fragment on the back stack doesn't have a host, so it should "
+ + "throw an exception");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ fm2.popBackStackImmediate();
+ // Now restoredOne should be added and should be in a good state.
+ assertTrue(restoredOne.isAdded());
final LoaderManager lm2 = restoredOne.getLoaderManager();
assertSame("didn't get same LoaderManager instance back", lm2, lm1);
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
new file mode 100644
index 0000000..ac1ac19
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app;
+
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.session.MediaSession;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.NotificationColorUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ @Test
+ public void testColorSatisfiedWhenBgDarkTextDarker() {
+ Notification.Builder builder = getMediaNotification();
+ builder.build();
+
+ // An initial guess where the foreground color is actually darker than an already dark bg
+ int backgroundColor = 0xff585868;
+ int initialForegroundColor = 0xff505868;
+ builder.setColorPalette(backgroundColor, initialForegroundColor);
+ int primaryTextColor = builder.getPrimaryTextColor();
+ assertTrue(satisfiesTextContrast(primaryTextColor, backgroundColor));
+ int secondaryTextColor = builder.getSecondaryTextColor();
+ assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor));
+ }
+
+ private Notification.Builder getMediaNotification() {
+ MediaSession session = new MediaSession(mContext, "test");
+ return new Notification.Builder(mContext, "color")
+ .setSmallIcon(com.android.internal.R.drawable.emergency_icon)
+ .setContentTitle("Title")
+ .setContentText("Text")
+ .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
+ }
+}
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index e9e3a18..2470e87 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -16,16 +16,14 @@
package android.app.admin;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/** Unit tests for {@link PasswordMetrics}. */
@RunWith(AndroidJUnit4.class)
@@ -43,20 +41,6 @@
assertEquals(0, metrics.numeric);
assertEquals(0, metrics.symbols);
assertEquals(0, metrics.nonLetter);
- assertTrue("default constructor does not produce default metrics", metrics.isDefault());
- }
-
- @Test
- public void testIsNotDefault() {
- final PasswordMetrics metrics = new PasswordMetrics(
- DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, 12);
- assertFalse("non-default metrics are repoted as default", metrics.isDefault());
- }
-
- @Test
- public void testComputeForEmptyPassword() {
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword("");
- assertTrue("empty password has default metrics", metrics.isDefault());
}
@Test
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 698f2ec..423d45ea 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -1323,24 +1323,8 @@
return;
}
Runtime.getRuntime().gc();
-
- final String packageName = ip.pkg.packageName;
- Log.i(TAG, "Deleting package : " + packageName);
-
- ApplicationInfo info = null;
try {
- info = getPm().getApplicationInfo(packageName, PackageManager.MATCH_UNINSTALLED_PACKAGES);
- } catch (NameNotFoundException ignored) {
- }
-
- DeleteObserver observer = new DeleteObserver(packageName);
- getPm().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);
- observer.waitForCompletion(MAX_WAIT_TIME);
-
- try {
- if (info != null) {
- assertUninstalled(info);
- }
+ cleanUpInstall(ip.pkg.packageName);
} finally {
File outFile = new File(ip.pkg.codePath);
if (outFile != null && outFile.exists()) {
@@ -1355,16 +1339,15 @@
}
Log.i(TAG, "Deleting package : " + pkgName);
try {
- ApplicationInfo info = getPm().getApplicationInfo(pkgName,
+ final ApplicationInfo info = getPm().getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES);
-
if (info != null) {
DeleteObserver observer = new DeleteObserver(pkgName);
getPm().deletePackage(pkgName, observer, PackageManager.DELETE_ALL_USERS);
observer.waitForCompletion(MAX_WAIT_TIME);
assertUninstalled(info);
}
- } catch (NameNotFoundException e) {
+ } catch (IllegalArgumentException | NameNotFoundException e) {
}
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 5debd7e..02ff209 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -399,8 +399,6 @@
Settings.Secure.ANR_SHOW_BACKGROUND,
Settings.Secure.ASSISTANT,
Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
- Settings.Secure.ASSIST_GESTURE_ENABLED_KEYGUARD,
- Settings.Secure.ASSIST_GESTURE_ENABLED_SLEEP,
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 7b7031b..29447ed 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -124,19 +124,40 @@
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
- isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_EMAIL,
+ "mailto:" + classifiedText));
}
@Test
public void testTextClassifyText_url() {
if (isTextClassifierDisabled()) return;
- String text = "Visit http://www.android.com for more information";
+ String text = "Visit www.android.com for more information";
String classifiedText = "www.android.com";
int startIndex = text.indexOf(classifiedText);
int endIndex = startIndex + classifiedText.length();
assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
- isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_URL,
+ "http://" + classifiedText));
+ }
+
+ @Test
+ public void testTextClassifyText_url_inCaps() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Visit HTTP://ANDROID.COM for more information";
+ String classifiedText = "HTTP://ANDROID.COM";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_URL,
+ "http://ANDROID.COM"));
}
@Test
@@ -149,7 +170,10 @@
int endIndex = startIndex + classifiedText.length();
LocaleList nullLocales = null;
assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
- isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+ isTextClassification(
+ classifiedText,
+ TextClassifier.TYPE_EMAIL,
+ "mailto:" + classifiedText));
}
@Test
@@ -206,18 +230,23 @@
}
private static Matcher<TextClassification> isTextClassification(
- final String text, final String type) {
+ final String text, final String type, final String intentUri) {
return new BaseMatcher<TextClassification>() {
@Override
public boolean matches(Object o) {
if (o instanceof TextClassification) {
TextClassification result = (TextClassification) o;
final boolean typeRequirementSatisfied;
+ String scheme;
switch (type) {
+ case TextClassifier.TYPE_EMAIL:
+ scheme = result.getIntent().getData().getScheme();
+ typeRequirementSatisfied = "mailto".equals(scheme);
+ break;
case TextClassifier.TYPE_URL:
- String scheme = result.getIntent().getData().getScheme();
- typeRequirementSatisfied = "http".equalsIgnoreCase(scheme)
- || "https".equalsIgnoreCase(scheme);
+ scheme = result.getIntent().getData().getScheme();
+ typeRequirementSatisfied = "http".equals(scheme)
+ || "https".equals(scheme);
break;
default:
typeRequirementSatisfied = true;
@@ -226,7 +255,8 @@
return typeRequirementSatisfied
&& text.equals(result.getText())
&& result.getEntityCount() > 0
- && type.equals(result.getEntity(0));
+ && type.equals(result.getEntity(0))
+ && intentUri.equals(result.getIntent().getDataString());
// TODO: Include other properties.
}
return false;
@@ -235,7 +265,8 @@
@Override
public void describeTo(Description description) {
description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type);
+ .appendText(", type=").appendValue(type)
+ .appendText(", intent.data=").appendValue(intentUri);
}
};
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 2c23018..55e804b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -116,6 +116,7 @@
// The other entry is filtered to the last used slot
assertThat(activity.getAdapter().getCount(), is(1));
+ assertThat(activity.getAdapter().getPlaceholderCount(), is(1));
ResolveInfo[] chosen = new ResolveInfo[1];
sOverrides.onSafelyStartCallback = targetInfo -> {
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 1dced75..e374e11 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -29,15 +29,15 @@
private static final int UID = 10500;
private static final WorkSource WS = new WorkSource(UID);
- /** Test that BatteryStatsImpl.Uid.noteBluetoothScanResultLocked. */
+ /** Test that BatteryStatsImpl.Uid.noteBluetoothScanResultsLocked. */
@SmallTest
public void testNoteBluetoothScanResultLocked() throws Exception {
MockBatteryStatsImpl bi = new MockBatteryStatsImpl(new MockClocks());
bi.updateTimeBasesLocked(true, true, 0, 0);
- bi.noteBluetoothScanResultFromSourceLocked(WS);
- bi.noteBluetoothScanResultFromSourceLocked(WS);
- assertEquals(2,
+ bi.noteBluetoothScanResultsFromSourceLocked(WS, 1);
+ bi.noteBluetoothScanResultsFromSourceLocked(WS, 100);
+ assertEquals(101,
bi.getUidStats().get(UID).getBluetoothScanResultCounter()
.getCountLocked(STATS_SINCE_CHARGED));
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
index ad8221b..620acae 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelUidCpuFreqTimeReaderTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.support.test.filters.SmallTest;
@@ -27,6 +28,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.BufferedReader;
@@ -70,18 +72,70 @@
times[i][j] = uids[i] * freqs[j] * 10;
}
}
- final String[] uidsTimesLines = getUidTimesLines(uids, times);
- final String[] lines = new String[uidsTimesLines.length + 1];
- System.arraycopy(uidsTimesLines, 0, lines, 0, uidsTimesLines.length);
- lines[uidsTimesLines.length] = null;
when(mBufferedReader.readLine())
- .thenReturn(getFreqsLine(freqs), lines);
+ .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, times));
mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
verify(mCallback).onCpuFreqs(freqs);
for (int i = 0; i < uids.length; ++i) {
verify(mCallback).onUidCpuFreqTime(uids[i], times[i]);
}
verifyNoMoreInteractions(mCallback);
+
+ // Verify that a second call will only return deltas.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] newTimes1 = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ newTimes1[i][j] = (times[i][j] + uids[i] + freqs[j]) * 10;
+ }
+ }
+ when(mBufferedReader.readLine())
+ .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes1));
+ mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
+ verify(mCallback).onCpuFreqs(freqs);
+ for (int i = 0; i < uids.length; ++i) {
+ verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes1[i], times[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+
+ // Verify that calling with a null callback doesn't result in any crashes
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] newTimes2 = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ newTimes2[i][j] = (newTimes1[i][j] + uids[i] * freqs[j]) * 10;
+ }
+ }
+ when(mBufferedReader.readLine())
+ .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes2));
+ mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, null);
+ verifyZeroInteractions(mCallback);
+
+ // Verify that the readDelta call will only return deltas when
+ // the previous call had null callback.
+ Mockito.reset(mCallback, mBufferedReader);
+ final long[][] newTimes3 = new long[uids.length][freqs.length];
+ for (int i = 0; i < uids.length; ++i) {
+ for (int j = 0; j < freqs.length; ++j) {
+ newTimes3[i][j] = (newTimes2[i][j] * (uids[i] + freqs[j])) * 10;
+ }
+ }
+ when(mBufferedReader.readLine())
+ .thenReturn(getFreqsLine(freqs), getUidTimesLines(uids, newTimes3));
+ mKernelUidCpuFreqTimeReader.readDelta(mBufferedReader, mCallback);
+ verify(mCallback).onCpuFreqs(freqs);
+ for (int i = 0; i < uids.length; ++i) {
+ verify(mCallback).onUidCpuFreqTime(uids[i], subtract(newTimes3[i], newTimes2[i]));
+ }
+ verifyNoMoreInteractions(mCallback);
+ }
+
+ private long[] subtract(long[] a1, long[] a2) {
+ long[] val = new long[a1.length];
+ for (int i = 0; i < val.length; ++i) {
+ val[i] = a1[i] - a2[i];
+ }
+ return val;
}
private String getFreqsLine(long[] freqs) {
@@ -94,7 +148,7 @@
}
private String[] getUidTimesLines(int[] uids, long[][] times) {
- final String[] lines = new String[uids.length];
+ final String[] lines = new String[uids.length + 1];
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < uids.length; ++i) {
sb.setLength(0);
@@ -104,6 +158,7 @@
}
lines[i] = sb.toString();
}
+ lines[uids.length] = null;
return lines;
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
new file mode 100644
index 0000000..4a23f40
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounterArray;
+import static com.android.internal.os.BatteryStatsImpl.TimeBase;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+
+/**
+ * Test class for {@link BatteryStatsImpl.LongSamplingCounterArray}.
+ *
+ * To run the tests, use
+ *
+ * runtest -c com.android.internal.os.LongSamplingCounterArrayTest frameworks-core
+ *
+ * or the following steps:
+ *
+ * Build: m FrameworksCoreTests
+ * Install: adb install -r \
+ * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ * Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
+ * com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSamplingCounterArrayTest {
+
+ private static final long[] COUNTS = {1111, 2222, 3333, 4444};
+ private static final long[] LOADED_COUNTS = {5555, 6666, 7777, 8888};
+ private static final long[] PLUGGED_COUNTS = {9999, 11111, 22222, 33333};
+ private static final long[] UNPLUGGED_COUNTS = {44444, 55555, 66666, 77777};
+ private static final long[] ZEROES = {0, 0, 0, 0};
+
+ @Mock private TimeBase mTimeBase;
+ private LongSamplingCounterArray mCounterArray;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mCounterArray = new LongSamplingCounterArray(mTimeBase);
+ Mockito.reset(mTimeBase);
+ }
+
+ @Test
+ public void testReadWriteParcel() {
+ final Parcel parcel = Parcel.obtain();
+ initializeCounterArrayWithDefaultValues();
+ LongSamplingCounterArray.writeToParcel(parcel, mCounterArray);
+ parcel.setDataPosition(0);
+
+ // Now clear counterArray and verify values are read from parcel correctly.
+ updateCounts(null, null, null, null);
+ mCounterArray = LongSamplingCounterArray.readFromParcel(parcel, mTimeBase);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ parcel.recycle();
+ }
+
+ @Test
+ public void testReadWriteSummaryParcel() {
+ final Parcel parcel = Parcel.obtain();
+ initializeCounterArrayWithDefaultValues();
+ LongSamplingCounterArray.writeSummaryToParcelLocked(parcel, mCounterArray);
+ parcel.setDataPosition(0);
+
+ // Now clear counterArray and verify values are read from parcel correctly.
+ updateCounts(null, null, null, null);
+ mCounterArray = LongSamplingCounterArray.readSummaryFromParcelLocked(parcel, mTimeBase);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ parcel.recycle();
+ }
+
+ @Test
+ public void testOnTimeStarted() {
+ initializeCounterArrayWithDefaultValues();
+ mCounterArray.onTimeStarted(0, 0, 0);
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testOnTimeStopped() {
+ initializeCounterArrayWithDefaultValues();
+ mCounterArray.onTimeStopped(0, 0, 0);
+ assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testGetCountsLocked() {
+ initializeCounterArrayWithDefaultValues();
+
+ when(mTimeBase.isRunning()).thenReturn(false);
+ long[] actualVal = mCounterArray.getCountsLocked(STATS_SINCE_CHARGED);
+ long[] expectedVal = PLUGGED_COUNTS;
+ assertArrayEquals(expectedVal, actualVal, "Unexpected values");
+
+ when(mTimeBase.isRunning()).thenReturn(true);
+ actualVal = mCounterArray.getCountsLocked(STATS_SINCE_CHARGED);
+ expectedVal = COUNTS;
+ assertArrayEquals(expectedVal, actualVal, "Unexpected values");
+ }
+
+ @Test
+ public void testAddCountLocked() {
+ final long[] deltas = {123, 234, 345, 456};
+ mCounterArray.addCountLocked(deltas);
+ assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(null, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+
+ initializeCounterArrayWithDefaultValues();
+ final long[] newCounts = new long[deltas.length];
+ for (int i = 0; i < deltas.length; ++i) {
+ newCounts[i] = COUNTS[i] + deltas[i];
+ }
+ mCounterArray.addCountLocked(deltas);
+ assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(PLUGGED_COUNTS, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
+ "Unexpected unpluggedCounts");
+ }
+
+ @Test
+ public void testReset() {
+ initializeCounterArrayWithDefaultValues();
+ // Test with detachIfReset=false
+ mCounterArray.reset(false /* detachIfReset */);
+ assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ verifyZeroInteractions(mTimeBase);
+
+ initializeCounterArrayWithDefaultValues();
+ // Test with detachIfReset=true
+ mCounterArray.reset(true /* detachIfReset */);
+ assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
+ assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mPluggedCounts, "Unexpected pluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ verify(mTimeBase).remove(mCounterArray);
+ verifyNoMoreInteractions(mTimeBase);
+ }
+
+ @Test
+ public void testDetach() {
+ mCounterArray.detach();
+ verify(mTimeBase).remove(mCounterArray);
+ verifyNoMoreInteractions(mTimeBase);
+ }
+
+ private void initializeCounterArrayWithDefaultValues() {
+ updateCounts(COUNTS, LOADED_COUNTS, PLUGGED_COUNTS, UNPLUGGED_COUNTS);
+ }
+
+ private void assertArrayEquals(long[] expected, long[] actual, String msg) {
+ assertTrue(msg + ", expected: " + Arrays.toString(expected)
+ + ", actual: " + Arrays.toString(actual), Arrays.equals(expected, actual));
+ }
+
+ private void updateCounts(long[] counts, long[] loadedCounts,
+ long[] pluggedCounts, long[] unpluggedCounts) {
+ mCounterArray.mCounts = counts;
+ mCounterArray.mLoadedCounts = loadedCounts;
+ mCounterArray.mPluggedCounts = pluggedCounts;
+ mCounterArray.mUnpluggedCounts = unpluggedCounts;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
index 5dc07c2..906d7e9 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ImageFloatingTextViewTest.java
@@ -16,7 +16,7 @@
package com.android.internal.widget;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@@ -111,6 +111,9 @@
mTextView.measure(widthMeasureSpec, heightMeasureSpec);
mView.measure(widthMeasureSpec, heightMeasureSpec);
- assertEquals(mTextView.getMeasuredHeight(), mView.getMeasuredHeight());
+ // We're at most allowed to be the same height as the regular textview and maybe a bit
+ // smaller since our layout snaps to full textlines.
+ assertTrue("The measured view should never be taller then the normal textview!",
+ mView.getMeasuredHeight() <= mTextView.getMeasuredHeight());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index 75b2c1d..20fd4d3 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.os.Debug;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.core.deps.guava.base.Function;
import android.support.test.filters.SmallTest;
@@ -46,8 +45,7 @@
@Before
public void setup() {
mContext = InstrumentationRegistry.getTargetContext();
- // maxHeight: 300px
- // spacing: 50px
+ // spacing: 5px
mView = (MessagingLinearLayout) LayoutInflater.from(mContext).inflate(
R.layout.messaging_linear_layout_test, null);
}
@@ -81,8 +79,8 @@
assertEquals(3, child1.getNumIndentLines());
assertEquals(0, child2.getNumIndentLines());
- assertFalse(child1.isHidden());
- assertFalse(child2.isHidden());
+ assertFalse("child1 should not be hidden", child1.isHidden());
+ assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(205, mView.getMeasuredHeight());
}
@@ -100,8 +98,8 @@
assertEquals(2, child1.getNumIndentLines());
assertEquals(1, child2.getNumIndentLines());
- assertFalse(child1.isHidden());
- assertFalse(child2.isHidden());
+ assertFalse("child1 should not be hidden", child1.isHidden());
+ assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(105, mView.getMeasuredHeight());
}
@@ -118,14 +116,14 @@
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
assertEquals(3, child2.getNumIndentLines());
- assertTrue(child1.isHidden());
- assertFalse(child2.isHidden());
- assertEquals(300, mView.getMeasuredHeight());
+ assertTrue("child1 should be hidden", child1.isHidden());
+ assertFalse("child2 should not be hidden", child2.isHidden());
+ assertEquals(350, mView.getMeasuredHeight());
}
@Test
- public void testLargeSmall_largeWrapsWith3indentbutnot3_andHitsMax() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 5 : 4);
+ public void testLargeSmall_largeWrapsWith3indentbutNotFullHeight_andHitsMax() {
+ FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 7 : 6);
FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
mView.setNumIndentLines(2);
@@ -135,10 +133,11 @@
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertTrue(child1.isHidden());
- assertFalse(child2.isHidden());
- assertEquals(50, mView.getMeasuredHeight());
- assertEquals(2, child2.getNumIndentLines());
+ assertFalse("child1 should not be hidden", child1.isHidden());
+ assertFalse("child2 should not be hidden", child2.isHidden());
+ assertEquals(355, mView.getMeasuredHeight());
+ assertEquals(3, child1.getNumIndentLines());
+ assertEquals(0, child2.getNumIndentLines());
}
@Test
@@ -153,8 +152,8 @@
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertFalse(child1.isHidden());
- assertFalse(child2.isHidden());
+ assertFalse("child1 should not be hidden", child1.isHidden());
+ assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(255, mView.getMeasuredHeight());
assertEquals(3, child1.getNumIndentLines());
assertEquals(0, child2.getNumIndentLines());
@@ -184,10 +183,23 @@
}
@Override
+ public int getLayoutHeight() {
+ return Math.max(LINE_HEIGHT, getMeasuredHeight());
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
getDefaultSize(500, widthMeasureSpec),
- resolveSize(getDesiredHeight(), heightMeasureSpec));
+ clampToMultiplesOfLineHeight(resolveSize(getDesiredHeight(),
+ heightMeasureSpec)));
+ }
+
+ private int clampToMultiplesOfLineHeight(int size) {
+ if (size <= LINE_HEIGHT) {
+ return size;
+ }
+ return (size / LINE_HEIGHT) * LINE_HEIGHT;
}
@Override
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
index a4b0916..f2e02e3 100644
--- a/core/tests/utiltests/Android.mk
+++ b/core/tests/utiltests/Android.mk
@@ -17,7 +17,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
frameworks-base-testutils \
- mockito-target-minus-junit4
+ mockito-target-minus-junit4 \
+ legacy-android-tests
LOCAL_JAVA_LIBRARIES := android.test.runner
@@ -28,3 +29,4 @@
LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
+
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0835cad..8efda2a 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -20,9 +20,11 @@
# =============================
# This contains the junit.framework and android.test classes that were in
# Android API level 25 excluding those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
LOCAL_MODULE := legacy-test
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core-oj core-libart framework
@@ -30,20 +32,35 @@
include $(BUILD_JAVA_LIBRARY)
# Build the legacy-android-test library
-# =============================
+# =====================================
# This contains the android.test classes that were in Android API level 25,
# including those from android.test.runner.
+# Also contains the com.android.internal.util.Predicate[s] classes.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(call all-java-files-under, src/android) \
- $(call all-java-files-under, ../test-runner/src/android)
+ $(call all-java-files-under, ../test-runner/src/android) \
+ $(call all-java-files-under, src/com)
LOCAL_MODULE := legacy-android-test
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
include $(BUILD_STATIC_JAVA_LIBRARY)
+# Build the legacy-android-tests library
+# ======================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, tests)
+LOCAL_MODULE := legacy-android-tests
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
ifeq ($(HOST_OS),linux)
# Build the legacy-performance-test-hostdex library
# =================================================
diff --git a/core/java/com/android/internal/util/Predicate.java b/legacy-test/src/com/android/internal/util/Predicate.java
similarity index 100%
rename from core/java/com/android/internal/util/Predicate.java
rename to legacy-test/src/com/android/internal/util/Predicate.java
diff --git a/core/java/com/android/internal/util/Predicates.java b/legacy-test/src/com/android/internal/util/Predicates.java
similarity index 99%
rename from core/java/com/android/internal/util/Predicates.java
rename to legacy-test/src/com/android/internal/util/Predicates.java
index c006564..fe1ff15 100644
--- a/core/java/com/android/internal/util/Predicates.java
+++ b/legacy-test/src/com/android/internal/util/Predicates.java
@@ -21,6 +21,8 @@
/**
* Predicates contains static methods for creating the standard set of
* {@code Predicate} objects.
+ *
+ * @hide
*/
public class Predicates {
diff --git a/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java b/legacy-test/tests/com/android/internal/util/PredicatesTest.java
similarity index 100%
rename from core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
rename to legacy-test/tests/com/android/internal/util/PredicatesTest.java
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index acf8883..07ff27d 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -62,7 +62,7 @@
"libskia",
"libui",
"libgui",
- "libprotobuf-cpp-full",
+ "libprotobuf-cpp-lite",
"libharfbuzz_ng",
"libft2",
"libminikin",
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 959b28b..d8207b1 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,7 +16,6 @@
#include "Bitmap.h"
#include "Caches.h"
-#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
#include "renderthread/RenderProxy.h"
@@ -35,15 +34,11 @@
#include <private/gui/ComposerService.h>
#include <binder/IServiceManager.h>
#include <ui/PixelFormat.h>
-#include <GrTexture.h>
#include <SkCanvas.h>
-#include <SkImagePriv.h>
namespace android {
-Mutex Bitmap::gLock;
-
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
int32_t rowBytes32 = SkToS32(rowBytes);
int64_t bigSize = (int64_t) height * rowBytes32;
@@ -316,7 +311,8 @@
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType,
+ SkColorSpace::MakeSRGB());
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
@@ -396,7 +392,6 @@
, mPixelStorageType(PixelStorageType::Hardware) {
mPixelStorage.hardware.buffer = buffer;
buffer->incStrong(buffer);
- setImmutable(); // HW bitmaps are always immutable
}
Bitmap::~Bitmap() {
@@ -479,13 +474,7 @@
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
if (isHardware()) {
- if (uirenderer::Properties::isSkiaEnabled()) {
- // TODO: add color correctness for Skia pipeline - pass null color space for now
- outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
- info().colorType(), info().alphaType(), nullptr));
- } else {
- outBitmap->allocPixels(info());
- }
+ outBitmap->allocPixels(info());
uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
return;
}
@@ -511,28 +500,4 @@
return nullptr;
}
-sk_sp<SkImage> Bitmap::makeImage(const uirenderer::renderthread::RenderThread* renderThread) {
- AutoMutex _lock(gLock); //TODO: implement lock free solution
- auto image = mImage;
- //TODO: use new API SkImage::isValid() instead of SkImage::getTexture()->getContext()
- if (!image.get() || (image->getTexture() && nullptr == image->getTexture()->getContext())) {
- if (isHardware() && uirenderer::RenderPipelineType::SkiaGL
- == uirenderer::Properties::getRenderPipelineType()) {
- //TODO: add Vulkan support
- if (renderThread) {
- image = uirenderer::skiapipeline::SkiaOpenGLPipeline::makeTextureImage(
- *renderThread, this);
- } else {
- image = uirenderer::renderthread::RenderProxy::makeTextureImage(this);
- }
- } else {
- SkBitmap skiaBitmap;
- getSkBitmapForShaders(&skiaBitmap);
- image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
- }
- mImage = image;
- }
- return image;
-}
-
} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index e650c20..9a76715 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -22,8 +22,6 @@
#include <SkPixelRef.h>
#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
-#include <utils/Mutex.h>
-#include <SkImage.h>
namespace android {
@@ -107,13 +105,6 @@
}
GraphicBuffer* graphicBuffer();
-
- // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
- // If invoked on the render thread, then RenderThread* argument is required.
- // If not invoked on the render thread, then RenderThread* must be nullptr.
- // makeImage is wrapping a gralloc buffer with an EGLImage and is passing a texture to Skia.
- // This is a temporary implementation until Skia can wrap the gralloc buffer in a SkImage.
- sk_sp<SkImage> makeImage(const uirenderer::renderthread::RenderThread*);
private:
Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
virtual ~Bitmap();
@@ -144,9 +135,6 @@
GraphicBuffer* buffer;
} hardware;
} mPixelStorage;
-
- sk_sp<SkImage> mImage;
- static Mutex gLock;
};
} //namespace android
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 68a0869..e0f5e54 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -137,7 +137,6 @@
float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
- const float casterZValue = casterProperties.getZ();
const RevealClip& revealClip = casterProperties.getRevealClip();
const SkPath* revealClipPath = revealClip.getPath();
@@ -178,6 +177,7 @@
// intersect the shadow-casting path with the reveal, if present
if (revealClipPath) {
Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
+ tmpPath.setIsVolatile(true);
casterPath = &tmpPath;
}
@@ -186,36 +186,23 @@
SkPath clipBoundsPath;
clipBoundsPath.addRect(casterClipRect);
Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
+ tmpPath.setIsVolatile(true);
casterPath = &tmpPath;
}
const Vector3 lightPos = SkiaPipeline::getLightCenter();
SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
- if (shadowMatrix.hasPerspective() || revealClipPath || clippedToBounds) {
- std::function<SkScalar(SkScalar, SkScalar)> casterHeightFunc;
- if (shadowMatrix.hasPerspective()) {
- // get the matrix with the full 3D transform
- mat4 zMatrix;
- caster->getRenderNode()->applyViewPropertyTransforms(zMatrix, true);
- SkScalar A = zMatrix[2];
- SkScalar B = zMatrix[6];
- SkScalar C = zMatrix[mat4::kTranslateZ];
- casterHeightFunc = [A, B, C](SkScalar x, SkScalar y) {
- return A*x + B*y + C; // casterZValue already baked into C
- };
- } else {
- casterHeightFunc = [casterZValue] (SkScalar, SkScalar) {
- return casterZValue;
- };
- }
-
- SkShadowUtils::DrawUncachedShadow(canvas, *casterPath, casterHeightFunc, skiaLightPos,
- SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
- casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
+ SkPoint3 zParams;
+ if (shadowMatrix.hasPerspective()) {
+ // get the matrix with the full 3D transform
+ mat4 zMatrix;
+ caster->getRenderNode()->applyViewPropertyTransforms(zMatrix, true);
+ zParams = SkPoint3::Make(zMatrix[2], zMatrix[6], zMatrix[mat4::kTranslateZ]);
} else {
- SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos,
- SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
- casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
+ zParams = SkPoint3::Make(0, 0, casterProperties.getZ());
}
+ SkShadowUtils::DrawShadow(canvas, *casterPath, zParams, skiaLightPos,
+ SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
+ casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
}
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 4885873..ae13131 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -28,8 +28,6 @@
#include <cutils/properties.h>
#include <strings.h>
-#include <SkImagePriv.h>
-#include <gl/GrGLTypes.h>
using namespace android::uirenderer::renderthread;
@@ -199,87 +197,6 @@
}
}
-static void deleteImageTexture(void* context) {
- EGLImageKHR EGLimage = reinterpret_cast<EGLImageKHR>(context);
- if (EGLimage != EGL_NO_IMAGE_KHR) {
- EGLDisplay display = eglGetCurrentDisplay();
- if (EGL_NO_DISPLAY == display) {
- display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- }
- eglDestroyImageKHR(display, EGLimage);
- }
-}
-
-sk_sp<SkImage> SkiaOpenGLPipeline::makeTextureImage(
- const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap) {
- renderThread.eglManager().initialize();
-
- GraphicBuffer* buffer = bitmap->graphicBuffer();
- EGLDisplay display = eglGetCurrentDisplay();
- if (EGL_NO_DISPLAY == display) {
- display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- }
- LOG_ALWAYS_FATAL_IF(!bitmap->isHardware(),
- "Texture image requires a HW bitmap.");
- // We use an EGLImage to access the content of the GraphicBuffer
- // The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- EGLImageKHR EGLimage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- clientBuffer, imageAttrs);
- if (EGLimage == EGL_NO_IMAGE_KHR) {
- ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
- return nullptr;
- }
-
- GLuint textureId = 0;
- glGenTextures(1, &textureId);
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EGLimage);
-
- GLenum status = GL_NO_ERROR;
- while ((status = glGetError()) != GL_NO_ERROR) {
- ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
- eglDestroyImageKHR(display, EGLimage);
- return nullptr;
- }
-
- sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
- grContext->resetContext();
-
- GrGLTextureInfo textureInfo;
- textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
- textureInfo.fID = textureId;
-
- GrBackendTextureDesc textureDescription;
- textureDescription.fWidth = bitmap->info().width();
- textureDescription.fHeight = bitmap->info().height();
- textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
- textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&textureInfo);
- PixelFormat format = buffer->getPixelFormat();
- switch (format) {
- case PIXEL_FORMAT_RGBA_8888:
- textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
- break;
- case PIXEL_FORMAT_RGBA_FP16:
- textureDescription.fConfig = kRGBA_half_GrPixelConfig;
- break;
- default:
- eglDestroyImageKHR(display, EGLimage);
- return nullptr;
- }
-
- // TODO: add color correctness - pass null color space for now
- sk_sp<SkImage> image = SkImage::MakeFromTexture(grContext.get(), textureDescription,
- bitmap->info().alphaType(), nullptr, deleteImageTexture, EGLimage);
- if (!image.get()) {
- eglDestroyImageKHR(display, EGLimage);
- return nullptr;
- }
- return image;
-}
-
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index f3ce189..36685dd 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -46,8 +46,6 @@
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
- static sk_sp<SkImage> makeTextureImage(
- const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap);
private:
renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 1863bdc..04aeb7c 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -61,7 +61,6 @@
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
CopyResult copyResult = CopyResult::UnknownError;
- // TODO: add color correctness - pass null color space for now
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
if (image) {
// convert to Skia data structures
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 75fb070..75f1adc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -159,11 +159,11 @@
GrContext* context = thread.getGrContext();
if (context) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
- auto image = bitmap->makeImage(&thread);
- if (image.get() && !bitmap->isHardware()) {
- SkImage_pinAsTexture(image.get(), context);
- SkImage_unpinAsTexture(image.get(), context);
- }
+ SkBitmap skiaBitmap;
+ bitmap->getSkBitmap(&skiaBitmap);
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+ SkImage_pinAsTexture(image.get(), context);
+ SkImage_unpinAsTexture(image.get(), context);
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index d78bca9..cf8b4dd 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -156,43 +156,57 @@
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- sk_sp<SkImage> image = bitmap.makeImage(nullptr);
- if (!bitmap.isImmutable()) {
- mDisplayList->mMutableImages.push_back(image.get());
- }
+ SkBitmap skBitmap;
+ bitmap.getSkBitmap(&skBitmap);
+
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
SkPaint tmpPaint;
mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint));
+ // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
+ // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
+ // when this function ends.
+ if (!skBitmap.isImmutable() && image.get() && !image->unique()) {
+ mDisplayList->mMutableImages.push_back(image.get());
+ }
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
const SkPaint* paint) {
+ SkBitmap bitmap;
+ hwuiBitmap.getSkBitmap(&bitmap);
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
- sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
- if (!hwuiBitmap.isImmutable()) {
- mDisplayList->mMutableImages.push_back(image.get());
- }
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
SkPaint tmpPaint;
mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint));
+ if (!bitmap.isImmutable() && image.get() && !image->unique()) {
+ mDisplayList->mMutableImages.push_back(image.get());
+ }
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
float dstBottom, const SkPaint* paint) {
+ SkBitmap bitmap;
+ hwuiBitmap.getSkBitmap(&bitmap);
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
- if (!hwuiBitmap.isImmutable()) {
- mDisplayList->mMutableImages.push_back(image.get());
- }
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
SkPaint tmpPaint;
mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint));
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
+ && !dstRect.isEmpty()) {
+ mDisplayList->mMutableImages.push_back(image.get());
+ }
}
void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
+ SkBitmap bitmap;
+ hwuiBitmap.getSkBitmap(&bitmap);
+
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -209,13 +223,13 @@
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
- if (!hwuiBitmap.isImmutable()) {
- mDisplayList->mMutableImages.push_back(image.get());
- }
+ sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
SkPaint tmpPaint;
mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint));
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
+ mDisplayList->mMutableImages.push_back(image.get());
+ }
}
}; // namespace skiapipeline
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 5c2ec0e..a1f1717 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -693,18 +693,6 @@
}
}
-CREATE_BRIDGE2(makeTextureImage, RenderThread* thread, Bitmap* bitmap) {
- return args->thread->makeTextureImage(args->bitmap).release();
-}
-
-sk_sp<SkImage> RenderProxy::makeTextureImage(Bitmap* bitmap) {
- SETUP_TASK(makeTextureImage);
- args->bitmap = bitmap;
- args->thread = &RenderThread::getInstance();
- sk_sp<SkImage> hardwareImage(reinterpret_cast<SkImage*>(staticPostAndWait(task)));
- return hardwareImage;
-}
-
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 97ad796..a60ed55 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -135,8 +135,6 @@
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
-
- static sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index d62b556..1450ec9 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,7 +17,6 @@
#include "RenderThread.h"
#include "../renderstate/RenderState.h"
-#include "../pipeline/skia/SkiaOpenGLPipeline.h"
#include "../pipeline/skia/SkiaOpenGLReadback.h"
#include "CanvasContext.h"
#include "EglManager.h"
@@ -434,24 +433,6 @@
return next;
}
-sk_sp<SkImage> RenderThread::makeTextureImage(Bitmap* bitmap) {
- auto renderType = Properties::getRenderPipelineType();
- sk_sp<SkImage> hardwareImage;
- switch (renderType) {
- case RenderPipelineType::SkiaGL:
- hardwareImage = skiapipeline::SkiaOpenGLPipeline::makeTextureImage(*this, bitmap);
- break;
- case RenderPipelineType::SkiaVulkan:
- //TODO: add Vulkan support
- break;
- default:
- LOG_ALWAYS_FATAL("makeTextureImage: canvas context type %d not supported",
- (int32_t) renderType);
- break;
- }
- return hardwareImage;
-}
-
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 34542c6..9bc5985 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -33,7 +33,6 @@
namespace android {
-class Bitmap;
class DisplayEventReceiver;
namespace uirenderer {
@@ -105,8 +104,6 @@
VulkanManager& vulkanManager() { return *mVkManager; }
- sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
-
protected:
virtual bool threadLoop() override;
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index ab6420e..87eaa6a 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -19,7 +19,7 @@
#include "JankTracker.h"
#include <frameworks/base/core/proto/android/service/graphicsstats.pb.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <log/log.h>
#include <inttypes.h>
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/mman.h>
namespace android {
namespace uirenderer {
@@ -46,10 +47,74 @@
const ProfileData* data);
static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
+class FileDescriptor {
+public:
+ FileDescriptor(int fd) : mFd(fd) {}
+ ~FileDescriptor() {
+ if (mFd != -1) {
+ close(mFd);
+ mFd = -1;
+ }
+ }
+ bool valid() { return mFd != -1; }
+ operator int() { return mFd; }
+private:
+ int mFd;
+};
+
+class FileOutputStreamLite : public io::ZeroCopyOutputStream {
+public:
+ FileOutputStreamLite(int fd) : mCopyAdapter(fd), mImpl(&mCopyAdapter) {}
+ virtual ~FileOutputStreamLite() {}
+
+ int GetErrno() { return mCopyAdapter.mErrno; }
+
+ virtual bool Next(void** data, int* size) override {
+ return mImpl.Next(data, size);
+ }
+
+ virtual void BackUp(int count) override {
+ mImpl.BackUp(count);
+ }
+
+ virtual int64 ByteCount() const override {
+ return mImpl.ByteCount();
+ }
+
+ bool Flush() {
+ return mImpl.Flush();
+ }
+
+private:
+ struct FDAdapter : public io::CopyingOutputStream {
+ int mFd;
+ int mErrno = 0;
+
+ FDAdapter(int fd) : mFd(fd) {}
+ virtual ~FDAdapter() {}
+
+ virtual bool Write(const void* buffer, int size) override {
+ int ret;
+ while (size) {
+ ret = TEMP_FAILURE_RETRY( write(mFd, buffer, size) );
+ if (ret <= 0) {
+ mErrno = errno;
+ return false;
+ }
+ size -= ret;
+ }
+ return true;
+ }
+ };
+
+ FileOutputStreamLite::FDAdapter mCopyAdapter;
+ io::CopyingOutputStreamAdaptor mImpl;
+};
+
bool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) {
- int fd = open(path.c_str(), O_RDONLY);
- if (fd == -1) {
+ FileDescriptor fd{open(path.c_str(), O_RDONLY)};
+ if (!fd.valid()) {
int err = errno;
// The file not existing is normal for addToDump(), so only log if
// we get an unexpected error
@@ -58,26 +123,41 @@
}
return false;
}
- uint32_t file_version;
- ssize_t bytesRead = read(fd, &file_version, sHeaderSize);
- if (bytesRead != sHeaderSize || file_version != sCurrentFileVersion) {
- ALOGW("Failed to read '%s', bytesRead=%zd file_version=%d", path.c_str(), bytesRead,
- file_version);
- close(fd);
+ struct stat sb;
+ if (fstat(fd, &sb) || sb.st_size < sHeaderSize) {
+ int err = errno;
+ // The file not existing is normal for addToDump(), so only log if
+ // we get an unexpected error
+ if (err != ENOENT) {
+ ALOGW("Failed to fstat '%s', errno=%d (%s) (st_size %d)", path.c_str(), err,
+ strerror(err), (int) sb.st_size);
+ }
+ return false;
+ }
+ void* addr = mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (!addr) {
+ int err = errno;
+ // The file not existing is normal for addToDump(), so only log if
+ // we get an unexpected error
+ if (err != ENOENT) {
+ ALOGW("Failed to mmap '%s', errno=%d (%s)", path.c_str(), err, strerror(err));
+ }
+ return false;
+ }
+ uint32_t file_version = *reinterpret_cast<uint32_t*>(addr);
+ if (file_version != sCurrentFileVersion) {
+ ALOGW("file_version mismatch! expected %d got %d", sCurrentFileVersion, file_version);
return false;
}
- io::FileInputStream input(fd);
+ void* data = reinterpret_cast<uint8_t*>(addr) + sHeaderSize;
+ int dataSize = sb.st_size - sHeaderSize;
+ io::ArrayInputStream input{data, dataSize};
bool success = output->ParseFromZeroCopyStream(&input);
- if (input.GetErrno() != 0) {
- ALOGW("Error reading from fd=%d, path='%s' err=%d (%s)",
- fd, path.c_str(), input.GetErrno(), strerror(input.GetErrno()));
- success = false;
- } else if (!success) {
+ if (!success) {
ALOGW("Parse failed on '%s' error='%s'",
path.c_str(), output->InitializationErrorString().c_str());
}
- close(fd);
return success;
}
@@ -212,7 +292,7 @@
return;
}
{
- io::FileOutputStream output(outFd);
+ FileOutputStreamLite output(outFd);
bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
if (output.GetErrno() != 0) {
ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)",
@@ -277,7 +357,7 @@
void GraphicsStatsService::finishDump(Dump* dump) {
if (dump->type() == DumpType::Protobuf) {
- io::FileOutputStream stream(dump->fd());
+ FileOutputStreamLite stream(dump->fd());
dump->proto().SerializeToZeroCopyStream(&stream);
}
delete dump;
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
index 773a7ea..ee20236 100644
--- a/libs/hwui/tests/unit/FontRendererTests.cpp
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -28,7 +28,7 @@
return true;
}
-RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, DISABLED_renderDropShadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) {
SkPaint paint;
paint.setTextSize(10);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 5383e57..8312bda 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -26,7 +26,7 @@
using namespace android;
using namespace android::uirenderer;
-RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, DISABLED_addRemove) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
SkPaint paint;
paint.setTextSize(20);
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index de85c16..d24a477 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -436,8 +436,8 @@
* E1BC code lock : [ 0 4ms ] : STATE_GAL_E1BC_CODE_LOCK is set
* E1C 2nd code lock : [ 0 100ms ] : STATE_GAL_E1C_2ND_CODE_LOCK is set
* E1B page : [ 0 2s ] : STATE_GAL_E1B_PAGE_SYNC is set
- * Time of week decoded : [ 0 1week ] : STATE_GAL_TOW_DECODED is set
- * Time of week known : [ 0 1week ] : STATE_GAL_TOW_KNOWN set</pre>
+ * Time of week decoded : [ 0 1week ] : STATE_TOW_DECODED is set
+ * Time of week known : [ 0 1week ] : STATE_TOW_KNOWN set</pre>
*
* Note: TOW Known refers to the case where TOW is possibly not decoded over the air but has
* been determined from other sources. If TOW decoded is set then TOW Known must also be set.
diff --git a/media/java/Android.bp b/media/java/Android.bp
new file mode 100644
index 0000000..0810699
--- /dev/null
+++ b/media/java/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+ name: "IMidiDeviceServer.aidl",
+ srcs: ["android/media/midi/IMidiDeviceServer.aidl"],
+}
diff --git a/media/java/android/media/AudioFocusRequest.java b/media/java/android/media/AudioFocusRequest.java
index b1dc3ad..9841815 100644
--- a/media/java/android/media/AudioFocusRequest.java
+++ b/media/java/android/media/AudioFocusRequest.java
@@ -40,7 +40,7 @@
* <p>When an application requests audio focus, it expresses its intention to “own” audio focus to
* play audio. Let’s review the different types of focus requests, the return value after a request,
* and the responses to a loss.
- * <br><b>Note:<b> applications should not play anything until granted focus.
+ * <p class="note">Note: applications should not play anything until granted focus.</p>
*
* <h3>The different types of focus requests</h3>
* <p>There are four focus request types. A successful focus request with each will yield different
@@ -77,9 +77,10 @@
*
* <p>An {@code AudioFocusRequest} instance always contains one of the four types of requests
* explained above. It is passed when building an {@code AudioFocusRequest} instance with its
- * builder in the {@link Builder} constructor {@link Builder#Builder(int)}, or with
- * {@link Builder#setFocusGain(int)} after copying an existing instance with
- * {@link Builder#Builder(AudioFocusRequest)}.
+ * builder in the {@link Builder} constructor
+ * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(int)}, or
+ * with {@link AudioFocusRequest.Builder#setFocusGain(int)} after copying an existing instance with
+ * {@link AudioFocusRequest.Builder#AudioFocusRequest.Builder(AudioFocusRequest)}.
*
* <h3>Qualifying your focus request</h3>
* <h4>Use case requiring a focus request</h4>
@@ -105,10 +106,11 @@
* <h4>Pausing vs ducking</h4>
* <p>When an application requested audio focus with
* {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK}, the system will duck the current focus
- * owner. Note that this behavior is <b>new for Android O<b>, whereas applications targeting SDK
- * up to API 25, applications had to implement the ducking themselves when they received a focus
+ * owner.
+ * <p class="note">Note: this behavior is <b>new for Android O</b>, whereas applications targeting
+ * SDK level up to API 25 had to implement the ducking themselves when they received a focus
* loss of {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
- * <br>But ducking is not always the behavior expected by the user. A typical example is when the
+ * <p>But ducking is not always the behavior expected by the user. A typical example is when the
* device plays driving directions while the user is listening to an audio book or podcast, and
* expects the audio playback to pause, instead of duck, as it is hard to understand a navigation
* prompt and spoken content at the same time. Therefore the system will not automatically duck
@@ -126,7 +128,92 @@
* speech, you can also declare so with {@link Builder#setWillPauseWhenDucked(boolean)}, which will
* cause the system to call your focus listener instead of automatically ducking.
*
+ * <h4>Example</h4>
+ * <p>The example below covers the following steps to be found in any application that would play
+ * audio, and use audio focus. Here we play an audio book, and our application is intended to pause
+ * rather than duck when it loses focus. These steps consist in:
+ * <ul>
+ * <li>Creating {@code AudioAttributes} to be used for the playback and the focus request.</li>
+ * <li>Configuring and creating the {@code AudioFocusRequest} instance that defines the intended
+ * focus behaviors.</li>
+ * <li>Requesting audio focus and checking the return code to see if playback can happen right
+ * away, or is delayed.</li>
+ * <li>Implementing a focus change listener to respond to focus gains and losses.</li>
+ * </ul>
+ * <p>
+ * <pre class="prettyprint">
+ * // initialization of the audio attributes and focus request
+ * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
+ * mPlaybackAttributes = new AudioAttributes.Builder()
+ * .setUsage(AudioAttributes.USAGE_MEDIA)
+ * .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+ * .build();
+ * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
+ * .setAudioAttributes(mPlaybackAttributes)
+ * .setAcceptsDelayedFocusGain(true)
+ * .setWillPauseWhenDucked(true)
+ * .setOnAudioFocusChangeListener(this, mMyHandler)
+ * .build();
+ * mMediaPlayer = new MediaPlayer();
+ * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
+ * final Object mFocusLock = new Object();
+ *
+ * boolean mPlaybackDelayed = false;
+ *
+ * // requesting audio focus
+ * int res = mAudioManager.requestAudioFocus(mFocusRequest);
+ * synchronized (mFocusLock) {
+ * if (res == AUDIOFOCUS_REQUEST_FAILED) {
+ * mPlaybackDelayed = false;
+ * } else if (res == AUDIOFOCUS_REQUEST_GRANTED) {
+ * mPlaybackDelayed = false;
+ * playbackNow();
+ * } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
+ * mPlaybackDelayed = true;
+ * }
+ * }
+ *
+ * // implementation of the OnAudioFocusChangeListener
+ * @Override
+ * public void onAudioFocusChange(int focusChange) {
+ * switch (focusChange) {
+ * case AudioManager.AUDIOFOCUS_GAIN:
+ * if (mPlaybackDelayed || mResumeOnFocusGain) {
+ * synchronized (mFocusLock) {
+ * mPlaybackDelayed = false;
+ * mResumeOnFocusGain = false;
+ * }
+ * playbackNow();
+ * }
+ * break;
+ * case AudioManager.AUDIOFOCUS_LOSS:
+ * synchronized (mFocusLock) {
+ * // this is not a transient loss, we shouldn't automatically resume for now
+ * mResumeOnFocusGain = false;
+ * mPlaybackDelayed = false;
+ * }
+ * pausePlayback();
+ * break;
+ * case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ * case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ * // we handle all transient losses the same way because we never duck audio books
+ * synchronized (mFocusLock) {
+ * // we should only resume if playback was interrupted
+ * mResumeOnFocusGain = mMediaPlayer.isPlaying();
+ * mPlaybackDelayed = false;
+ * }
+ * pausePlayback();
+ * break;
+ * }
+ * }
+ *
+ * // Important:
+ * // Also set "mResumeOnFocusGain" to false when the user pauses or stops playback: this way your
+ * // application doesn't automatically restart when it gains focus, even though the user had
+ * // stopped it.
+ * </pre>
*/
+
public final class AudioFocusRequest {
// default attributes for the request when not specified
@@ -244,36 +331,15 @@
/**
* Builder class for {@link AudioFocusRequest} objects.
- * <p> Here is an example where {@code Builder} is used to define the
- * {@link AudioFocusRequest} for requesting audio focus:
- *
- * <pre class="prettyprint">
- * mAudioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE);
- * mPlaybackAttributes = new AudioAttributes.Builder()
- * .setUsage(AudioAttributes.USAGE_GAME)
- * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
- * .build();
- * mFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
- * .setAudioAttributes(mPlaybackAttributes)
- * .setAcceptsDelayedFocusGain(true)
- * .setOnAudioFocusChangeListener(mMyFocusListener, mMyHandler)
- * .build();
- * mMediaPlayer = new MediaPlayer();
- * ...
- * mMediaPlayer.setAudioAttributes(mPlaybackAttributes);
- * ...
- * boolean mPlaybackAuthorized = true;;
- * int res = mAudioManager.requestAudioFocus(mFocusRequest);
- * if (res == AUDIOFOCUS_REQUEST_FAILED) {
- * mPlaybackAuthorized = false;
- * cancelPlayback();
- * } else if (res == AUDIOFOCUS_REQUEST_DELAYED) {
- * playbackDelayed();
- * } else { // res == AUDIOFOCUS_REQUEST_GRANTED
- * playbackNow();
- * }
- * </pre>
- *
+ * <p>See {@link AudioFocusRequest} for an example of building an instance with this builder.
+ * <br>The default values for the instance to be built are:
+ * <table>
+ * <tr><td>focus listener and handler</td><td>none</td></tr>
+ * <tr><td>{@code AudioAttributes}</td><td>attributes with usage set to
+ * {@link AudioAttributes#USAGE_MEDIA}</td></tr>
+ * <tr><td>pauses on duck</td><td>false</td></tr>
+ * <tr><td>supports delayed focus grant</td><td>false</td></tr>
+ * </table>
*/
public static final class Builder {
private OnAudioFocusChangeListener mFocusListener;
diff --git a/media/java/android/media/VolumeAutomation.java b/media/java/android/media/VolumeAutomation.java
index dff8801..ff2e645 100644
--- a/media/java/android/media/VolumeAutomation.java
+++ b/media/java/android/media/VolumeAutomation.java
@@ -31,9 +31,9 @@
* @param configuration the {@link VolumeShaper.Configuration configuration}
* that specifies the curve and duration to use.
* @return a {@code VolumeShaper} object
- * @throws IllegalArgumentException if the configuration is not allowed by the player.
- * @throws IllegalStateException if too many VolumeShapers are requested or the state of
- * the player does not permit its creation (e.g. player is released).
+ * @throws IllegalArgumentException if the {@code configuration} is not allowed by the player.
+ * @throws IllegalStateException if too many {@code VolumeShaper}s are requested
+ * or the state of the player does not permit its creation (e.g. player is released).
*/
public @NonNull VolumeShaper createVolumeShaper(
@NonNull VolumeShaper.Configuration configuration);
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 8f4721f..3068706 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -31,8 +31,16 @@
/**
* The {@code VolumeShaper} class is used to automatically control audio volume during media
* playback, allowing simple implementation of transition effects and ducking.
+ * It is created from implementations of {@code VolumeAutomation},
+ * such as {@code MediaPlayer} and {@code AudioTrack} (referred to as "players" below),
+ * by {@link MediaPlayer#createVolumeShaper} or {@link AudioTrack#createVolumeShaper}.
*
- * The {@link VolumeShaper} appears as an additional scaling on the audio output,
+ * A {@code VolumeShaper} is intended for short volume changes.
+ * If the audio output sink changes during
+ * a {@code VolumeShaper} transition, the precise curve position may be lost, and the
+ * {@code VolumeShaper} may advance to the end of the curve for the new audio output sink.
+ *
+ * The {@code VolumeShaper} appears as an additional scaling on the audio output,
* and adjusts independently of track or stream volume controls.
*/
public final class VolumeShaper implements AutoCloseable {
@@ -52,7 +60,19 @@
/**
* Applies the {@link VolumeShaper.Operation} to the {@code VolumeShaper}.
+ *
+ * Applying {@link VolumeShaper.Operation#PLAY} after {@code PLAY}
+ * or {@link VolumeShaper.Operation#REVERSE} after
+ * {@code REVERSE} has no effect.
+ *
+ * Applying {@link VolumeShaper.Operation#PLAY} when the player
+ * hasn't started will synchronously start the {@code VolumeShaper} when
+ * playback begins.
+ *
* @param operation the {@code operation} to apply.
+ * @throws IllegalStateException if the player is uninitialized or if there
+ * is a critical failure. In that case, the {@code VolumeShaper} should be
+ * recreated.
*/
public void apply(@NonNull Operation operation) {
/* void */ applyPlayer(new VolumeShaper.Configuration(mId), operation);
@@ -65,11 +85,24 @@
* This allows the user to change the volume shape
* while the existing {@code VolumeShaper} is in effect.
*
+ * The effect of {@code replace()} is similar to an atomic close of
+ * the existing {@code VolumeShaper} and creation of a new {@code VolumeShaper}.
+ *
+ * If the {@code operation} is {@link VolumeShaper.Operation#PLAY} then the
+ * new curve starts immediately.
+ *
+ * If the {@code operation} is
+ * {@link VolumeShaper.Operation#REVERSE}, then the new curve will
+ * be delayed until {@code PLAY} is applied.
+ *
* @param configuration the new {@code configuration} to use.
- * @param operation the operation to apply to the {@code VolumeShaper}
+ * @param operation the {@code operation} to apply to the {@code VolumeShaper}
* @param join if true, match the start volume of the
* new {@code configuration} to the current volume of the existing
* {@code VolumeShaper}, to avoid discontinuity.
+ * @throws IllegalStateException if the player is uninitialized or if there
+ * is a critical failure. In that case, the {@code VolumeShaper} should be
+ * recreated.
*/
public void replace(
@NonNull Configuration configuration, @NonNull Operation operation, boolean join) {
@@ -81,7 +114,14 @@
/**
* Returns the current volume scale attributable to the {@code VolumeShaper}.
*
+ * This is the last volume from the {@code VolumeShaper} used for the player,
+ * or the initial volume if the {@code VolumeShaper} hasn't been started with
+ * {@link VolumeShaper.Operation#PLAY}.
+ *
* @return the volume, linearly represented as a value between 0.f and 1.f.
+ * @throws IllegalStateException if the player is uninitialized or if there
+ * is a critical failure. In that case, the {@code VolumeShaper} should be
+ * recreated.
*/
public float getVolume() {
return getStatePlayer(mId).getVolume();
@@ -89,7 +129,14 @@
/**
* Releases the {@code VolumeShaper} object; any volume scale due to the
- * {@code VolumeShaper} is removed.
+ * {@code VolumeShaper} is removed after closing.
+ *
+ * If the volume does not reach 1.f when the {@code VolumeShaper} is closed
+ * (or finalized), there may be an abrupt change of volume.
+ *
+ * {@code close()} may be safely called after a prior {@code close()}.
+ * This class implements the Java {@code AutoClosable} interface and
+ * may be used with try-with-resources.
*/
@Override
public void close() {
@@ -107,11 +154,11 @@
@Override
protected void finalize() {
- close(); // ensure we remove the native volume shaper
+ close(); // ensure we remove the native VolumeShaper
}
/**
- * Internal call to apply the configuration and operation to the Player.
+ * Internal call to apply the {@code configuration} and {@code operation} to the player.
* Returns a valid shaper id or throws the appropriate exception.
* @param configuration
* @param operation
@@ -137,7 +184,7 @@
// Due to RPC handling, we translate integer codes to exceptions right before
// delivering to the user.
if (id == VOLUME_SHAPER_INVALID_OPERATION) {
- throw new IllegalStateException("player or volume shaper deallocated");
+ throw new IllegalStateException("player or VolumeShaper deallocated");
} else {
throw new IllegalArgumentException("invalid configuration or operation: " + id);
}
@@ -146,9 +193,9 @@
}
/**
- * Internal call to retrieve the current VolumeShaper state.
+ * Internal call to retrieve the current {@code VolumeShaper} state.
* @param id
- * @return the current {@vode VolumeShaper.State}
+ * @return the current {@code VolumeShaper.State}
* @throws IllegalStateException if the player has been deallocated or is uninitialized.
*/
private @NonNull VolumeShaper.State getStatePlayer(int id) {
@@ -180,6 +227,9 @@
* by {@link VolumeShaper#replace(Configuration, Operation, boolean)
* VolumeShaper.replace(Configuration, Operation, boolean)}
* to replace an existing {@code configuration}.
+ * <p>
+ * The {@link AudioTrack} and {@link MediaPlayer} classes implement
+ * the {@link VolumeAutomation} interface.
*/
public static final class Configuration implements Parcelable {
private static final int MAXIMUM_CURVE_POINTS = 16;
@@ -485,7 +535,7 @@
/**
* @hide
- * Constructs a volume shaper from an id.
+ * Constructs a {@code VolumeShaper} from an id.
*
* This is an opaque handle for controlling a {@code VolumeShaper} that has
* already been sent to a player. The {@code id} is returned from the
@@ -756,7 +806,7 @@
/**
* Sets the interpolator type.
*
- * If omitted the interplator type is {@link #INTERPOLATOR_TYPE_CUBIC}.
+ * If omitted the default interpolator type is {@link #INTERPOLATOR_TYPE_CUBIC}.
*
* @param interpolatorType method of interpolation used for the volume curve.
* One of {@link #INTERPOLATOR_TYPE_STEP},
@@ -802,7 +852,7 @@
}
/**
- * Sets the volume shaper duration in milliseconds.
+ * Sets the {@code VolumeShaper} duration in milliseconds.
*
* If omitted, the default duration is 1 second.
*
@@ -1059,13 +1109,13 @@
/**
* Defer playback until next operation is sent. This is used
- * when starting a VolumeShaper effect.
+ * when starting a {@code VolumeShaper} effect.
*/
private static final int FLAG_DEFER = 1 << 3;
/**
* Use the id specified in the configuration, creating
- * VolumeShaper as needed; the configuration should be
+ * {@code VolumeShaper} as needed; the configuration should be
* TYPE_SCALE.
*/
private static final int FLAG_CREATE_IF_NEEDED = 1 << 4;
@@ -1074,18 +1124,20 @@
private final int mFlags;
private final int mReplaceId;
+ private final float mXOffset;
@Override
public String toString() {
return "VolumeShaper.Operation{"
+ "mFlags = 0x" + Integer.toHexString(mFlags).toUpperCase()
+ ", mReplaceId = " + mReplaceId
+ + ", mXOffset = " + mXOffset
+ "}";
}
@Override
public int hashCode() {
- return Objects.hash(mFlags, mReplaceId);
+ return Objects.hash(mFlags, mReplaceId, mXOffset);
}
@Override
@@ -1093,10 +1145,10 @@
if (!(o instanceof Operation)) return false;
if (o == this) return true;
final Operation other = (Operation) o;
- // if xOffset (native field only) is brought into Java
- // we need to do proper NaN comparison as that is allowed.
+
return mFlags == other.mFlags
- && mReplaceId == other.mReplaceId;
+ && mReplaceId == other.mReplaceId
+ && Float.compare(mXOffset, other.mXOffset) == 0;
}
@Override
@@ -1109,7 +1161,7 @@
// this needs to match the native VolumeShaper.Operation parceling
dest.writeInt(mFlags);
dest.writeInt(mReplaceId);
- dest.writeFloat(Float.NaN); // xOffset (ignored at Java level)
+ dest.writeFloat(mXOffset);
}
public static final Parcelable.Creator<VolumeShaper.Operation> CREATOR
@@ -1119,11 +1171,12 @@
// this needs to match the native VolumeShaper.Operation parceling
final int flags = p.readInt();
final int replaceId = p.readInt();
- final float xOffset = p.readFloat(); // ignored at Java level
+ final float xOffset = p.readFloat();
return new VolumeShaper.Operation(
flags
- , replaceId);
+ , replaceId
+ , xOffset);
}
@Override
@@ -1132,9 +1185,10 @@
}
};
- private Operation(@Flag int flags, int replaceId) {
+ private Operation(@Flag int flags, int replaceId, float xOffset) {
mFlags = flags;
mReplaceId = replaceId;
+ mXOffset = xOffset;
}
/**
@@ -1146,6 +1200,7 @@
public static final class Builder {
int mFlags;
int mReplaceId;
+ float mXOffset;
/**
* Constructs a new {@code Builder} with the defaults.
@@ -1153,23 +1208,27 @@
public Builder() {
mFlags = 0;
mReplaceId = -1;
+ mXOffset = Float.NaN;
}
/**
- * Constructs a new Builder from a given {@code VolumeShaper.Operation}
+ * Constructs a new {@code Builder} from a given {@code VolumeShaper.Operation}
* @param operation the {@code VolumeShaper.operation} whose data will be
- * reused in the new Builder.
+ * reused in the new {@code Builder}.
*/
public Builder(@NonNull VolumeShaper.Operation operation) {
mReplaceId = operation.mReplaceId;
mFlags = operation.mFlags;
+ mXOffset = operation.mXOffset;
}
/**
- * Replaces the previous {@code VolumeShaper} specified by id.
- * It has no other effect if the {@code VolumeShaper} is
- * already expired.
- * @param id the id of the previous {@code VolumeShaper}.
+ * Replaces the previous {@code VolumeShaper} specified by {@code id}.
+ *
+ * The {@code VolumeShaper} specified by the {@code id} is removed
+ * if it exists. The configuration should be TYPE_SCALE.
+ *
+ * @param id the {@code id} of the previous {@code VolumeShaper}.
* @param join if true, match the volume of the previous
* shaper to the start volume of the new {@code VolumeShaper}.
* @return the same {@code Builder} instance.
@@ -1194,8 +1253,9 @@
}
/**
- * Terminates the VolumeShaper.
- * Do not call directly, use {@link VolumeShaper#release()}.
+ * Terminates the {@code VolumeShaper}.
+ *
+ * Do not call directly, use {@link VolumeShaper#close()}.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder terminate() {
@@ -1214,8 +1274,12 @@
/**
* Use the id specified in the configuration, creating
- * VolumeShaper as needed; the configuration should be
+ * {@code VolumeShaper} only as needed; the configuration should be
* TYPE_SCALE.
+ *
+ * If the {@code VolumeShaper} with the same id already exists
+ * then the operation has no effect.
+ *
* @return the same {@code Builder} instance.
*/
public @NonNull Builder createIfNeeded() {
@@ -1224,6 +1288,28 @@
}
/**
+ * Sets the {@code xOffset} to use for the {@code VolumeShaper}.
+ *
+ * The {@code xOffset} is the position on the volume curve,
+ * and setting takes effect when the {@code VolumeShaper} is used next.
+ *
+ * @param xOffset a value between (or equal to) 0.f and 1.f, or Float.NaN to ignore.
+ * @return the same {@code Builder} instance.
+ * @throws IllegalArgumentException if {@code xOffset} is not between 0.f and 1.f,
+ * or a Float.NaN.
+ */
+ public @NonNull Builder setXOffset(float xOffset) {
+ if (xOffset < -0.f) {
+ throw new IllegalArgumentException("Negative xOffset not allowed");
+ } else if (xOffset > 1.f) {
+ throw new IllegalArgumentException("xOffset > 1.f not allowed");
+ }
+ // Float.NaN passes through
+ mXOffset = xOffset;
+ return this;
+ }
+
+ /**
* Sets the operation flag. Do not call this directly but one of the
* other builder methods.
*
@@ -1245,7 +1331,7 @@
* @return a new {@code VolumeShaper.Operation} object
*/
public @NonNull Operation build() {
- return new Operation(mFlags, mReplaceId);
+ return new Operation(mFlags, mReplaceId, mXOffset);
}
} // Operation.Builder
} // Operation
@@ -1316,15 +1402,18 @@
/**
* Gets the volume of the {@link VolumeShaper.State}.
+ * @return linear volume between 0.f and 1.f.
*/
public float getVolume() {
return mVolume;
}
/**
- * Gets the elapsed ms of the {@link VolumeShaper.State}
+ * Gets the {@code xOffset} position on the normalized curve
+ * of the {@link VolumeShaper.State}.
+ * @return the curve x position between 0.f and 1.f.
*/
- public double getXOffset() {
+ public float getXOffset() {
return mXOffset;
}
} // State
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 789d5e0..ece19e4 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -148,62 +148,60 @@
* </p>
*/
public void connect() {
- if (mState != CONNECT_STATE_DISCONNECTED) {
- throw new IllegalStateException("connect() called while not disconnected (state="
- + getStateLabel(mState) + ")");
- }
- // TODO: remove this extra check.
- if (DBG) {
- if (mServiceConnection != null) {
- throw new RuntimeException("mServiceConnection should be null. Instead it is "
- + mServiceConnection);
- }
- }
- if (mServiceBinder != null) {
- throw new RuntimeException("mServiceBinder should be null. Instead it is "
- + mServiceBinder);
- }
- if (mServiceCallbacks != null) {
- throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
- + mServiceCallbacks);
+ if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
+ throw new IllegalStateException("connect() called while neither disconnecting nor "
+ + "disconnected (state=" + getStateLabel(mState) + ")");
}
mState = CONNECT_STATE_CONNECTING;
-
- final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
- intent.setComponent(mServiceComponent);
-
- final ServiceConnection thisConnection = mServiceConnection = new MediaServiceConnection();
-
- boolean bound = false;
- try {
- bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- } catch (Exception ex) {
- Log.e(TAG, "Failed binding to service " + mServiceComponent);
- }
-
- if (!bound) {
- // Tell them that it didn't work. We are already on the main thread,
- // but we don't want to do callbacks inside of connect(). So post it,
- // and then check that we are on the same ServiceConnection. We know
- // we won't also get an onServiceConnected or onServiceDisconnected,
- // so we won't be doing double callbacks.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Ensure that nobody else came in or tried to connect again.
- if (thisConnection == mServiceConnection) {
- forceCloseConnection();
- mCallback.onConnectionFailed();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mState == CONNECT_STATE_DISCONNECTING) {
+ return;
+ }
+ mState = CONNECT_STATE_CONNECTING;
+ // TODO: remove this extra check.
+ if (DBG) {
+ if (mServiceConnection != null) {
+ throw new RuntimeException("mServiceConnection should be null. Instead it"
+ + " is " + mServiceConnection);
}
}
- });
- }
+ if (mServiceBinder != null) {
+ throw new RuntimeException("mServiceBinder should be null. Instead it is "
+ + mServiceBinder);
+ }
+ if (mServiceCallbacks != null) {
+ throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
+ + mServiceCallbacks);
+ }
- if (DBG) {
- Log.d(TAG, "connect...");
- dump();
- }
+ final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
+ intent.setComponent(mServiceComponent);
+
+ mServiceConnection = new MediaServiceConnection();
+
+ boolean bound = false;
+ try {
+ bound = mContext.bindService(intent, mServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed binding to service " + mServiceComponent);
+ }
+
+ if (!bound) {
+ // Tell them that it didn't work.
+ forceCloseConnection();
+ mCallback.onConnectionFailed();
+ }
+
+ if (DBG) {
+ Log.d(TAG, "connect...");
+ dump();
+ }
+ }
+ });
}
/**
@@ -218,6 +216,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
+ // connect() could be called before this. Then we will disconnect and reconnect.
if (mServiceCallbacks != null) {
try {
mServiceBinder.disconnect(mServiceCallbacks);
@@ -227,7 +226,13 @@
Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
}
}
+ int state = mState;
forceCloseConnection();
+ // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
+ // the operation came after disconnect() can be handled properly.
+ if (state != CONNECT_STATE_DISCONNECTING) {
+ mState = state;
+ }
if (DBG) {
Log.d(TAG, "disconnect...");
dump();
@@ -245,6 +250,9 @@
* a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
* for a clean shutdown, but everywhere else is a dirty shutdown and should
* notify the app.
+ * <p>
+ * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
+ * except for disconnect().
*/
private void forceCloseConnection() {
if (mServiceConnection != null) {
@@ -684,8 +692,9 @@
* Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
*/
private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
- if (mServiceCallbacks != callback) {
- if (mState != CONNECT_STATE_DISCONNECTED) {
+ if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
+ || mState == CONNECT_STATE_DISCONNECTED) {
+ if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
+ mServiceCallbacks + " this=" + this);
}
@@ -1040,8 +1049,9 @@
* Return true if this is the current ServiceConnection. Also logs if it's not.
*/
private boolean isCurrent(String funcName) {
- if (mServiceConnection != this) {
- if (mState != CONNECT_STATE_DISCONNECTED) {
+ if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
+ || mState == CONNECT_STATE_DISCONNECTED) {
+ if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
// Check mState, because otherwise this log is noisy.
Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
+ mServiceConnection + " this=" + this);
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index e7da20b..102e02d 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -601,10 +601,12 @@
* given time frame.
*
* @param channelId The ID of the channel to return programs for.
- * @param startTime The start time used to filter programs. The returned programs should have
- * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
- * @param endTime The end time used to filter programs. The returned programs should have
- * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
+ * @param startTime The start time used to filter programs. The returned programs will have a
+ * {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than or equal to
+ {@code startTime}.
+ * @param endTime The end time used to filter programs. The returned programs will have
+ * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than or equal to
+ * {@code endTime}.
*/
public static Uri buildProgramsUriForChannel(long channelId, long startTime,
long endTime) {
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 7b5f778..e24124d 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -974,7 +974,7 @@
* seek to a position earlier than the start position.
*
* <p>For playback of a recorded program initiated by {@link #onTimeShiftPlay(Uri)}, the
- * start position is the time when playback starts. It does not change.
+ * start position should be 0 and does not change.
*
* @see #onTimeShiftPlay(Uri)
* @see #onTimeShiftResume()
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
new file mode 100644
index 0000000..9686ab5
--- /dev/null
+++ b/media/jni/Android.bp
@@ -0,0 +1,83 @@
+cc_library_shared {
+ name: "libmedia_jni",
+
+ srcs: [
+ "android_media_ImageWriter.cpp",
+ "android_media_ImageReader.cpp",
+ "android_media_MediaCrypto.cpp",
+ "android_media_MediaCodec.cpp",
+ "android_media_MediaCodecList.cpp",
+ "android_media_MediaDataSource.cpp",
+ "android_media_MediaDescrambler.cpp",
+ "android_media_MediaDrm.cpp",
+ "android_media_MediaExtractor.cpp",
+ "android_media_MediaHTTPConnection.cpp",
+ "android_media_MediaMetricsJNI.cpp",
+ "android_media_MediaMetadataRetriever.cpp",
+ "android_media_MediaMuxer.cpp",
+ "android_media_MediaPlayer.cpp",
+ "android_media_MediaProfiles.cpp",
+ "android_media_MediaRecorder.cpp",
+ "android_media_MediaScanner.cpp",
+ "android_media_MediaSync.cpp",
+ "android_media_ResampleInputStream.cpp",
+ "android_media_SyncParams.cpp",
+ "android_media_Utils.cpp",
+ "android_mtp_MtpDatabase.cpp",
+ "android_mtp_MtpDevice.cpp",
+ "android_mtp_MtpServer.cpp",
+ "midi/android_media_midi_MidiDevice.cpp",
+ ],
+
+ shared_libs: [
+ "libandroid_runtime",
+ "libnativehelper",
+ "libutils",
+ "libbinder",
+ "libmedia",
+ "libmediametrics",
+ "libmediadrm",
+ "libmidi",
+ "libskia",
+ "libui",
+ "liblog",
+ "libcutils",
+ "libgui",
+ "libstagefright",
+ "libstagefright_foundation",
+ "libcamera_client",
+ "libmtp",
+ "libexif",
+ "libpiex",
+ "libandroidfw",
+ ],
+
+ header_libs: ["libhardware_headers"],
+
+ static_libs: ["libgrallocusage"],
+
+ include_dirs: [
+ "frameworks/base/core/jni",
+ "frameworks/native/include/media/openmax",
+ "system/media/camera/include",
+ ],
+
+ export_include_dirs: ["."],
+
+ export_shared_lib_headers: [
+ "libpiex",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
+
+subdirs = [
+ "audioeffect",
+ "soundpool",
+]
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
deleted file mode 100644
index c2ed8cf..0000000
--- a/media/jni/Android.mk
+++ /dev/null
@@ -1,79 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_media_ImageWriter.cpp \
- android_media_ImageReader.cpp \
- android_media_MediaCrypto.cpp \
- android_media_MediaCodec.cpp \
- android_media_MediaCodecList.cpp \
- android_media_MediaDataSource.cpp \
- android_media_MediaDescrambler.cpp \
- android_media_MediaDrm.cpp \
- android_media_MediaExtractor.cpp \
- android_media_MediaHTTPConnection.cpp \
- android_media_MediaMetricsJNI.cpp \
- android_media_MediaMetadataRetriever.cpp \
- android_media_MediaMuxer.cpp \
- android_media_MediaPlayer.cpp \
- android_media_MediaProfiles.cpp \
- android_media_MediaRecorder.cpp \
- android_media_MediaScanner.cpp \
- android_media_MediaSync.cpp \
- android_media_ResampleInputStream.cpp \
- android_media_SyncParams.cpp \
- android_media_Utils.cpp \
- android_mtp_MtpDatabase.cpp \
- android_mtp_MtpDevice.cpp \
- android_mtp_MtpServer.cpp \
- midi/android_media_midi_MidiDevice.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libnativehelper \
- libutils \
- libbinder \
- libmedia \
- libmediametrics \
- libmediadrm \
- libmidi \
- libskia \
- libui \
- liblog \
- libcutils \
- libgui \
- libstagefright \
- libstagefright_foundation \
- libcamera_client \
- libmtp \
- libexif \
- libpiex \
- libandroidfw
-
-LOCAL_STATIC_LIBRARIES := \
- libgrallocusage \
-
-LOCAL_C_INCLUDES += \
- external/libexif/ \
- external/piex/ \
- external/tremor/Tremor \
- frameworks/base/core/jni \
- frameworks/base/libs/hwui \
- frameworks/base/media/native \
- frameworks/av/media/libmedia \
- frameworks/av/media/libstagefright \
- frameworks/av/media/mtp \
- frameworks/native/include/media/openmax \
- $(call include-path-for, libhardware)/hardware \
- $(PV_INCLUDES) \
- $(JNI_H_INCLUDE)
-
-LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code
-
-LOCAL_MODULE:= libmedia_jni
-
-include $(BUILD_SHARED_LIBRARY)
-
-# build libsoundpool.so
-# build libaudioeffect_jni.so
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 163c4b0..52fadfa 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -27,7 +27,6 @@
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
-#include <camera3.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index b5ea632..7c424d9 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -25,7 +25,6 @@
#include <gui/Surface.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
-#include <camera3.h>
#include <jni.h>
#include <JNIHelp.h>
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index 2adbfee..cbdb8ce 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -51,6 +51,9 @@
}
JCrypto::~JCrypto() {
+ if (mCrypto != NULL) {
+ mCrypto->destroyPlugin();
+ }
mCrypto.clear();
JNIEnv *env = AndroidRuntime::getJNIEnv();
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index c62d930..458d847 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -17,6 +17,7 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "AndroidMediaUtils"
+#include <hardware/camera3.h>
#include <utils/Log.h>
#include "android_media_Utils.h"
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 39c1554..af2f2d7 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -21,7 +21,6 @@
#include "src/piex.h"
#include <android_runtime/AndroidRuntime.h>
-#include <camera3.h>
#include <gui/CpuConsumer.h>
#include <jni.h>
#include <JNIHelp.h>
diff --git a/media/jni/android_media_VolumeShaper.h b/media/jni/android_media_VolumeShaper.h
index 73498a2..1a13ffa 100644
--- a/media/jni/android_media_VolumeShaper.h
+++ b/media/jni/android_media_VolumeShaper.h
@@ -40,6 +40,7 @@
jmethodID opConstructId;
jfieldID opFlagsId;
jfieldID opReplaceIdId;
+ jfieldID opXOffsetId;
// VolumeShaper.State
jclass stClazz;
@@ -74,9 +75,10 @@
if (opClazz == nullptr) {
return;
}
- opConstructId = env->GetMethodID(opClazz, "<init>", "(II)V");
+ opConstructId = env->GetMethodID(opClazz, "<init>", "(IIF)V");
opFlagsId = env->GetFieldID(opClazz, "mFlags", "I");
opReplaceIdId = env->GetFieldID(opClazz, "mReplaceId", "I");
+ opXOffsetId = env->GetFieldID(opClazz, "mXOffset", "F");
env->DeleteLocalRef(lclazz);
lclazz = env->FindClass("android/media/VolumeShaper$State");
@@ -179,17 +181,20 @@
VolumeShaper::Operation::Flag flags =
(VolumeShaper::Operation::Flag)env->GetIntField(joperation, fields.opFlagsId);
int replaceId = env->GetIntField(joperation, fields.opReplaceIdId);
+ float xOffset = env->GetFloatField(joperation, fields.opXOffsetId);
- sp<VolumeShaper::Operation> operation = new VolumeShaper::Operation(flags, replaceId);
+ sp<VolumeShaper::Operation> operation =
+ new VolumeShaper::Operation(flags, replaceId, xOffset);
return operation;
}
static jobject convertOperationToJobject(
JNIEnv *env, const fields_t &fields, const sp<VolumeShaper::Operation> &operation) {
// prepare constructor args
- jvalue args[2];
+ jvalue args[3];
args[0].i = (jint)operation->getFlags();
args[1].i = (jint)operation->getReplaceId();
+ args[2].f = (jfloat)operation->getXOffset();
jobject joperation = env->NewObjectA(fields.opClazz, fields.opConstructId, args);
return joperation;
diff --git a/media/jni/audioeffect/Android.bp b/media/jni/audioeffect/Android.bp
new file mode 100644
index 0000000..2aca0c1
--- /dev/null
+++ b/media/jni/audioeffect/Android.bp
@@ -0,0 +1,25 @@
+cc_library_shared {
+ name: "libaudioeffect_jni",
+
+ srcs: [
+ "android_media_AudioEffect.cpp",
+ "android_media_Visualizer.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libandroid_runtime",
+ "libnativehelper",
+ "libmedia",
+ "libaudioclient",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
deleted file mode 100644
index 777636b..0000000
--- a/media/jni/audioeffect/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_media_AudioEffect.cpp \
- android_media_Visualizer.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libutils \
- libandroid_runtime \
- libnativehelper \
- libmedia \
- libaudioclient \
-
-LOCAL_MODULE:= libaudioeffect_jni
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index 401012f..d4cc3fb 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -86,6 +86,7 @@
case NO_MEMORY:
return AUDIOEFFECT_ERROR_NO_MEMORY;
case DEAD_OBJECT:
+ case FAILED_TRANSACTION: // Hidl crash shows as FAILED_TRANSACTION: -2147483646
return AUDIOEFFECT_ERROR_DEAD_OBJECT;
default:
return AUDIOEFFECT_ERROR;
diff --git a/media/jni/midi/android_media_midi_MidiDevice.cpp b/media/jni/midi/android_media_midi_MidiDevice.cpp
index 3743e4a..4df8436 100644
--- a/media/jni/midi/android_media_midi_MidiDevice.cpp
+++ b/media/jni/midi/android_media_midi_MidiDevice.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "Midi-JNI"
#include <android_util_Binder.h>
-#include <midi/midi_internal.h>
+#include <midi_internal.h>
#include <nativehelper/jni.h>
#include <utils/Log.h>
diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp
new file mode 100644
index 0000000..35b7b01
--- /dev/null
+++ b/media/jni/soundpool/Android.bp
@@ -0,0 +1,28 @@
+cc_library_shared {
+ name: "libsoundpool",
+
+ srcs: [
+ "android_media_SoundPool.cpp",
+ "SoundPool.cpp",
+ "SoundPoolThread.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libandroid_runtime",
+ "libnativehelper",
+ "libaudioclient",
+ "libmediandk",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
deleted file mode 100644
index 509a59b..0000000
--- a/media/jni/soundpool/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_media_SoundPool.cpp \
- SoundPool.cpp \
- SoundPoolThread.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libutils \
- libandroid_runtime \
- libnativehelper \
- libaudioclient \
- libmediandk \
- libbinder
-
-LOCAL_MODULE:= libsoundpool
-
-LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/native/Android.bp b/media/native/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/media/native/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index 3500805..11f0dea 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -12,10 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// The headers module is in frameworks/media/native/midi/Android.bp.
-ndk_library {
- name: "libmidi.ndk",
- symbol_file: "libmidi.map.txt",
- first_version: "26",
-// unversioned_until: "current",
+cc_library_shared {
+ name: "libmidi",
+
+ srcs: [
+ "midi.cpp",
+ ":IMidiDeviceServer.aidl",
+ ],
+
+ aidl: {
+ include_dirs: ["frameworks/base/media/java"],
+ export_aidl_headers: true,
+ },
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-O0",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libbinder",
+ "libutils",
+ "libmedia",
+ ],
+
+ export_include_dirs: ["."],
}
diff --git a/media/native/midi/Android.mk b/media/native/midi/Android.mk
deleted file mode 100644
index dbc5eed..0000000
--- a/media/native/midi/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- ../../java/android/media/midi/IMidiDeviceServer.aidl \
- midi.cpp
-
-LOCAL_AIDL_INCLUDES := \
- $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
- frameworks/native/aidl/binder
-
-LOCAL_CFLAGS += -Wall -Werror -O0
-
-LOCAL_MODULE := libmidi
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SHARED_LIBRARIES := liblog libbinder libutils libmedia
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
index 6678f8b..5680d9f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/StaticMetadata.java
@@ -1139,9 +1139,18 @@
}
List<Integer> modeList = new ArrayList<Integer>();
for (int mode : modes) {
- modeList.add(mode);
+ // Skip vendor-added modes
+ if (mode <= CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
+ modeList.add(mode);
+ }
}
checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
+ modes = new int[modeList.size()];
+ for (int i = 0; i < modeList.size(); i++) {
+ modes[i] = modeList.get(i);
+ }
+
+ checkTrueForKey(modesKey, "value is empty", !modeList.isEmpty());
// All camera device must support ON
checkTrueForKey(modesKey, "values " + modeList.toString() + " must contain ON mode",
@@ -1227,7 +1236,17 @@
return new int[0];
}
- List<Integer> modesList = Arrays.asList(CameraTestUtils.toObject(afModes));
+ List<Integer> modesList = new ArrayList<Integer>();
+ for (int afMode : afModes) {
+ // Skip vendor-added AF modes
+ if (afMode > CameraCharacteristics.CONTROL_AF_MODE_EDOF) continue;
+ modesList.add(afMode);
+ }
+ afModes = new int[modesList.size()];
+ for (int i = 0; i < modesList.size(); i++) {
+ afModes[i] = modesList.get(i);
+ }
+
if (isHardwareLevelLimitedOrBetter()) {
// Some LEGACY mode devices do not support AF OFF
checkTrueForKey(key, " All camera devices must support OFF mode",
@@ -1417,6 +1436,16 @@
return fpsRanges;
}
+ public static String getAeModeName(int aeMode) {
+ return (aeMode >= AE_MODE_NAMES.length) ? String.format("VENDOR_AE_MODE_%d", aeMode) :
+ AE_MODE_NAMES[aeMode];
+ }
+
+ public static String getAfModeName(int afMode) {
+ return (afMode >= AF_MODE_NAMES.length) ? String.format("VENDOR_AF_MODE_%d", afMode) :
+ AF_MODE_NAMES[afMode];
+ }
+
/**
* Get the highest supported target FPS range.
* Prioritizes maximizing the min FPS, then the max FPS without lowering min FPS.
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 5d20cf3..c9fba95 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -122,6 +122,11 @@
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+ webSettings.setUseWideViewPort(true);
+ webSettings.setLoadWithOverviewMode(true);
+ webSettings.setSupportZoom(true);
+ webSettings.setBuiltInZoomControls(true);
+ webSettings.setDisplayZoomControls(false);
mWebViewClient = new MyWebViewClient();
myWebView.setWebViewClient(mWebViewClient);
myWebView.setWebChromeClient(new MyWebChromeClient());
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
index 843b313..8d79f62 100644
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/AndroidManifest.xml
@@ -22,7 +22,6 @@
android:label="@string/downloads_app_label"
android:icon="@mipmap/ic_launcher_download"
android:theme="@android:style/Theme.NoDisplay"
- android:screenOrientation="locked"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
index c5292b8..629f6df 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
@@ -18,19 +18,38 @@
import android.annotation.NonNull;
import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
/**
* Sends intent to MtpDocumentsService.
*/
class ServiceIntentSender {
- private Context mContext;
+ private final static String CHANNEL_ID = "device_notification_channel";
+ private final Context mContext;
ServiceIntentSender(Context context) {
mContext = context;
+
+ // Create notification channel.
+ final NotificationChannel mChannel = new NotificationChannel(
+ CHANNEL_ID,
+ context.getResources().getString(
+ com.android.internal.R.string.default_notification_channel_label),
+ NotificationManager.IMPORTANCE_LOW);
+ final NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.createNotificationChannel(mChannel);
+ }
+
+ @VisibleForTesting
+ protected ServiceIntentSender() {
+ mContext = null;
}
/**
@@ -60,12 +79,11 @@
final String title = context.getResources().getString(
R.string.accessing_notification_title,
device.name);
- return new Notification.Builder(context)
+ return new Notification.Builder(context, CHANNEL_ID)
.setLocalOnly(true)
.setContentTitle(title)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
.setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
.setFlag(Notification.FLAG_NO_CLEAR, true)
.build();
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
index ed2dc38..17b3086 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
@@ -17,10 +17,6 @@
package com.android.mtp;
class TestServiceIntentSender extends ServiceIntentSender {
- TestServiceIntentSender() {
- super(null);
- }
-
@Override
void sendUpdateNotificationIntent(MtpDeviceRecord[] record) {}
}
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 0647b4f..6c322ed 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -49,9 +49,9 @@
<item msgid="1805837518286731242">"Undgår midlertidigt dårlig forbindelse"</item>
</string-array>
<string-array name="hdcp_checking_titles">
- <item msgid="441827799230089869">"Kontrollér aldrig"</item>
- <item msgid="6042769699089883931">"Kontrollér kun for DRM-indhold"</item>
- <item msgid="9174900380056846820">"Kontrollér altid"</item>
+ <item msgid="441827799230089869">"Tjek aldrig"</item>
+ <item msgid="6042769699089883931">"Tjek kun for DRM-indhold"</item>
+ <item msgid="9174900380056846820">"Tjek altid"</item>
</string-array>
<string-array name="hdcp_checking_summaries">
<item msgid="505558545611516707">"Brug aldrig HDCP-kontrol"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 0447c52..aa0becf 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -210,7 +210,7 @@
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Vil du tillade udviklingsindstillinger?"</string>
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificer apps via USB"</string>
- <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollér apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
+ <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tjek apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillad, at ringetoner på telefonen kan afspilles i Bluetooth-headset"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
@@ -298,7 +298,7 @@
<string name="inactive_app_inactive_summary" msgid="5091363706699855725">"Inaktiv. Tryk for at skifte."</string>
<string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktiv. Tryk for at skifte."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"Kørende tjenester"</string>
- <string name="runningservices_settings_summary" msgid="854608995821032748">"Vis og kontrollér kørende tjenester"</string>
+ <string name="runningservices_settings_summary" msgid="854608995821032748">"Vis og administrer kørende tjenester"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Konfigurer WebView-implementering"</string>
<string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Dette valg er ikke længere gyldigt. Prøv igen."</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index aa6b3c2..fd20d47 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -319,7 +319,7 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
<string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
<string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> inguru gelditzen dira"</string>
- <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> gelditzen dira guztiz kargatu arte"</string>
+ <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> falta dira guztiz kargatu arte"</string>
<string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> inguru gelditzen dira"</string>
<string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
@@ -327,7 +327,7 @@
<string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Ezezaguna"</string>
- <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzea"</string>
+ <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzen"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"kargatzen"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Ez da kargatzen ari"</string>
<string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 5d29ec0..c69f324 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -324,7 +324,7 @@
<string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - encore environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> avant une charge complète"</string>
+ <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 929332f..399199d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -109,7 +109,7 @@
<string name="tts_default_pitch_title" msgid="6135942113172488671">"Ton"</string>
<string name="tts_default_pitch_summary" msgid="1944885882882650009">"Afecta ao ton da voz sintetizada"</string>
<string name="tts_default_lang_title" msgid="8018087612299820556">"Idioma"</string>
- <string name="tts_lang_use_system" msgid="2679252467416513208">"Utilizar idioma do sistema"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"Utiliza o idioma do sistema"</string>
<string name="tts_lang_not_selected" msgid="7395787019276734765">"Idioma non seleccionado"</string>
<string name="tts_default_lang_summary" msgid="5219362163902707785">"Define a voz específica do idioma para o texto falado"</string>
<string name="tts_play_example_title" msgid="7094780383253097230">"Escoitar un exemplo"</string>
@@ -349,7 +349,7 @@
<string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
<string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
- <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
+ <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e comentarios"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
<string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
<string name="retail_demo_reset_message" msgid="118771671364131297">"Insire contrasinal para restablec. en demostración"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index e0157bc..9e7355b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -21,7 +21,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak dapat memindai jaringan"</string>
- <string name="wifi_security_none" msgid="7985461072596594400">"Tidak Ada"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"Tidak ada"</string>
<string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string>
<string name="wifi_disabled_generic" msgid="4259794910584943386">"Nonaktif"</string>
<string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string>
@@ -229,7 +229,7 @@
<string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Monitor Telefoni akan mengumpulkan log jika mendeteksi masalah pada fungsi telefoni/modem dan mengirimkan notifikasi ke pengguna untuk melaporkan bug"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Masukan"</string>
<string name="debug_drawing_category" msgid="6755716469267367852">"Gambar"</string>
- <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat perangkat keras"</string>
+ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat hardware"</string>
<string name="media_category" msgid="4388305075496848353">"Media"</string>
<string name="debug_monitoring_category" msgid="7640508148375798343">"Memantau"</string>
<string name="strict_mode" msgid="1938795874357830695">"Mode ketat diaktifkan"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 41a116e..3ed642d 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -294,7 +294,7 @@
<item msgid="8280754435979370728">"നമ്മൾ കാണുന്നത് പോലെയുള്ള സ്വാഭാവിക വർണ്ണങ്ങൾ"</item>
<item msgid="5363960654009010371">"ഡിജിറ്റൽ ഉള്ളടക്കത്തിനായി വർണ്ണങ്ങൾ ഒപ്റ്റിമൈസ് ചെയ്തു"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"നിഷ്ക്രിയ ആപ്പ്സ്"</string>
+ <string name="inactive_apps_title" msgid="1317817863508274533">"നിഷ്ക്രിയ ആപ്പുകൾ"</string>
<string name="inactive_app_inactive_summary" msgid="5091363706699855725">"നിഷ്ക്രിയം. മാറ്റുന്നതിനു ടാപ്പുചെയ്യുക."</string>
<string name="inactive_app_active_summary" msgid="4174921824958516106">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 52840e3..12c52812 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -205,10 +205,10 @@
<string name="debug_view_attributes" msgid="6485448367803310384">"Харах тохируулгын шалгалтыг идэвхжүүлэх"</string>
<string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi идэвхтэй байхад ч гэсэн гар утасны датаг идэвхтэй байлгадаг (сүлжээг түргэн солихын тулд)."</string>
<string name="adb_warning_title" msgid="6234463310896563253">"USB дебаг хийхийг зөвшөөрөх үү?"</string>
- <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликешн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликейшн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Таны өмнө нь зөвшөөрөл өгсөн бүх компьютерээс USB дебаг хандалтыг нь хураах уу?"</string>
<string name="dev_settings_warning_title" msgid="7244607768088540165">"Хөгжлийн тохиргоог зөвшөөрөх үү?"</string>
- <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликешнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
@@ -219,12 +219,12 @@
<string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP шалгах авирыг тохируулах"</string>
<string name="debug_debugging_category" msgid="6781250159513471316">"Согог хайх"</string>
<string name="debug_app" msgid="8349591734751384446">"Согог засах апп сонгоно уу"</string>
- <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликешн тохируулаагүй"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликешн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
- <string name="select_application" msgid="5156029161289091703">"Аппликешн сонгох"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликейшн тохируулаагүй"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликейшн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"Аппликейшн сонгох"</string>
<string name="no_application" msgid="2813387563129153880">"Юуг ч биш"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"Согог засагчийг хүлээх"</string>
- <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликешн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликейшн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
<string name="telephony_monitor_switch" msgid="1764958220062121194">"Утасны хяналт"</string>
<string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Утасны хяналт нь утас/модемын ажиллагаанд асуудал илрүүлсэн тохиолдолд лог цуглуулж, хэрэглэгчид алдааг засах мэдэгдэл илгээнэ"</string>
<string name="debug_input_category" msgid="1811069939601180246">"Оруулах"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a6ad468..ef43134 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -102,8 +102,8 @@
<string name="running_process_item_user_label" msgid="3129887865552025943">"Mtumiaji: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguo-msingi zimewekwa"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Hakuna chaguo-misingi zilizowekwa"</string>
- <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya maandishi kwa hotuba"</string>
- <string name="tts_settings_title" msgid="1237820681016639683">"Kubadilisha maandishi hadi usemi"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya kusoma maandishi kwa sauti"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"Kipengele cha kusoma maandishi kwa sauti"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Kasi ya kutamka"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Kasi ya kutamkwa kwa maneno"</string>
<string name="tts_default_pitch_title" msgid="6135942113172488671">"Uzito wa sauti"</string>
@@ -117,7 +117,7 @@
<string name="tts_install_data_title" msgid="4264378440508149986">"Sakinisha data ya sauti"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"Sakinisha data ya sauti inayohitajika kuunganisha usemi"</string>
<string name="tts_engine_security_warning" msgid="8786238102020223650">"Hotuba hii inawezesha injini huenda ikaweza kukusanya maandishi ambayo yatazungumziwa, ikijumlisha data ya kibinafsi ya nenosiri na namba ya kaddi ya mkopo. Inatoka kwa injini ya <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> Wezesha matumizi ya hotuba hii iliyowezeshwa ya injini?"</string>
- <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi kwa towe ya maandishi hadi sauti."</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi ili kipengele cha kusoma maandishi kwa sauti kifanye kazi."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"Huu ni mfano wa usanisi usemaji"</string>
<string name="tts_status_title" msgid="7268566550242584413">"Hali ya lugha chaguo-msingi"</string>
<string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> inaweza kutumiwa kikamilifu"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
index 766c42b..d9f4c44 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.settingslib;
import android.os.SystemClock;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 0ab296e..3135f1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -204,6 +204,13 @@
return colorAccent;
}
+ public static int getThemeAttr(Context context, int attr) {
+ TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+ int theme = ta.getResourceId(0, 0);
+ ta.recycle();
+ return theme;
+ }
+
public static Drawable getDrawable(Context context, int attr) {
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
Drawable drawable = ta.getDrawable(0);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 24ede16..7268d00 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -19,6 +19,8 @@
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
@@ -26,16 +28,22 @@
import android.os.ParcelUuid;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.R;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
-public final class A2dpProfile implements LocalBluetoothProfile {
+public class A2dpProfile implements LocalBluetoothProfile {
private static final String TAG = "A2dpProfile";
private static boolean V = false;
+ private Context mContext;
+
private BluetoothA2dp mService;
+ BluetoothA2dpWrapper.Factory mWrapperFactory;
+ private BluetoothA2dpWrapper mServiceWrapper;
private boolean mIsProfileReady;
private final LocalBluetoothAdapter mLocalAdapter;
@@ -59,6 +67,7 @@
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothA2dp) proxy;
+ mServiceWrapper = mWrapperFactory.getInstance(mService);
// We just bound to the service, so refresh the UI for any connected A2DP devices.
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
while (!deviceList.isEmpty()) {
@@ -88,13 +97,20 @@
A2dpProfile(Context context, LocalBluetoothAdapter adapter,
CachedBluetoothDeviceManager deviceManager,
LocalBluetoothProfileManager profileManager) {
+ mContext = context;
mLocalAdapter = adapter;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
+ mWrapperFactory = new BluetoothA2dpWrapperImpl.Factory();
mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(),
BluetoothProfile.A2DP);
}
+ @VisibleForTesting
+ void setWrapperFactory(BluetoothA2dpWrapper.Factory factory) {
+ mWrapperFactory = factory;
+ }
+
public boolean isConnectable() {
return true;
}
@@ -173,6 +189,72 @@
return false;
}
+ public boolean supportsHighQualityAudio(BluetoothDevice device) {
+ int support = mServiceWrapper.supportsOptionalCodecs(device);
+ return support == BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED;
+ }
+
+ public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
+ int enabled = mServiceWrapper.getOptionalCodecsEnabled(device);
+ if (enabled != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN) {
+ return enabled == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED;
+ } else if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED &&
+ supportsHighQualityAudio(device)) {
+ // Since we don't have a stored preference and the device isn't connected, just return
+ // true since the default behavior when the device gets connected in the future would be
+ // to have optional codecs enabled.
+ return true;
+ }
+ BluetoothCodecConfig codecConfig = null;
+ if (mServiceWrapper.getCodecStatus() != null) {
+ codecConfig = mServiceWrapper.getCodecStatus().getCodecConfig();
+ }
+ if (codecConfig != null) {
+ return !codecConfig.isMandatoryCodec();
+ } else {
+ return false;
+ }
+ }
+
+ public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
+ int prefValue = enabled
+ ? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
+ : BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
+ mServiceWrapper.setOptionalCodecsEnabled(device, prefValue);
+ if (getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
+ return;
+ }
+ if (enabled) {
+ mService.enableOptionalCodecs();
+ } else {
+ mService.disableOptionalCodecs();
+ }
+ }
+
+ public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
+ int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
+ if (!supportsHighQualityAudio(device) ||
+ getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
+ return mContext.getString(unknownCodecId);
+ }
+ // We want to get the highest priority codec, since that's the one that will be used with
+ // this device, and see if it is high-quality (ie non-mandatory).
+ BluetoothCodecConfig[] selectable = null;
+ if (mServiceWrapper.getCodecStatus() != null) {
+ selectable = mServiceWrapper.getCodecStatus().getCodecsSelectableCapabilities();
+ // To get the highest priority, we sort in reverse.
+ Arrays.sort(selectable,
+ (a, b) -> {
+ return b.getCodecPriority() - a.getCodecPriority();
+ });
+ }
+ if (selectable == null || selectable.length < 1 || selectable[0].isMandatoryCodec()) {
+ return mContext.getString(unknownCodecId);
+ }
+ return mContext.getString(R.string.bluetooth_profile_a2dp_high_quality,
+ selectable[0].getCodecName());
+ }
+
public String toString() {
return NAME;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapper.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapper.java
new file mode 100644
index 0000000..aa3e835
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * This interface replicates some methods of android.bluetooth.BluetoothA2dp that are new and not
+ * yet available in our current version of Robolectric. It provides a thin wrapper to call the real
+ * methods in production and a mock in tests.
+ */
+public interface BluetoothA2dpWrapper {
+
+ static interface Factory {
+ BluetoothA2dpWrapper getInstance(BluetoothA2dp service);
+ }
+
+ /**
+ * @return the real {@code BluetoothA2dp} object
+ */
+ BluetoothA2dp getService();
+
+ /**
+ * Wraps {@code BluetoothA2dp.getCodecStatus}
+ */
+ public BluetoothCodecStatus getCodecStatus();
+
+ /**
+ * Wraps {@code BluetoothA2dp.supportsOptionalCodecs}
+ */
+ int supportsOptionalCodecs(BluetoothDevice device);
+
+ /**
+ * Wraps {@code BluetoothA2dp.getOptionalCodecsEnabled}
+ */
+ int getOptionalCodecsEnabled(BluetoothDevice device);
+
+ /**
+ * Wraps {@code BluetoothA2dp.setOptionalCodecsEnabled}
+ */
+ void setOptionalCodecsEnabled(BluetoothDevice device, int value);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapperImpl.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapperImpl.java
new file mode 100644
index 0000000..14fa796
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothA2dpWrapperImpl.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+
+public class BluetoothA2dpWrapperImpl implements BluetoothA2dpWrapper {
+
+ public static class Factory implements BluetoothA2dpWrapper.Factory {
+ @Override
+ public BluetoothA2dpWrapper getInstance(BluetoothA2dp service) {
+ return new BluetoothA2dpWrapperImpl(service);
+ }
+ }
+
+ private BluetoothA2dp mService;
+
+ public BluetoothA2dpWrapperImpl(BluetoothA2dp service) {
+ mService = service;
+ }
+
+ @Override
+ public BluetoothA2dp getService() {
+ return mService;
+ }
+
+ @Override
+ public BluetoothCodecStatus getCodecStatus() {
+ return mService.getCodecStatus();
+ }
+
+ @Override
+ public int supportsOptionalCodecs(BluetoothDevice device) {
+ return mService.supportsOptionalCodecs(device);
+ }
+
+ @Override
+ public int getOptionalCodecsEnabled(BluetoothDevice device) {
+ return mService.getOptionalCodecsEnabled(device);
+ }
+
+ @Override
+ public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
+ mService.setOptionalCodecsEnabled(device, value);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 5a9a749..0750dc7 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -42,7 +42,7 @@
* LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
* objects for the available Bluetooth profiles.
*/
-public final class LocalBluetoothProfileManager {
+public class LocalBluetoothProfileManager {
private static final String TAG = "LocalBluetoothProfileManager";
private static final boolean DEBUG = Utils.D;
/** Singleton instance. */
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 46fbb24..bb525c8 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -26,6 +26,8 @@
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.Path.Direction;
+import android.graphics.Path.FillType;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -36,8 +38,9 @@
public class BatteryMeterDrawableBase extends Drawable {
- private static final float ASPECT_RATIO = 9.5f / 14.5f;
+ private static final float ASPECT_RATIO = .58f;
public static final String TAG = BatteryMeterDrawableBase.class.getSimpleName();
+ private static final float RADIUS_RATIO = 1.75f / 17f;
protected final Context mContext;
protected final Paint mFramePaint;
@@ -88,12 +91,6 @@
private final Path mClipPath = new Path();
private final Path mTextPath = new Path();
- private int mDarkModeBackgroundColor;
- private int mDarkModeFillColor;
-
- private int mLightModeBackgroundColor;
- private int mLightModeFillColor;
-
public BatteryMeterDrawableBase(Context context, int frameColor) {
mContext = context;
final Resources res = context.getResources();
@@ -156,15 +153,6 @@
mPlusPaint = new Paint(mBoltPaint);
mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
- mDarkModeBackgroundColor =
- Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
- mDarkModeFillColor =
- Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
- mLightModeBackgroundColor =
- Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
- mLightModeFillColor =
- Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
-
mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
}
@@ -259,16 +247,6 @@
return color;
}
- public void setDarkIntensity(float darkIntensity) {
- if (darkIntensity == mOldDarkIntensity) {
- return;
- }
- int backgroundColor = getBackgroundColor(darkIntensity);
- int fillColor = getFillColor(darkIntensity);
- setColors(fillColor, backgroundColor);
- mOldDarkIntensity = darkIntensity;
- }
-
public void setColors(int fillColor, int backgroundColor) {
mIconTint = fillColor;
mFramePaint.setColor(backgroundColor);
@@ -277,20 +255,6 @@
invalidateSelf();
}
- private int getBackgroundColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
- }
-
- private int getFillColor(float darkIntensity) {
- return getColorForDarkIntensity(
- darkIntensity, mLightModeFillColor, mDarkModeFillColor);
- }
-
- private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
- return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
- }
-
@Override
public void draw(Canvas c) {
final int level = mLevel;
@@ -302,28 +266,20 @@
final int width = (int) (ASPECT_RATIO * mHeight);
int px = (mWidth - width) / 2;
- final int buttonHeight = (int) (height * mButtonHeightFraction);
+ final int buttonHeight = Math.round(height * mButtonHeightFraction);
mFrame.set(0, 0, width, height);
mFrame.offset(px, 0);
// button-frame: area above the battery body
mButtonFrame.set(
- mFrame.left + Math.round(width * 0.25f),
+ mFrame.left + Math.round(width * 0.3f),
mFrame.top,
- mFrame.right - Math.round(width * 0.25f),
+ mFrame.right - Math.round(width * 0.3f),
mFrame.top + buttonHeight);
- mButtonFrame.top += mSubpixelSmoothingLeft;
- mButtonFrame.left += mSubpixelSmoothingLeft;
- mButtonFrame.right -= mSubpixelSmoothingRight;
-
// frame: battery body area
mFrame.top += buttonHeight;
- mFrame.left += mSubpixelSmoothingLeft;
- mFrame.top += mSubpixelSmoothingLeft;
- mFrame.right -= mSubpixelSmoothingRight;
- mFrame.bottom -= mSubpixelSmoothingRight;
// set the battery charging color
mBatteryPaint.setColor(mCharging ? mChargeColor : getColorForLevel(level));
@@ -339,15 +295,10 @@
// define the battery shape
mShapePath.reset();
- mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
- mShapePath.lineTo(mButtonFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.top);
- mShapePath.lineTo(mFrame.right, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.bottom);
- mShapePath.lineTo(mFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mFrame.top);
- mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+ final float radius = RADIUS_RATIO * (mFrame.height() + buttonHeight);
+ mShapePath.setFillType(FillType.WINDING);
+ mShapePath.addRoundRect(mFrame, radius, radius, Direction.CW);
+ mShapePath.addRect(mButtonFrame, Direction.CW);
if (mCharging) {
// define the bolt shape
diff --git a/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java
new file mode 100644
index 0000000..656ab86
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility.
+ */
+public class BluetoothCodecConfig {
+ public boolean isMandatoryCodec() { return true; }
+ public String getCodecName() { return null;}
+}
diff --git a/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java
new file mode 100644
index 0000000..919ec3f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/android/bluetooth/BluetoothCodecStatus.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+/**
+ * A placeholder class to prevent ClassNotFound exceptions caused by lack of visibility.
+ */
+public class BluetoothCodecStatus {
+ public BluetoothCodecConfig getCodecConfig() { return null; }
+ public BluetoothCodecConfig[] getCodecsSelectableCapabilities() { return null; }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
new file mode 100644
index 0000000..07a0e11
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothCodecConfig;
+import android.bluetooth.BluetoothCodecStatus;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.R;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class A2dpProfileTest {
+
+ @Mock Context mContext;
+ @Mock LocalBluetoothAdapter mAdapter;
+ @Mock CachedBluetoothDeviceManager mDeviceManager;
+ @Mock LocalBluetoothProfileManager mProfileManager;
+ @Mock BluetoothDevice mDevice;
+ @Mock BluetoothA2dp mBluetoothA2dp;
+ @Mock BluetoothA2dpWrapper mBluetoothA2dpWrapper;
+ BluetoothProfile.ServiceListener mServiceListener;
+
+ A2dpProfile mProfile;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ // Capture the A2dpServiceListener our A2dpProfile will pass during its constructor, so that
+ // we can call its onServiceConnected method and get it to use our mock BluetoothA2dp
+ // object.
+ doAnswer((invocation) -> {
+ mServiceListener = (BluetoothProfile.ServiceListener) invocation.getArguments()[1];
+ return null;
+ }).when(mAdapter).getProfileProxy(any(Context.class), any(), eq(BluetoothProfile.A2DP));
+
+ mProfile = new A2dpProfile(mContext, mAdapter, mDeviceManager, mProfileManager);
+ mProfile.setWrapperFactory((service) -> { return mBluetoothA2dpWrapper; });
+ mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp);
+ }
+
+ @Test
+ public void supportsHighQualityAudio() {
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
+ assertThat(mProfile.supportsHighQualityAudio(mDevice)).isTrue();
+
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
+ assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
+
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN);
+ assertThat(mProfile.supportsHighQualityAudio(mDevice)).isFalse();
+ }
+
+ @Test
+ public void isHighQualityAudioEnabled() {
+ when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
+
+ when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
+
+ // If we don't have a stored pref for whether optional codecs should be enabled or not,
+ // then isHighQualityAudioEnabled() should return true or false based on whether optional
+ // codecs are supported. If the device is connected then we should ask it directly, but if
+ // the device isn't connected then rely on the stored pref about such support.
+ when(mBluetoothA2dpWrapper.getOptionalCodecsEnabled(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN);
+ when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
+ BluetoothProfile.STATE_DISCONNECTED);
+
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
+
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
+
+ when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
+ BluetoothProfile.STATE_CONNECTED);
+ BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
+ when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+ BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
+ when(status.getCodecConfig()).thenReturn(config);
+ when(config.isMandatoryCodec()).thenReturn(false);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isTrue();
+ when(config.isMandatoryCodec()).thenReturn(true);
+ assertThat(mProfile.isHighQualityAudioEnabled(mDevice)).isFalse();
+ }
+
+ // Strings to use in fake resource lookups.
+ private static String KNOWN_CODEC_LABEL = "Use high quality audio: %1$s";
+ private static String UNKNOWN_CODEC_LABEL = "Use high quality audio";
+
+ /**
+ * Helper for setting up several tests of getHighQualityAudioOptionLabel
+ */
+ private void setupLabelTest() {
+ // SettingsLib doesn't have string resource lookup working for robotests, so fake our own
+ // string loading.
+ when(mContext.getString(eq(R.string.bluetooth_profile_a2dp_high_quality),
+ any(String.class))).thenAnswer((invocation) -> {
+ return String.format(KNOWN_CODEC_LABEL, invocation.getArguments()[1]);
+ });
+ when(mContext.getString(eq(R.string.bluetooth_profile_a2dp_high_quality_unknown_codec)))
+ .thenReturn(UNKNOWN_CODEC_LABEL);
+
+ // Most tests want to simulate optional codecs being supported by the device, so do that
+ // by default here.
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
+ }
+
+ @Test
+ public void getLableCodecsNotSupported() {
+ setupLabelTest();
+ when(mBluetoothA2dpWrapper.supportsOptionalCodecs(any())).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
+ assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL);
+ }
+
+ @Test
+ public void getLabelDeviceDisconnected() {
+ setupLabelTest();
+ when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
+ BluetoothProfile.STATE_DISCONNECTED);
+ assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL);
+ }
+
+ @Test
+ public void getLabelDeviceConnectedButNotHighQualityCodec() {
+ setupLabelTest();
+ when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
+ BluetoothProfile.STATE_CONNECTED);
+ BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
+ BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
+ BluetoothCodecConfig[] configs = {config};
+ when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+ when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
+
+ when(config.isMandatoryCodec()).thenReturn(true);
+ assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(UNKNOWN_CODEC_LABEL);
+ }
+
+ @Test
+ public void getLabelDeviceConnectedWithHighQualityCodec() {
+ setupLabelTest();
+ when(mBluetoothA2dp.getConnectionState(any())).thenReturn(
+ BluetoothProfile.STATE_CONNECTED);
+ BluetoothCodecStatus status = mock(BluetoothCodecStatus.class);
+ BluetoothCodecConfig config = mock(BluetoothCodecConfig.class);
+ BluetoothCodecConfig[] configs = {config};
+ when(mBluetoothA2dpWrapper.getCodecStatus()).thenReturn(status);
+ when(status.getCodecsSelectableCapabilities()).thenReturn(configs);
+
+ when(config.isMandatoryCodec()).thenReturn(false);
+ when(config.getCodecName()).thenReturn("PiedPiper");
+ assertThat(mProfile.getHighQualityAudioOptionLabel(mDevice)).isEqualTo(
+ String.format(KNOWN_CODEC_LABEL, config.getCodecName()));
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d43b740..f57f48f 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -192,6 +192,9 @@
<!-- to access ResolverRankerServices -->
<uses-permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE" />
+ <!-- to access instant apps -->
+ <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/res/anim/ic_dnd_disable_bar01_0_animation.xml b/packages/SystemUI/res/anim/ic_dnd_disable_bar01_0_animation.xml
deleted file mode 100644
index a914687c..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_disable_bar01_0_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set
- xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 0.680404663086,3.53039550781 c 0.0,0.0 -0.01416015625,0.00492858886719 -0.01416015625,0.00492858886719 c 0.0,0.0 1.41400146484,-1.41400146484 1.41400146484,-1.41400146484 c 0.0,0.0 0.0151519775391,-0.00492858886719 0.0151519775391,-0.00492858886719 c 0.0,0.0 -1.41499328613,1.41400146484 -1.41499328613,1.41400146484 Z"
- android:valueTo="M 0.680404663086,3.53039550781 c 0.0,0.0 20.0110015869,20.0110015869 20.0110015869,20.0110015869 c 0.0,0.0 1.41400146484,-1.41400146484 1.41400146484,-1.41400146484 c 0.0,0.0 -20.0100097656,-20.0110015869 -20.0100097656,-20.0110015869 c 0.0,0.0 -1.41499328613,1.41400146484 -1.41499328613,1.41400146484 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_dnd_disable_mask_1_animation.xml b/packages/SystemUI/res/anim/ic_dnd_disable_mask_1_animation.xml
deleted file mode 100644
index 3c60c01..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_disable_mask_1_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set
- xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M -9.67768859863,-9.82725524902 c 0.0,0.0 -7.8091583252,7.18409729004 -7.8091583252,7.18409729004 c 0.0,0.0 20.9320983887,20.9321136475 20.9320983887,20.9321136475 c 0.0,0.0 15.041595459,-15.0416717529 15.041595459,-15.0416717529 c 0.0,0.0 -20.5361938477,-20.536239624 -20.5361938477,-20.536239624 c 0.0,0.0 -6.20835876465,6.05171203613 -6.20835876465,6.05171203613 c 0.0,0.0 0.219390869141,0.219299316406 0.219390869141,0.219299316406 c 0.0,0.0 -1.41998291016,1.40998840332 -1.41998291016,1.40998840332 c 0.0,0.0 -0.219390869141,-0.219299316406 -0.219390869141,-0.219299316406 Z"
- android:valueTo="M -9.67768859863,-9.82725524902 c 0.0,0.0 -7.8091583252,7.18409729004 -7.8091583252,7.18409729004 c 0.0,0.0 20.9320983887,20.9321136475 20.9320983887,20.9321136475 c 0.0,0.0 15.041595459,-15.0416717529 15.041595459,-15.0416717529 c 0.0,0.0 -20.5361938477,-20.536239624 -20.5361938477,-20.536239624 c 0.0,0.0 -6.20835876465,6.05171203613 -6.20835876465,6.05171203613 c 0.0,0.0 20.4531555176,20.4530792236 20.4531555176,20.4530792236 c 0.0,0.0 -1.41999816895,1.40995788574 -1.41999816895,1.40995788574 c 0.0,0.0 -20.4531402588,-20.4530487061 -20.4531402588,-20.4530487061 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_mask_1_animation.xml b/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_mask_1_animation.xml
deleted file mode 100644
index 8d3296e..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_mask_1_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set
- xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M -9.67768859863,-9.82725524902 c 0.0,0.0 -7.8091583252,7.18409729004 -7.8091583252,7.18409729004 c 0.0,0.0 20.9320983887,20.9321136475 20.9320983887,20.9321136475 c 0.0,0.0 15.041595459,-15.0416717529 15.041595459,-15.0416717529 c 0.0,0.0 -20.5361938477,-20.536239624 -20.5361938477,-20.536239624 c 0.0,0.0 -6.20835876465,6.05171203613 -6.20835876465,6.05171203613 c 0.0,0.0 0.219390869141,0.219299316406 0.219390869141,0.219299316406 c 0.0,0.0 -1.41998291016,1.40998840332 -1.41998291016,1.40998840332 c 0.0,0.0 -0.219390869141,-0.219299316406 -0.219390869141,-0.219299316406 Z"
- android:valueTo="M -9.67768859863,-9.82725524902 c 0.0,0.0 -7.8091583252,7.18409729004 -7.8091583252,7.18409729004 c 0.0,0.0 20.9320983887,20.9321136475 20.9320983887,20.9321136475 c 0.0,0.0 15.041595459,-15.0416717529 15.041595459,-15.0416717529 c 0.0,0.0 -20.5361938477,-20.536239624 -20.5361938477,-20.536239624 c 0.0,0.0 -6.20835876465,6.05171203613 -6.20835876465,6.05171203613 c 0.0,0.0 19.8804626465,19.8695220947 19.8804626465,19.8695220947 c 0.0,0.0 -1.41999816895,1.40995788574 -1.41999816895,1.40995788574 c 0.0,0.0 -19.8804473877,-19.8694915771 -19.8804473877,-19.8694915771 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_outer_ring_merged_animation.xml b/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_outer_ring_merged_animation.xml
deleted file mode 100644
index 2626499..0000000
--- a/packages/SystemUI/res/anim/ic_dnd_total_silence_disable_outer_ring_merged_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set
- xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 0.0,-10.0 c -5.5,0.0 -10.0,4.5 -10.0,10.0 c 0.0,5.5 4.5,10.0 10.0,10.0 c 5.5,0.0 10.0,-4.5 10.0,-10.0 c 0.0,-5.5 -4.5,-10.0 -10.0,-10.0 Z M 0.0,8.5 c -4.69999694824,0.0 -8.5,-3.80000305176 -8.5,-8.5 c 0.0,-4.69999694824 3.80000305176,-8.5 8.5,-8.5 c 4.69999694824,0.0 8.5,3.80000305176 8.5,8.5 c 0.0,4.69999694824 -3.80000305176,8.5 -8.5,8.5 Z M -11.3195953369,-8.46960449219 c 0.0,0.0 -0.0141754150391,0.00492858886719 -0.014175415039,0.00492858886719 c 0.0,0.0 1.41400146484,-1.41400146484 1.41400146484,-1.41400146484 c 0.0,0.0 0.0151672363281,-0.00492858886719 0.0151672363281,-0.00492858886719 c 0.0,0.0 -1.41499328613,1.41400146484 -1.41499328613,1.41400146484 Z M 3.0,1.0 c 0.0,0.0 -6.0,0.0 -6.0,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 c 0.0,0.0 6.0,0.0 6.0,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 Z M 0.0,-6.0 c -3.30000305176,0.0 -6.0,2.69999694824 -6.0,6.0 c 0.0,3.30000305176 2.69999694824,6.0 6.0,6.0 c 3.30000305176,0.0 6.0,-2.69999694824 6.0,-6.0 c 0.0,-3.30000305176 -2.60000610352,-6.0 -6.0,-6.0 Z"
- android:valueTo="M 0.0,-10.0 c -5.5,0.0 -10.0,4.5 -10.0,10.0 c 0.0,5.5 4.5,10.0 10.0,10.0 c 5.5,0.0 10.0,-4.5 10.0,-10.0 c 0.0,-5.5 -4.5,-10.0 -10.0,-10.0 Z M 0.0,8.5 c -4.69999694824,0.0 -8.5,-3.80000305176 -8.5,-8.5 c 0.0,-4.69999694824 3.80000305176,-8.5 8.5,-8.5 c 4.69999694824,0.0 8.5,3.80000305176 8.5,8.5 c 0.0,4.69999694824 -3.80000305176,8.5 -8.5,8.5 Z M -11.3195953369,-8.46960449219 c 0.0,0.0 20.0109863281,20.0110015869 20.0109863281,20.0110015869 c 0.0,0.0 1.41400146484,-1.41400146484 1.41400146484,-1.41400146484 c 0.0,0.0 -20.0099945068,-20.0110015869 -20.0099945068,-20.0110015869 c 0.0,0.0 -1.41499328613,1.41400146484 -1.41499328613,1.41400146484 Z M 5.0,1.0 c 0.0,0.0 -10.0,0.0 -10.0,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 c 0.0,0.0 10.0,0.0 10.0,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 Z M 0.0,-10.0 c -5.52000427246,0.0 -10.0,4.47999572754 -10.0,10.0 c 0.0,5.52000427246 4.47999572754,10.0 10.0,10.0 c 5.52000427246,0.0 10.0,-4.47999572754 10.0,-10.0 c 0.0,-5.52000427246 -4.47999572754,-10.0 -10.0,-10.0 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_hotspot_disable_animation_cross_1.xml
deleted file mode 100644
index ad06d8e..0000000
--- a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 4.44044494629,2.24310302734 c 0.0,0.0 0.0875396728516,0.112457275391 0.0875396728516,0.112457275391 "
- android:valueTo="M 4.44044494629,2.24310302734 c 0.0,0.0 35.4000396729,35.3999633789 35.4000396729,35.3999633789 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_disable_cross_1_pathdata_interpolator" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_hotspot_disable_animation_mask.xml
deleted file mode 100644
index 4cd8ce9..0000000
--- a/packages/SystemUI/res/anim/ic_hotspot_disable_animation_mask.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="117"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 6.97125244141,7.33258056641 6.97125244141,7.33258056641 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -6.77128601074,-6.82850646973 -6.77128601074,-6.82850646973 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.659332275391,0.664688110352 0.659332275391,0.664688110351 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 29.0108337402,34.4080963135 29.0108337402,34.4080963135 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 29.8566131592,30.1964874268 29.8566131592,30.1964874268 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -29.6566467285,-29.6924133301 -29.6566467285,-29.6924133301 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.905746459961,0.856552124023 0.905746459961,0.856552124023 c 0.0,0.0 -3.13299560547,2.82975769043 -3.13299560547,2.82975769043 c 0.0,0.0 28.7644195557,34.2162475586 28.7644195557,34.2162475586 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_disable_mask_pathdata_interpolator_1" />
- <objectAnimator
- android:duration="233"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 29.8566131592,30.1964874268 29.8566131592,30.1964874268 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -29.6566467285,-29.6924133301 -29.6566467285,-29.6924133301 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.905746459961,0.856552124023 0.905746459961,0.856552124023 c 0.0,0.0 -3.13299560547,2.82975769043 -3.13299560547,2.82975769043 c 0.0,0.0 28.7644195557,34.2162475586 28.7644195557,34.2162475586 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 43.1884765625,43.515335083 43.1884765625,43.515335083 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -42.9885101318,-43.0112609863 -42.9885101318,-43.0112609863 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 13.0984039307,13.025604248 13.0984039307,13.025604248 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 16.571762085,22.0471801758 16.571762085,22.0471801758 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_disable_mask_pathdata_interpolator_2" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_hotspot_enable_animation_cross_1.xml
deleted file mode 100644
index 523e53a..0000000
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 4.44044494629,2.24310302734 c 0.0,0.0 35.4000396729,35.3999633789 35.4000396729,35.3999633789 "
- android:valueTo="M 4.44044494629,2.24310302734 c 0.0,0.0 0.0875396728516,0.112457275391 0.0875396728516,0.112457275391 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_hotspot_enable_animation_mask.xml
deleted file mode 100644
index 7562c9b..0000000
--- a/packages/SystemUI/res/anim/ic_hotspot_enable_animation_mask.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="233"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 43.1884765625,43.515335083 43.1884765625,43.515335083 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -42.9885101318,-43.0112609863 -42.9885101318,-43.0112609863 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 13.0984039307,13.025604248 13.0984039307,13.025604248 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 16.571762085,22.0471801758 16.571762085,22.0471801758 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 29.8566131592,30.1964874268 29.8566131592,30.1964874268 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -29.6566467285,-29.6924133301 -29.6566467285,-29.6924133301 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.905746459961,0.856552124023 0.905746459961,0.856552124023 c 0.0,0.0 -3.13299560547,2.82975769043 -3.13299560547,2.82975769043 c 0.0,0.0 28.7644195557,34.2162475586 28.7644195557,34.2162475586 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_enable_mask_pathdata_interpolator_1" />
- <objectAnimator
- android:duration="117"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 29.8566131592,30.1964874268 29.8566131592,30.1964874268 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -29.6566467285,-29.6924133301 -29.6566467285,-29.6924133301 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.905746459961,0.856552124023 0.905746459961,0.856552124023 c 0.0,0.0 -3.13299560547,2.82975769043 -3.13299560547,2.82975769043 c 0.0,0.0 28.7644195557,34.2162475586 28.7644195557,34.2162475586 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 6.97125244141,7.33258056641 6.97125244141,7.33258056641 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -6.77128601074,-6.82850646973 -6.77128601074,-6.82850646973 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 0.659332275391,0.664688110352 0.659332275391,0.664688110351 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 29.0108337402,34.4080963135 29.0108337402,34.4080963135 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_hotspot_enable_mask_pathdata_interpolator_2" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_cross_1.xml
deleted file mode 100644
index 5e78f4c..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_invert_colors_disable_cross_1_pathdata_interpolator" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_icon.xml b/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_icon.xml
deleted file mode 100644
index 9cc3b8e..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_icon.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_mask.xml
deleted file mode 100644
index 7f77372..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_disable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_cross_1.xml
deleted file mode 100644
index eacd248..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_invert_colors_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_icon.xml b/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_icon.xml
deleted file mode 100644
index 50a1af6..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_icon.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="0.54"
- android:valueTo="0.54"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="0.54"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_mask.xml
deleted file mode 100644
index a2126a0..0000000
--- a/packages/SystemUI/res/anim/ic_invert_colors_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_invert_colors_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_cross_1.xml
deleted file mode 100644
index 39e4aec..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_airplane_disable_cross_1_pathdata_interpolator" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_ic_signal_airplane.xml b/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_ic_signal_airplane.xml
deleted file mode 100644
index 9cc3b8e..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_ic_signal_airplane.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_mask.xml
deleted file mode 100644
index 7f77372..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_disable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_cross_1.xml
deleted file mode 100644
index 1b73cc0..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_airplane_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_ic_signal_airplane.xml b/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_ic_signal_airplane.xml
deleted file mode 100644
index 5fdb2a0..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_ic_signal_airplane.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_mask.xml
deleted file mode 100644
index c45426c..0000000
--- a/packages/SystemUI/res/anim/ic_signal_airplane_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_airplane_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_cross_1.xml
deleted file mode 100644
index b9b19f5..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 8.34049987793,5.6930847168 c 0.0,0.0 0.274993896484,0.29997253418 0.274993896484,0.29997253418 "
- android:valueTo="M 8.34049987793,5.6930847168 c 0.0,0.0 29.7749786377,29.7999725342 29.7749786377,29.7999725342 "
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_ic_signal_flashlight.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_ic_signal_flashlight.xml
deleted file mode 100644
index 9cc3b8e..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_ic_signal_flashlight.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_mask.xml
deleted file mode 100644
index 321a965..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_disable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-39.2849731445 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-39.2975769043 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_cross_1.xml
deleted file mode 100644
index 011a96f..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 8.34049987793,5.6930847168 c 0.0,0.0 29.7749786377,29.7999725342 29.7749786377,29.7999725342 "
- android:valueTo="M 8.34049987793,5.6930847168 c 0.0,0.0 0.274993896484,0.29997253418 0.274993896484,0.29997253418 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_flashlight_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_ic_signal_flashlight.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_ic_signal_flashlight.xml
deleted file mode 100644
index 5fdb2a0..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_ic_signal_flashlight.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_mask.xml
deleted file mode 100644
index 14bab3a..0000000
--- a/packages/SystemUI/res/anim/ic_signal_flashlight_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-39.2975769043 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-39.2849731445 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_flashlight_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_location_disable_animation_cross_1.xml
deleted file mode 100644
index 0c57530..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 6.44050598145,1.9430847168 c 0.0,0.0 0.374984741211,0.399978637695 0.374984741211,0.399978637695 "
- android:valueTo="M 6.44050598145,1.9430847168 c 0.0,0.0 33.5749816895,33.4499664307 33.5749816895,33.4499664307 "
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_ic_signal_location.xml b/packages/SystemUI/res/anim/ic_signal_location_disable_animation_ic_signal_location.xml
deleted file mode 100644
index 9cc3b8e..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_ic_signal_location.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="1"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_location_disable_animation_mask.xml
deleted file mode 100644
index 501d68b..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_disable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 7.3759765625,7.55284118652 7.3759765625,7.55284118652 c 0.0,0.0 -2.61698913574,2.0938873291 -2.61698913574,2.0938873291 c 0.0,0.0 -7.57595825195,-7.56428527832 -7.57595825195,-7.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,41.1153411865 40.9884796143,41.1153411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-41.1267852783 -41.1884460449,-41.1267852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_location_enable_animation_cross_1.xml
deleted file mode 100644
index 1b5445d..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 6.44050598145,1.9430847168 c 0.0,0.0 33.5749816895,33.4499664307 33.5749816895,33.4499664307 "
- android:valueTo="M 6.44050598145,1.9430847168 c 0.0,0.0 0.374984741211,0.399978637695 0.374984741211,0.399978637695 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_location_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_ic_signal_location.xml b/packages/SystemUI/res/anim/ic_signal_location_enable_animation_ic_signal_location.xml
deleted file mode 100644
index 5fdb2a0..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_ic_signal_location.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_location_enable_animation_mask.xml
deleted file mode 100644
index 9ca12da..0000000
--- a/packages/SystemUI/res/anim/ic_signal_location_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 38.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,41.1153411865 40.9884796143,41.1153411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-41.1267852783 -41.1884460449,-41.1267852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 38.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 7.3759765625,7.55284118652 7.3759765625,7.55284118652 c 0.0,0.0 -2.61698913574,2.0938873291 -2.61698913574,2.0938873291 c 0.0,0.0 -7.57595825195,-7.56428527832 -7.57595825195,-7.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_location_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_cross_1.xml
deleted file mode 100644
index 661ab08..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_cross_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="0"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_mask.xml
deleted file mode 100644
index 1199442..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml
deleted file mode 100644
index 6c7e751..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
- android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator" />
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="333"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="1"
- android:interpolator="@android:interpolator/linear" />
- <objectAnimator
- android:duration="17"
- android:propertyName="strokeAlpha"
- android:valueFrom="1"
- android:valueTo="0"
- android:interpolator="@android:interpolator/linear" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml
deleted file mode 100644
index c699fe2..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <set
- android:ordering="sequentially" >
- <objectAnimator
- android:duration="200"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="0.5"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- <objectAnimator
- android:duration="350"
- android:propertyName="alpha"
- android:valueFrom="0.5"
- android:valueTo="1"
- android:interpolator="@android:interpolator/fast_out_slow_in" />
- </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml
deleted file mode 100644
index 5595e5c..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
- <objectAnimator
- android:duration="350"
- android:propertyName="pathData"
- android:valueFrom="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueTo="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
- android:valueType="pathType"
- android:interpolator="@interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml b/packages/SystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
index b131c38..99ee3b1 100644
--- a/packages/SystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
+++ b/packages/SystemUI/res/drawable/car_stat_sys_data_bluetooth_indicator.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,10 +16,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="17dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
-
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M14.0,24.0l-4.0,-4.0l-4.0,4.0l4.0,4.0L14.0,24.0zM35.4,15.4L24.0,4.0l-2.0,0.0l0.0,15.2L12.8,10.0L10.0,12.8L21.2,24.0L10.0,35.2l2.8,2.8l9.2,-9.2L22.0,44.0l2.0,0.0l11.4,-11.4L26.8,24.0L35.4,15.4zM26.0,11.7l3.8,3.8L26.0,19.2L26.0,11.7zM29.8,32.6L26.0,36.3l0.0,-7.5L29.8,32.6zM38.0,20.0l-4.0,4.0l4.0,4.0l4.0,-4.0L38.0,20.0z"/>
+ android:viewportWidth="18.0"
+ android:viewportHeight="18.0">
+ <group
+ android:translateY="0.5"
+ android:translateX="0.5" >
+ <path
+ android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
+ android:fillColor="#FFFFFF"/>
+ </group>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml b/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml
deleted file mode 100644
index d755481..0000000
--- a/packages/SystemUI/res/drawable/ic_dnd_disable_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_dnd_disable" >
- <target
- android:name="mask_1"
- android:animation="@anim/ic_dnd_disable_mask_1_animation" />
- <target
- android:name="bar01_0"
- android:animation="@anim/ic_dnd_disable_bar01_0_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml b/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml
deleted file mode 100644
index f796d62..0000000
--- a/packages/SystemUI/res/drawable/ic_dnd_total_silence_disable_animation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_dnd_total_silence_disable" >
- <target
- android:name="mask_1"
- android:animation="@anim/ic_dnd_total_silence_disable_mask_1_animation" />
- <target
- android:name="outer_ring_merged"
- android:animation="@anim/ic_dnd_total_silence_disable_outer_ring_merged_animation" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml b/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml
deleted file mode 100644
index e446a32..0000000
--- a/packages/SystemUI/res/drawable/ic_hotspot_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_hotspot_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_hotspot_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_hotspot_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml b/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml
deleted file mode 100644
index 945e42f..0000000
--- a/packages/SystemUI/res/drawable/ic_hotspot_enable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_hotspot_enable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_hotspot_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_hotspot_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml b/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml
deleted file mode 100644
index aeda0a5..0000000
--- a/packages/SystemUI/res/drawable/ic_invert_colors_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_invert_colors_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_invert_colors_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_invert_colors_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml b/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml
deleted file mode 100644
index 85928ac..0000000
--- a/packages/SystemUI/res/drawable/ic_invert_colors_enable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_invert_colors_enable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_invert_colors_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_invert_colors_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml
deleted file mode 100644
index 56ae4aa..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_airplane_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_airplane_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_airplane_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml
deleted file mode 100644
index 87dfba9..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_enable_animation.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_airplane_enable" >
- <target
- android:name="ic_signal_airplane"
- android:animation="@anim/ic_signal_airplane_enable_animation_ic_signal_airplane" />
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_airplane_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_airplane_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml
deleted file mode 100644
index e228b7c..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_flashlight_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_flashlight_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_flashlight_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml
deleted file mode 100644
index 220c65e..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_flashlight_enable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_flashlight_enable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_flashlight_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_flashlight_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml
deleted file mode 100644
index 0e9d1cb..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_location_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_location_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_location_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_location_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml
deleted file mode 100644
index 9f1d917..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_location_enable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_location_enable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_location_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_location_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
deleted file mode 100644
index 9c23126..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_disable_animation.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_workmode_disable" >
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_workmode_disable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_workmode_disable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
deleted file mode 100644
index 04ddfad..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_enable_animation.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/ic_signal_workmode_enable" >
- <target
- android:name="ic_signal_briefcase"
- android:animation="@anim/ic_signal_workmode_enable_animation_ic_signal_briefcase" />
- <target
- android:name="mask"
- android:animation="@anim/ic_signal_workmode_enable_animation_mask" />
- <target
- android:name="cross_1"
- android:animation="@anim/ic_signal_workmode_enable_animation_cross_1" />
-</animated-vector>
diff --git a/packages/SystemUI/res/drawable/pip_expand.xml b/packages/SystemUI/res/drawable/pip_expand.xml
new file mode 100644
index 0000000..cdb2ee5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_expand.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:pathData="M0 0h36v36H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
+7v3h5v5h3V7h-8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_ll.xml b/packages/SystemUI/res/drawable/pip_expand_ll.xml
deleted file mode 100644
index a8b82b5..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_ll.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#fff"
- android:pathData="M7.5,52h45a5,5,0,0,0,5-5V12.95A5,5,0,0,0,52.5,8H7.5a5,5,0,0,0-5,4.95V47A5,5,0,0,0,7.5,52Zm-1-5V13a1,1,0,0,1,1-1h45a1,1,0,0,1,1,1V47a1,1,0,0,1-1,1H7.5A1,1,0,0,1,6.5,47Z" />
- <path
- android:pathData="M0,0V60H60V0H0Z" />
- <path
- android:fillColor="#fff"
- android:pathData="M35,39.14v2a1,1,0,0,0,1,1H46.5a1,1,0,0,0,1-1V30.64a1,1,0,0,0-1-1h-2a1,1,0,0,0-1,1v7.5H36A1,1,0,0,0,35,39.14Z" />
- <path
- android:fillColor="#fff"
- android:pathData="M13.5,30.36h2a1,1,0,0,0,1-1v-7.5H24a1,1,0,0,0,1-1v-2a1,1,0,0,0-1-1H13.5a1,1,0,0,0-1,1v10.5A1,1,0,0,0,13.5,30.36Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_lr.xml b/packages/SystemUI/res/drawable/pip_expand_lr.xml
deleted file mode 100644
index 44d97ef..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_lr.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M57.5,47V12.95c0-2.75-2.25-4.95-5-4.95h-45c-2.75,0-5,2.2-5,4.95V47c0,2.75,2.25,5,5,5h45
-C55.25,52,57.5,49.75,57.5,47z
-M52.5,48h-45c-0.55,0-1-0.45-1-1V13c0-0.55,0.45-1,1-1h45c0.55,0,1,0.45,1,1v34
-C53.5,47.55,53.05,48,52.5,48z" />
- <path
- android:pathData="M60,0v60H0L0,0L60,0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M25,39.14v2c0,0.55-0.45,1-1,1H13.5c-0.55,0-1-0.45-1-1v-10.5c0-0.55,0.45-1,1-1h2c0.55,0,1,0.45,1,1v7.5
-H24C24.55,38.14,25,38.59,25,39.14z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M46.5,30.36h-2c-0.55,0-1-0.45-1-1v-7.5H36c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h10.5
-c0.55,0,1,0.45,1,1v10.5C47.5,29.91,47.05,30.36,46.5,30.36z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pl.xml b/packages/SystemUI/res/drawable/pip_expand_pl.xml
deleted file mode 100644
index 57b9358..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pl.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M47,2.5H12.95C10.2,2.5,8,4.75,8,7.5v45c0,2.75,2.2,5,4.95,5H47c2.75,0,5-2.25,5-5v-45
-C52,4.75,49.75,2.5,47,2.5z
-M48,7.5v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45c0-0.55,0.45-1,1-1h34
-C47.55,6.5,48,6.95,48,7.5z" />
- <path
- android:pathData="M0,0l60,0v60H0L0,0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M39.14,35h2c0.55,0,1,0.45,1,1v10.5c0,0.55-0.45,1-1,1h-10.5c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h7.5
-V36C38.14,35.45,38.59,35,39.14,35z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M30.36,13.5v2c0,0.55-0.45,1-1,1h-7.5V24c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V13.5c0-0.55,0.45-1,1-1
-h10.5C29.91,12.5,30.36,12.95,30.36,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pr.xml b/packages/SystemUI/res/drawable/pip_expand_pr.xml
deleted file mode 100644
index e34a95d..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pr.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="60dp"
- android:height="60dp"
- android:viewportWidth="60"
- android:viewportHeight="60">
-
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M8,7.5v45c0,2.75,2.25,5,5,5h34.05c2.75,0,4.95-2.25,4.95-5v-45c0-2.75-2.2-5-4.95-5H13
-C10.25,2.5,8,4.75,8,7.5z
-M13,6.5h34c0.55,0,1,0.45,1,1v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45C12,6.95,12.45,6.5,13,6.5z" />
- <path
- android:pathData="M60,0L0,0l0,60h60V0z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M20.86,35h-2c-0.55,0-1,0.45-1,1v10.5c0,0.55,0.45,1,1,1h10.5c0.55,0,1-0.45,1-1v-2c0-0.55-0.45-1-1-1h-7.5
-V36C21.86,35.45,21.41,35,20.86,35z" />
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M29.64,13.5v2c0,0.55,0.45,1,1,1h7.5V24c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1V13.5c0-0.55-0.45-1-1-1
-h-10.5C30.09,12.5,29.64,12.95,29.64,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_disable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_hotspot_disable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc0442f..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_disable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_disable_ic_hotspot_alpha_interpolator.xml b/packages/SystemUI/res/interpolator/ic_hotspot_disable_ic_hotspot_alpha_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_disable_ic_hotspot_alpha_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_1.xml
deleted file mode 100644
index 0cc9c02..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_1.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0 0.833333333,0.833333333 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_2.xml
deleted file mode 100644
index 44c755e..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_disable_mask_pathdata_interpolator_2.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0.166666667 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_hotspot_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc90d28..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_1.xml
deleted file mode 100644
index e361d9c..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_1.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.833333333,0.833333333 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_2.xml
deleted file mode 100644
index 25ba970..0000000
--- a/packages/SystemUI/res/interpolator/ic_hotspot_enable_mask_pathdata_interpolator_2.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0.166666667 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_invert_colors_disable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_invert_colors_disable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc0442f..0000000
--- a/packages/SystemUI/res/interpolator/ic_invert_colors_disable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_invert_colors_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_invert_colors_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc90d28..0000000
--- a/packages/SystemUI/res/interpolator/ic_invert_colors_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_invert_colors_enable_mask_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_invert_colors_enable_mask_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_invert_colors_enable_mask_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_airplane_disable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_airplane_disable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc0442f..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_airplane_disable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index bc90d28..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_mask_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_mask_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_airplane_enable_mask_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_mask_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_mask_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_flashlight_enable_mask_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_location_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_location_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_location_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_location_enable_mask_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_location_enable_mask_pathdata_interpolator.xml
deleted file mode 100644
index f7072f2..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_location_enable_mask_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index 66cfaff..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.166666667,0 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index a0118d70..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
- android:pathData="M 0,0 c 0.8,0 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 6fe00c0..bbd315e 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -71,51 +71,51 @@
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginEnd="@*android:dimen/notification_content_margin_end"
- android:orientation="horizontal">
+ android:orientation="vertical">
<!-- Channel Text -->
<LinearLayout
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical">
+ android:orientation="horizontal">
<!-- Channel Name -->
<TextView
android:id="@+id/channel_name"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_marginBottom="6dp"
style="@style/TextAppearance.NotificationInfo.Primary" />
- <!-- Secondary Text - only one shows at a time -->
- <TextView
- android:id="@+id/channel_disabled"
+ <!-- Ban Channel Switch -->
+ <Switch
+ android:id="@+id/channel_enabled_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationInfo.Secondary.Warning" />
- <TextView
- android:id="@+id/num_channels_desc"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/notification_channel_disabled"
- style="@style/TextAppearance.NotificationInfo.Secondary" />
- <!-- Optional link to app. Only appears if the channel is not disabled -->
- <TextView
- android:id="@+id/app_settings"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:ellipsize="end"
- android:maxLines="1"
- style="@style/TextAppearance.NotificationInfo.Secondary.Link"/>
+ android:layout_gravity="end|center_vertical"
+ android:contentDescription="@string/notification_channel_switch_accessibility"
+ android:background="@null" />
</LinearLayout>
- <!-- Ban Channel Switch -->
- <Switch
- android:id="@+id/channel_enabled_switch"
+ <!-- Secondary Text - only one shows at a time -->
+ <TextView
+ android:id="@+id/channel_disabled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="end|center_vertical"
- android:contentDescription="@string/notification_channel_switch_accessibility"
- android:background="@null" />
+ android:text="@string/notification_channel_disabled"
+ style="@style/TextAppearance.NotificationInfo.Secondary.Warning" />
+ <TextView
+ android:id="@+id/num_channels_desc"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/notification_channel_disabled"
+ style="@style/TextAppearance.NotificationInfo.Secondary" />
+ <!-- Optional link to app. Only appears if the channel is not disabled -->
+ <TextView
+ android:id="@+id/app_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:ellipsize="end"
+ android:maxLines="1"
+ style="@style/TextAppearance.NotificationInfo.Secondary.Link"/>
</LinearLayout>
<!-- Settings and Done buttons -->
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 8c66bab..8b7f692 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -38,6 +38,8 @@
android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="@string/pip_phone_expand"
+ android:padding="10dp"
+ android:src="@drawable/pip_expand"
android:background="?android:selectableItemBackgroundBorderless" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 9a97d60..2e22943 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -40,13 +40,13 @@
android:layout_width="wrap_content"
>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/ethernet"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/ethernet_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -79,13 +79,13 @@
android:layout_width="wrap_content"
>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/wifi_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/wifi_signal_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -120,14 +120,14 @@
android:layout_width="wrap_content"
android:contentDescription="@string/accessibility_no_sims">
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneLightTheme"
+ android:theme="?attr/lightIconTheme"
android:id="@+id/no_sims"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
- android:theme="@style/DualToneDarkTheme"
+ android:theme="?attr/darkIconTheme"
android:id="@+id/no_sims_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 51eefb6..029d16e 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -48,7 +48,6 @@
android:layout_height="match_parent"
android:importantForAccessibility="no"
sysui:ignoreRightInset="true"
- sysui:scrimColor="@color/scrim_behind_color"
/>
<com.android.systemui.statusbar.AlphaOptimizedView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 7a93f8f..bb4f2d8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Af"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Met kragkennisgewingkontroles kan jy \'n belangrikheidvlak van 0 tot 5 vir \'n program se kennisgewings stel. \n\n"<b>"Vlak 5"</b>" \n- Wys aan die bokant van die kennisgewinglys \n- Laat volskermonderbreking toe \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 4"</b>" \n- Verhoed volskermonderbreking \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 3"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n\n"<b>"Vlak 2"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n\n"<b>"Vlak 1"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n- Versteek van sluitskerm en statusbalk \n- Wys aan die onderkant van die kennisgewinglys \n\n"<b>"Vlak 0"</b>" \n- Blokkeer alle kennisgewings van die program af"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Kennisgewings"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Jy sal nie meer hierdie kennisgewings kry nie."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Jy sal nie meer hierdie kennisgewings kry nie"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kennisgewingkategorieë"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Hierdie program het nie kennisgewingkategorieë nie"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-af/strings_tv.xml b/packages/SystemUI/res/values-af/strings_tv.xml
index 3582af1..8a1e6c9 100644
--- a/packages/SystemUI/res/values-af/strings_tv.xml
+++ b/packages/SystemUI/res/values-af/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Beeld-in-beeld"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Titellose program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Maak PIP toe"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Volskerm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index afef464..b037336 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ጠፍቷል"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"በኃይል ማሳወቂያ መቆጣጠሪያዎች አማካኝነት የአንድ መተግበሪያ ማሳወቂያዎች የአስፈላጊነት ደረጃ ከ0 እስከ 5 ድረስ ማዘጋጀት ይችላሉ። \n\n"<b>"ደረጃ 5"</b>" \n- በማሳወቂያ ዝርዝሩ አናት ላይ አሳይ \n- የሙሉ ማያ ገጽ ማቋረጥን ፍቀድ \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 4"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 3"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- በፍጹም አጮልቀው አይምልከቱ \n\n"<b>"ደረጃ 2"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ እና ንዝረትን በፍጹም አይኑር \n\n"<b>"ደረጃ 1"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ ወይም ንዝረትን በፍጹም አያደርጉ \n- ከመቆለፊያ ገጽ እና የሁኔታ አሞሌ ይደብቁ \n- በማሳወቂያ ዝርዝር ግርጌ ላይ አሳይ \n\n"<b>"ደረጃ 0"</b>" \n- ሁሉንም የመተግበሪያው ማሳወቂያዎች ያግዱ"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ማሳወቂያዎች"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"እነዚህን ማሳወቂያዎች ከእንግዲህ አያግኙዋቸውም።"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"እነዚህን ማሳወቂያዎች ከእንግዲህ አያገኟቸውም"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> የማሳወቂያ ምድቦች"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ይህ መተግበሪያ የማሳወቂያ ምድቦች የሉትም"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-am/strings_tv.xml b/packages/SystemUI/res/values-am/strings_tv.xml
index cd32b93..89fd692 100644
--- a/packages/SystemUI/res/values-am/strings_tv.xml
+++ b/packages/SystemUI/res/values-am/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ፎቶ በፎቶ"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ርዕስ የሌለው ፕሮግራም)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIPን ዝጋ"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ሙሉ ማያ ገጽ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c083fd1..17480fe 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -556,7 +556,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"إيقاف"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة التأمين وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"الإشعارات"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"لن تتلقى هذه الإشعارات بعد الآن."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"لن تتلقى هذه الإشعارات بعد الآن."</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> فئة إشعار"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"لا يحتوي هذا التطبيق على فئات إشعار"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ar/strings_tv.xml b/packages/SystemUI/res/values-ar/strings_tv.xml
index dcc673d..fe4d943 100644
--- a/packages/SystemUI/res/values-ar/strings_tv.xml
+++ b/packages/SystemUI/res/values-ar/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"صورة داخل صورة"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ليس هناك عنوان للبرنامج)"</string>
<string name="pip_close" msgid="3480680679023423574">"إغلاق PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ملء الشاشة"</string>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index b0f813f..08c1ce5 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Deaktiv"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Enerji bildiriş nəzarəti ilə, tətbiq bildirişləri üçün əhəmiyyət səviyyəsini 0-dan 5-ə kimi ayarlaya bilərsiniz. \n\n"<b>"Səviyyə 5"</b>" \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n- Tam ekran kəsintisinə icazə verin \n- Hər zaman izləyin \n\n"<b>"Səviyyə 4"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Hər zaman izləyin \n\n"<b>"Level 3"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n\n"<b>"Level 2"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n\n"<b>"Səviyyə 1"</b>" \n- Prevent full screen interruption \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n- Ekran kilidi və ya status panelindən gizlədin \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n\n"<b>"Səviyyə 0"</b>" \n- Bütün bildirişləri tətbiqdən blok edin"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirişlər"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirişlər daha sizə göndərilməyəcək."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Bu bildirişlər daha sizə göndərilməyəcək"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> bildiriş kateqoriyaları"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Bu tətbiqin bildiriş kateqoriyası yoxdur"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-az/strings_tv.xml b/packages/SystemUI/res/values-az/strings_tv.xml
index 5e2f8bb..532c8d6 100644
--- a/packages/SystemUI/res/values-az/strings_tv.xml
+++ b/packages/SystemUI/res/values-az/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Şəkil-içində-Şəkil"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Başlıqsız proqram)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP bağlayın"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Tam ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 7c2cc18..a7e6f6a 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -473,7 +473,7 @@
<string name="hidden_notifications_title" msgid="7139628534207443290">"Brže dobijajte obaveštenja"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Pregledajte ih pre otključavanja"</string>
<string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ne, hvala"</string>
- <string name="hidden_notifications_setup" msgid="41079514801976810">"Podesi"</string>
+ <string name="hidden_notifications_setup" msgid="41079514801976810">"Aktiviraj"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="volume_zen_end_now" msgid="3179845345429841822">"Prekini odmah"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Pomoću naprednih kontrola za obaveštenja možete da podesite nivo važnosti od 0. do 5. za obaveštenja aplikacije. \n\n"<b>"5. nivo"</b>" \n– Prikazuju se u vrhu liste obaveštenja \n- Dozvoli prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"4. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"3. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n\n"<b>"2. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n\n"<b>"1. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n– Sakrij na zaključanom ekranu i statusnoj traci \n– Prikazuju se u dnu liste obaveštenja \n\n"<b>"0. nivo"</b>" \n– Blokiraj sva obaveštenja iz aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obaveštenja"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete da dobijate ova obaveštenja."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Više nećete dobijati ova obaveštenja"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Kategorija obaveštenja: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obaveštenja"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -739,7 +739,7 @@
<string name="lockscreen_unlock_left" msgid="2043092136246951985">"I leva prečica otključava"</string>
<string name="lockscreen_unlock_right" msgid="1529992940510318775">"I desna prečica otključava"</string>
<string name="lockscreen_none" msgid="4783896034844841821">"Ništa"</string>
- <string name="tuner_launch_app" msgid="1527264114781925348">"Pokretanje <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_launch_app" msgid="1527264114781925348">"Pokreni <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="tuner_other_apps" msgid="4726596850501162493">"Druge aplikacije"</string>
<string name="tuner_circle" msgid="2340998864056901350">"Krug"</string>
<string name="tuner_plus" msgid="6792960658533229675">"Plus"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index b41782b..6be4046 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Slika u slici"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program bez naslova)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ceo ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 8c4a617..ce90937 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Выключана"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"З дапамогай пашыранага кіравання апавяшчэннямі вы можаце задаваць узровень важнасці апавяшчэнняў праграмы ад 0 да 5. \n\n"<b>"Узровень 5"</b>" \n- Паказваць уверсе спіса апавяшчэнняў \n- Дазваляць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 4"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 3"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n\n"<b>"Узровень 2"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n\n"<b>"Узровень 1"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n- Хаваць з экрана блакіроўкі і панэлі стану \n- Паказваць унізе спіса апавяшчэнняў \n\n"<b>"Узровень 0"</b>" \n- Блакіраваць усе апавяшчэнні ад праграмы"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Апавяшчэнні"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больш не будзеце атрымліваць гэтыя апавяшчэнні."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Вы больш не будзеце атрымліваць гэтыя апавяшчэнні"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Катэгорый апавяшчэнняў: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"У гэтай праграме няма катэгорый апавяшчэнняў"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-be/strings_tv.xml b/packages/SystemUI/res/values-be/strings_tv.xml
index a339d32..b9761b7 100644
--- a/packages/SystemUI/res/values-be/strings_tv.xml
+++ b/packages/SystemUI/res/values-be/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Відарыс у відарысе"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Праграма без назвы)"</string>
<string name="pip_close" msgid="3480680679023423574">"Закрыць PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ва ўвесь экран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d818f28..b1f1ae9 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Изкл."</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"С помощта на контролите за известията можете да зададете ниво на важност от 0 до 5 за известията от дадено приложение. \n\n"<b>"Ниво 5"</b>" \n– Показване най-горе в списъка с известия. \n– Разрешаване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 4"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 3"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n\n"<b>"Ниво 2"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n\n"<b>"Ниво 1"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n– Скриване от заключения екран и лентата на състоянието. \n– Показване най-долу в списъка с известия. \n\n"<b>"Ниво 0"</b>" \n– Блокиране на всички известия от приложението."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Известия"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Вече няма да получавате тези известия."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Вече няма да получавате тези известия"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> категории известия"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"За това приложение няма категории на известията"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-bg/strings_tv.xml b/packages/SystemUI/res/values-bg/strings_tv.xml
index 40521bc..ffe9007 100644
--- a/packages/SystemUI/res/values-bg/strings_tv.xml
+++ b/packages/SystemUI/res/values-bg/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Картина в картина"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Програма без заглавие)"</string>
<string name="pip_close" msgid="3480680679023423574">"Затваряне на PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Цял екран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 8180453..7392d04 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"বন্ধ আছে"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"পাওয়ার বিজ্ঞপ্তির নিয়ন্ত্রণগুলি ব্যহবার করে, আপনি কোনো অ্যাপ্লিকেশানের বিজ্ঞপ্তির জন্য ০ থেকে ৫ পর্যন্ত একটি গুরুত্বের লেভেলকে সেট করতে পারবেন৷ \n\n"<b>"লেভেল ৫"</b>" \n- বিজ্ঞপ্তি তালিকার শীর্ষে দেখায় \n- পূর্ণ স্ক্রীনের বাধাকে অনুমতি দেয় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৪"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৩"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n\n"<b>"লেভেল ২"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n\n"<b>"লেভেল ১"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n- লক স্ক্রীন এবং স্থিতি দন্ড থেকে লুকায় \n- বিজ্ঞপ্তি তালিকার নীচের দিকে দেখায় \n\n"<b>"লেভেল ০"</b>" \n- অ্যাপ্লিকেশান থেকে সমস্ত বিজ্ঞপ্তিকে অবরূদ্ধ করে"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"বিজ্ঞপ্তি"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"আপনি আর এই বিজ্ঞপ্তিগুলি পাবেন না।"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"আপনি এই বিজ্ঞপ্তিগুলি আর পাবেন না"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> বিজ্ঞপ্তির বিভাগগুলি"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"এই অ্যাপটিতে বিজ্ঞপ্তির বিভাগ নেই"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-bn/strings_tv.xml b/packages/SystemUI/res/values-bn/strings_tv.xml
index 9c6d5bc..ed95ac4 100644
--- a/packages/SystemUI/res/values-bn/strings_tv.xml
+++ b/packages/SystemUI/res/values-bn/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ছবির-মধ্যে-ছবি"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(শিরোনামহীন প্রোগ্রাম)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP বন্ধ করুন"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"পূর্ণ স্ক্রীন"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4905db1..563d81b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -552,7 +552,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Uz kontrolu obavještenja o napajanju, možete postaviti nivo značaja obavještenja iz aplikacije, i to od nivoa 0 do 5. \n\n"<b>"Nivo 5"</b>" \n- Prikaži na vrhu liste obavještenja \n- Dopusti prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nvio 4"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nivo 3"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n\n"<b>"Nivo 2"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n\n"<b>"Nivo 1"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikada ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n- Sakrij sa ekrana za zaključavanje i statusne trake \n- Prikaži na dnu liste obavještenja \n\n"<b>"Nivo 0"</b>" \n- Blokiraj sva obavještenja iz aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obavještenja"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Nećete više primati ova obavještenja."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Nećete više primati ova obavještenja"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Kategorije obavještenja: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obavještenja"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-bs/strings_tv.xml b/packages/SystemUI/res/values-bs/strings_tv.xml
index 932b9ce..b0b3612 100644
--- a/packages/SystemUI/res/values-bs/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Slika u slici"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program bez naslova)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Cijeli ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index e5696f9..5858bb8 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -206,12 +206,12 @@
<string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"S\'ha desactivat el mode No molestis."</string>
<string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"S\'ha activat el mode No molestis."</string>
<string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
- <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"El Bluetooth està desactivat."</string>
- <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"El Bluetooth està activat."</string>
+ <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth desactivat."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth activat."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"S\'està connectant el Bluetooth."</string>
- <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"El Bluetooth està connectat."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"El Bluetooth està desactivat."</string>
- <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"El Bluetooth està activat."</string>
+ <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"Bluetooth connectat."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"Bluetooth desactivat."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"Bluetooth activat."</string>
<string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Informes d\'ubicació desactivats"</string>
<string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Informes d\'ubicació activats"</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Els informes d\'ubicació estan desactivats."</string>
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivat"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Amb els controls de notificació millorats, pots establir un nivell d\'importància d\'entre 0 i 5 per a les notificacions d\'una aplicació. \n\n"<b>"Nivell 5"</b>" \n- Mostra les notificacions a la part superior de la llista \n- Permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 4"</b>" \n- No permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 3"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n\n"<b>"Nivell 2"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- Les notificacions no poden emetre sons ni vibracions \n\n"<b>"Nivell 1"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- No activa mai el so ni la vibració \n- Amaga les notificacions de la pantalla de bloqueig i de la barra d\'estat \n- Mostra les notificacions a la part inferior de la llista \n\n"<b>"Nivell 0"</b>" \n- Bloqueja totes les notificacions de l\'aplicació"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacions"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ja no rebràs aquestes notificacions."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ja no rebràs aquestes notificacions"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categories de notificació"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Aquesta aplicació no té categories de notificació"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ca/strings_tv.xml b/packages/SystemUI/res/values-ca/strings_tv.xml
index 9bfbb69..6e9fae5 100644
--- a/packages/SystemUI/res/values-ca/strings_tv.xml
+++ b/packages/SystemUI/res/values-ca/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imatge en imatge"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa sense títol)"</string>
<string name="pip_close" msgid="3480680679023423574">"Tanca PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 83138b4..1101217 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuto"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt z obrazovky uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Oznámení"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Tato oznámení již nebudete dostávat."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Tato oznámení již nebudete dostávat"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Kategorie oznámení: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Tato aplikace nemá kategorie oznámení"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index 77806de..f27974f 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Obraz v obraze"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Bez názvu)"</string>
<string name="pip_close" msgid="3480680679023423574">"Ukončit PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Celá obrazovka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 5a859de..3a0a083 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Du modtager ikke længere disse underretninger."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Du modtager ikke længere disse underretninger"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> underretningskategorier"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Denne app har ingen underretningskategorier"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-da/strings_tv.xml b/packages/SystemUI/res/values-da/strings_tv.xml
index 4fe671b..d24cb3a 100644
--- a/packages/SystemUI/res/values-da/strings_tv.xml
+++ b/packages/SystemUI/res/values-da/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Integreret billede"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program uden titel)"</string>
<string name="pip_close" msgid="3480680679023423574">"Luk PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Fuld skærm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index d9af495..55480fb 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Aus"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Mit den erweiterten Benachrichtigungseinstellungen kannst du für App-Benachrichtigungen eine Wichtigkeitsstufe von 0 bis 5 festlegen. \n\n"<b>"Stufe 5"</b>" \n- Auf der Benachrichtigungsleiste ganz oben anzeigen \n- Vollbildunterbrechung zulassen \n- Immer kurz einblenden \n\n"<b>"Stufe 4"</b>" \n- Keine Vollbildunterbrechung \n- Immer kurz einblenden \n\n"<b>"Stufe 3"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n\n"<b>"Stufe 2"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n\n"<b>"Stufe 1"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n- Auf Sperrbildschirm und Statusleiste verbergen \n- Auf der Benachrichtigungsleiste ganz unten anzeigen \n\n"<b>"Stufe 0"</b>" \n- Alle Benachrichtigungen der App sperren"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Benachrichtigungen"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Du erhältst diese Benachrichtigungen nicht mehr."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Du erhältst diese Benachrichtigungen nicht mehr"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> Benachrichtigungskategorien"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Diese App hat keine Benachrichtigungskategorien"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-de/strings_tv.xml b/packages/SystemUI/res/values-de/strings_tv.xml
index 733ed12..c83a52e 100644
--- a/packages/SystemUI/res/values-de/strings_tv.xml
+++ b/packages/SystemUI/res/values-de/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Bild-in-Bild"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Kein Programmtitel)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP schließen"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Vollbild"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 80f6065..53d29fe 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Ανενεργή"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Με τα στοιχεία ελέγχου ειδοποίησης ισχύος, μπορείτε να ορίσετε ένα επίπεδο βαρύτητας από 0 έως 5 για τις ειδοποιήσεις μιας εφαρμογής. \n\n"<b>"Επίπεδο 5"</b>" \n- Εμφάνιση στην κορυφή της λίστας ειδοποιήσεων \n- Να επιτρέπεται η διακοπή πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 4"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 3"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n\n"<b>"Επίπεδο 2"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n\n"<b>"Επίπεδο 1"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n- Απόκρυψη από την οθόνη κλειδώματος και τη γραμμή κατάστασης \n- Εμφάνιση στο κάτω μέρος της λίστας ειδοποιήσεων \n\n"<b>"Επίπεδο 0"</b>" \n- Αποκλεισμός όλων των ειδοποιήσεων από την εφαρμογή"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ειδοποιήσεις"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Δεν θα λαμβάνεται πλέον αυτές τις ειδοποιήσεις."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Δεν θα λαμβάνετε πλέον αυτές τις ειδοποιήσεις"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> κατηγορίες ειδοποιήσεων"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Αυτή η εφαρμογή δεν διαθέτει κατηγορίες ειδοποιήσεων"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-el/strings_tv.xml b/packages/SystemUI/res/values-el/strings_tv.xml
index 7d92748..4e613ce 100644
--- a/packages/SystemUI/res/values-el/strings_tv.xml
+++ b/packages/SystemUI/res/values-el/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Λειτουργία Picture-in-picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Δεν υπάρχει τίτλος προγράμματος)"</string>
<string name="pip_close" msgid="3480680679023423574">"Κλείσιμο PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Πλήρης οθόνη"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 056a1e0..874bc67 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"You won\'t get these notifications anymore."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"You won\'t get these notifications anymore"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> notification categories"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"This app doesn\'t have notification categories"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-en-rAU/strings_tv.xml b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
index 16fdfe1..ffcd655 100644
--- a/packages/SystemUI/res/values-en-rAU/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 056a1e0..874bc67 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"You won\'t get these notifications anymore."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"You won\'t get these notifications anymore"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> notification categories"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"This app doesn\'t have notification categories"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-en-rGB/strings_tv.xml b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
index 16fdfe1..ffcd655 100644
--- a/packages/SystemUI/res/values-en-rGB/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 056a1e0..874bc67 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. \n\n"<b>"Level 5"</b>" \n- Show at the top of the notification list \n- Allow full screen interruption \n- Always peek \n\n"<b>"Level 4"</b>" \n- Prevent full screen interruption \n- Always peek \n\n"<b>"Level 3"</b>" \n- Prevent full screen interruption \n- Never peek \n\n"<b>"Level 2"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound and vibration \n\n"<b>"Level 1"</b>" \n- Prevent full screen interruption \n- Never peek \n- Never make sound or vibrate \n- Hide from lock screen and status bar \n- Show at the bottom of the notification list \n\n"<b>"Level 0"</b>" \n- Block all notifications from the app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"You won\'t get these notifications anymore."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"You won\'t get these notifications anymore"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> notification categories"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"This app doesn\'t have notification categories"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-en-rIN/strings_tv.xml b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
index 16fdfe1..ffcd655 100644
--- a/packages/SystemUI/res/values-en-rIN/strings_tv.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(No title program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Close PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 3a69668..b690df1 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Con los controles de activación de notificaciones, puedes establecer un nivel de importancia para las notificaciones de una app. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones. \n- Permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 4"</b>" \n- No permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 3"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n\n"<b>"Nivel 2"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n\n"<b>"Nivel 1"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n- Ocultar de la pantalla bloqueada y la barra de estado. \n- Mostrar al final de la lista de notificaciones. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la app."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ya no recibirás estas notificaciones"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificaciones"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta app no tiene categorías de notificación"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-es-rUS/strings_tv.xml b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
index 04552a7..aabf59d 100644
--- a/packages/SystemUI/res/values-es-rUS/strings_tv.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imagen en imagen"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Sin título de programa)"</string>
<string name="pip_close" msgid="3480680679023423574">"Cerrar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 999d625..2a98dcc 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Los controles de energía de las notificaciones permiten establecer un nivel de importancia de 0 a 5 para las notificaciones de las aplicaciones. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones \n- Permitir interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 4"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 3"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n\n"<b>"Nivel 2"</b>" \n- Evitar interrumpir en el modo de pantalla completa\n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n\n"<b>"Nivel 1"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n- Ocultar de la pantalla de bloqueo y de la barra de estado \n- Mostrar en la parte inferior de la lista de notificaciones \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la aplicación"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ya no recibirás estas notificaciones"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificación"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicación no tiene categorías de notificación"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-es/strings_tv.xml b/packages/SystemUI/res/values-es/strings_tv.xml
index 04552a7..add06a7 100644
--- a/packages/SystemUI/res/values-es/strings_tv.xml
+++ b/packages/SystemUI/res/values-es/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imagen en imagen"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa sin título)"</string>
<string name="pip_close" msgid="3480680679023423574">"Cerrar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 05085fa..72c382a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Väljas"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Toite märguannete juhtnuppudega saate määrata rakenduse märguannete tähtsuse taseme vahemikus 0–5. \n\n"<b>"5. tase"</b>" \n- Kuva märguannete loendi ülaosas\n- Luba täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"4. tase"</b>" \n- Keela täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"3. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n\n"<b>"2. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n\n"<b>"1. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n- Peida lukustuskuval ja olekuribal \n- Kuva märguannete loendi allosas \n\n"<b>"Tase 0"</b>" \n- Blokeeri kõik rakenduse märguanded"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Märguanded"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Te ei saa enam neid märguandeid."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Te ei saa enam neid märguandeid"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> märguandekategooriat"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Sellel rakendusel ei ole märguannete kategooriaid"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-et/strings_tv.xml b/packages/SystemUI/res/values-et/strings_tv.xml
index c05ccd6..bfd3884 100644
--- a/packages/SystemUI/res/values-et/strings_tv.xml
+++ b/packages/SystemUI/res/values-et/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Pilt pildis"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programmi pealkiri puudub)"</string>
<string name="pip_close" msgid="3480680679023423574">"Sule PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Täisekraan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 6aadacb..42386e2 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desaktibatuta"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Bateria-mailaren arabera jakinarazpenak kontrolatzeko aukerekin, 0 eta 5 bitarteko garrantzi-mailetan sailka ditzakezu aplikazioen jakinarazpenak. \n\n"<b>"5. maila"</b>" \n- Erakutsi jakinarazpenen zerrendaren goialdean. \n- Baimendu etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"4. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"3. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n\n"<b>"2. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n\n"<b>"1. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n- Ezkutatu pantaila blokeatutik eta egoera-barratik. \n- Erakutsi jakinarazpenen zerrendaren behealdean. \n\n"<b>"0. maila"</b>" \n- Blokeatu aplikazioaren jakinarazpen guztiak."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Jakinarazpenak"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Aurrerantzean ez duzu jasoko horrelako jakinarazpenik."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Aurrerantzean ez duzu jasoko horrelako jakinarazpenik"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Jakinarazpenen <xliff:g id="NUMBER">%d</xliff:g> kategoria"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Aplikazio honek ez du jakinarazpen-kategoriarik"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-eu/strings_tv.xml b/packages/SystemUI/res/values-eu/strings_tv.xml
index e145f09..6dd81a6 100644
--- a/packages/SystemUI/res/values-eu/strings_tv.xml
+++ b/packages/SystemUI/res/values-eu/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Pantaila txikia"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa izengabea)"</string>
<string name="pip_close" msgid="3480680679023423574">"Itxi PIPa"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantaila osoa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 63050ae..7197617 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"خاموش"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"با کنترلهای قدرتمند اعلان میتوانید سطح اهمیت اعلانهای هر برنامه را از ۰ تا ۵ تعیین کنید. \n\n"<b>"سطح ۵"</b>" \n- در صدر فهرست اعلانها نشان داده میشود \n- وقفه برای نمایش تمامصفحه مجاز است \n- همیشه اجمالی نشان داده میشود \n\n"<b>"سطح ۴"</b>" \n- وقفه برای نمایش تمامصفحه مجاز نیست \n- همیشه اجمالی نشان داده میشود \n\n"<b>"سطح ۳"</b>" \n- وقفه برای نمایش تمامصفحه مجاز نیست \n- هیچوقت اجمالی نشان داده نمیشود \n\n"<b>"سطح ۲"</b>" \n- وقفه برای نمایش تمامصفحه مجاز نیست \n- هیچوقت اجمالی نشان داده نمیشود \n- هیچوقت صدا و لرزش ایجاد نمیکند \n\n"<b>"سطح ۱"</b>" \n- نمایش تمام صفحه مجاز نیست \n- هیچوقت اجمالی نشان داده نمیشود \n- هیچوقت صدا یا لرزش ایجاد نمیکند \n- در قفل صفحه و نوار وضعیت پنهان است \n- در پایین فهرست اعلانها نشان داده میشود \n\n"<b>"سطح ۰"</b>" \n- همه اعلانهای این برنامه مسدود است"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"اعلانها"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"دیگر این اعلانها را دریافت نخواهید کرد."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"دیگر این اعلانها را دریافت نخواهید کرد"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> دسته اعلان"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"این برنامه دسته اعلان ندارد"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-fa/strings_tv.xml b/packages/SystemUI/res/values-fa/strings_tv.xml
index 9507a6f..e34fccb2 100644
--- a/packages/SystemUI/res/values-fa/strings_tv.xml
+++ b/packages/SystemUI/res/values-fa/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"تصویر در تصویر"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(برنامه بدون عنوان)"</string>
<string name="pip_close" msgid="3480680679023423574">"بستن PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"تمام صفحه"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index ec6a6d9..67bda58 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Pois käytöstä"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ilmoitusten tehohallinnan avulla voit määrittää sovelluksen ilmoituksille tärkeystason väliltä 0–5. \n\n"<b>"Taso 5"</b>" \n– Ilmoitukset näytetään ilmoitusluettelon yläosassa \n– Näkyminen koko näytön tilassa sallitaan \n– Ilmoitukset kurkistavat aina näytölle\n\n"<b>"Taso 4"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ilmoitukset kurkistavat aina näytölle \n\n"<b>"Taso 3"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n\n"<b>"Taso 2"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n\n"<b>"Taso 1"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n– Ilmoitukset piilotetaan lukitusnäytöltä ja tilapalkista \n– Ilmoitukset näytetään ilmoitusluettelon alaosassa \n\n"<b>"Taso 0"</b>" \n– Kaikki sovelluksen ilmoitukset estetään"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ilmoitukset"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Et saa näitä ilmoituksia enää."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Et saa näitä ilmoituksia enää."</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ilmoitusluokkaa"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Tällä sovelluksella ei ole ilmoitusluokkia."</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index 1d91f6f..0ee98b2 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Kuva kuvassa"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Nimetön)"</string>
<string name="pip_close" msgid="3480680679023423574">"Sulje PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Koko näyttö"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 77a545e..caf219b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Désactivé"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Avec les réglages avancés des notifications, vous pouvez définir un degré d\'importance de 0 à 5 pour les notifications d\'une application. \n\n"<b>"Niveau 5"</b>" \n- Afficher dans le haut de la liste des notifications \n- Autoriser les interruptions en mode plein écran \n- Toujours afficher les aperçus \n\n"<b>"Niveau 4"</b>" \n- Empêcher les interruptions en mode plein écran \n- Toujours afficher les aperçus \n\n"<b>"Niveau 3"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n\n"<b>"Niveau 2"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n- Ne pas autoriser les sons et les vibrations \n\n"<b>"Niveau 1"</b>" \n- Empêcher les interruptions en mode plein écran \n- Ne jamais afficher les aperçus \n- Ne pas autoriser les sons et les vibrations \n- Masquer de l\'écran de verrouillage et de la barre d\'état status bar \n- Afficher dans le bas de la liste des notifications \n\n"<b>"Level 0"</b>" \n- Bloquer toutes les notifications de l\'application"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Vous ne recevrez plus ces notifications."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Vous ne recevrez plus ces notifications"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> catégories de notification"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Cette application n\'a pas de catégories de notification"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
index ec27fd0..f8769b8 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Incrustation d\'image"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Aucun programme de titre)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fermer mode IDI"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Plein écran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3b3ef48..8fff5ad 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Désactivé"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Grâce aux commandes de gestion des notifications, vous pouvez définir le niveau d\'importance (compris entre 0 et 5) des notifications d\'une application. \n\n"<b>"Niveau 5"</b>" \n- Afficher en haut de la liste des notifications \n- Autoriser l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 4"</b>" \n- Empêcher l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 3"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n\n"<b>"Niveau 2"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n\n"<b>"Niveau 1"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n- Masquer les notifications dans l\'écran de verrouillage et la barre d\'état \n- Afficher au bas de la liste des notifications \n\n"<b>"Niveau 0"</b>" \n- Bloquer toutes les notifications de l\'application"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Vous ne recevrez plus ces notifications."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Vous ne recevrez plus ces notifications"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> catégories de notification"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Cette application n\'a pas de catégories de notification"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-fr/strings_tv.xml b/packages/SystemUI/res/values-fr/strings_tv.xml
index 0fd0dff..3c0ad7a 100644
--- a/packages/SystemUI/res/values-fr/strings_tv.xml
+++ b/packages/SystemUI/res/values-fr/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programme sans titre)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fermer mode PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Plein écran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 05d41f0..2abd5ec 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivar"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Cos controis de notificacións mellorados, podes asignarlles un nivel de importancia comprendido entre 0 e 5 ás notificacións dunha aplicación determinada. \n\n"<b>"Nivel 5"</b>" \n- Mostrar na parte superior da lista de notificacións. \n- Permitir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 4"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 3"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n\n"<b>"Nivel 2"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n\n"<b>"Nivel 1"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n- Ocultar na pantalla de bloqueo e na barra de estado. \n- Mostrar na parte inferior da lista de notificacións. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas as notificacións da aplicación."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacións"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Deixarás de recibir estas notificacións."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Deixarás de recibir estas notificacións"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorías de notificacións"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicación non ten categorías de notificacións"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-gl/strings_tv.xml b/packages/SystemUI/res/values-gl/strings_tv.xml
index 9ca6759..c7f0ce1 100644
--- a/packages/SystemUI/res/values-gl/strings_tv.xml
+++ b/packages/SystemUI/res/values-gl/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imaxe superposta"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa sen título)"</string>
<string name="pip_close" msgid="3480680679023423574">"Pechar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pantalla completa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d0131e2..ede86c4 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"બંધ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"પાવર સૂચના નિયંત્રણો સાથે, તમે ઍપ્લિકેશનની સૂચનાઓ માટે 0 થી 5 સુધીના મહત્વના સ્તરને સેટ કરી શકો છો. \n\n"<b>"સ્તર 5"</b>" \n- સૂચના સૂચિની ટોચ પર બતાવો \n- પૂર્ણ સ્ક્રીન અવરોધની મંજૂરી આપો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 4"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 3"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n\n"<b>"સ્તર 2"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અને વાઇબ્રેશન કરશો નહીં \n\n"<b>"સ્તર 1"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અથવા વાઇબ્રેટ કરશો નહીં \n- લૉક સ્ક્રીન અને સ્થિતિ બારથી છુપાવો \n- સૂચના સૂચિના તળિયા પર બતાવો \n\n"<b>"સ્તર 0"</b>" \n- ઍપ્લિકેશનની તમામ સૂચનાઓને અવરોધિત કરો"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"સૂચનાઓ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"તમને હવે આ સૂચનાઓ મળશે નહીં."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"તમને હવે આ સૂચનાઓ મળશે નહીં"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> સૂચના કૅટેગરીઓ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"આ ઍપ્લિકેશનમાં સૂચના કૅટેગરી નથી"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-gu/strings_tv.xml b/packages/SystemUI/res/values-gu/strings_tv.xml
index e53c524..5b98fb9 100644
--- a/packages/SystemUI/res/values-gu/strings_tv.xml
+++ b/packages/SystemUI/res/values-gu/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ચિત્રમાં-ચિત્ર"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(કોઈ ટાઇટલ પ્રોગ્રામ નથી)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP બંધ કરો"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"પૂર્ણ સ્ક્રીન"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f2baa04..3ccd7b2 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"पावर नोटिफ़िकेशन नियंत्रण के द्वारा, आप किसी ऐप्लिकेशन के नोटिफ़िकेशन के लिए 0 से 5 तक महत्व का लेवल सेट कर सकते हैं. \n\n"<b>"लेवल 5"</b>" \n- नोटिफ़िकेशन सूची के शीर्ष पर दिखाएं \n- पूर्ण स्क्रीन बाधा की अनुमति दें \n- हमेशा तांक-झांक करें \n\n"<b>"लेवल 4"</b>" \n- पूर्ण स्क्रीन बाधा को रोकें \n- हमेशा तांक-झांक करें \n\n"<b>"लेवल 3"</b>" \n- पूर्ण स्क्रीन बाधा को रोकें \n- कभी भी तांक-झांक ना करें \n\n"<b>"लेवल 2"</b>" \n- पूर्ण स्क्रीन बाधा को रोकें \n- कभी भी तांक-झांक ना करें \n- कभी भी ध्वनि या कंपन ना करें \n\n"<b>"लेवल 1"</b>" \n- पूर्ण स्क्रीन बाधा को रोकें \n- कभी भी तांक-झांक ना करें \n- कभी भी ध्वनि या कंपन ना करें \n- लॉक स्क्रीन और स्थिति बार से छिपाएं \n- नोटिफ़िकेशन सूची के नीचे दिखाएं \n\n"<b>"लेवल 0"</b>" \n- ऐप्लिकेशन के सभी नोटिफ़िकेशन अवरुद्ध कर दें"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"नोटिफ़िकेशन"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"अब आपको ये नोटिफ़िकेशन नहीं मिलेंगे."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"अब आपको ये नोटिफ़िकेशन नहीं मिलेंगे"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"नोटिफ़िकेशन की <xliff:g id="NUMBER">%d</xliff:g> श्रेणियां"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"इस ऐप्लिकेशन में नोटिफ़िकेशन श्रेणियां नहीं हैं"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-hi/strings_tv.xml b/packages/SystemUI/res/values-hi/strings_tv.xml
index 6c90d66..39f06f6 100644
--- a/packages/SystemUI/res/values-hi/strings_tv.xml
+++ b/packages/SystemUI/res/values-hi/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"चित्र में चित्र"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(कोई शीर्षक कार्यक्रम नहीं)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP बंद करें"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रीन"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2b6bceb..373a1ad 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Napredne kontrole obavijesti omogućuju vam da postavite razinu važnosti za obavijesti aplikacije od 0 do 5. \n\n"<b>"Razina 5"</b>" \n– prikaži na vrhu popisa obavijesti \n– dopusti prekide prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 4"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 3"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled\n\n"<b>"Razina 2"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n\n"<b>"Razina 1"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n– ne prikazuj na zaključanom zaslonu i traci statusa \n– prikaži na dnu popisa obavijesti \n\n"<b>"Razina 0"</b>" \n– blokiraj sve obavijesti aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obavijesti"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete primati te obavijesti."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Više nećete primati te obavijesti"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Broj kategorija obavijesti: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ova aplikacija nema kategorije obavijesti"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-hr/strings_tv.xml b/packages/SystemUI/res/values-hr/strings_tv.xml
index 37854bd..7cbaa26 100644
--- a/packages/SystemUI/res/values-hr/strings_tv.xml
+++ b/packages/SystemUI/res/values-hr/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Slika u slici"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program bez naslova)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Cijeli zaslon"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index dd231b7..7710ad8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kikapcsolva"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Az értesítési beállítások révén 0-tól 5-ig állíthatja be a fontossági szintet az alkalmazás értesítéseinél. \n\n"<b>"5. szint"</b>" \n– Megjelenítés az értesítési lista tetején \n– Teljes képernyő megszakításának engedélyezése \n– Mindig felugrik \n\n"<b>"4. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Mindig felugrik \n\n"<b>"3. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n\n"<b>"2. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés és rezgés \n\n"<b>"1. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés vagy rezgés \n– Elrejtés a lezárási képernyőről és az állapotsávról \n– Megjelenítés az értesítési lista alján \n\n"<b>"0. szint"</b>" \n– Az alkalmazás összes értesítésének letiltása"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Értesítések"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Többé nem jelennek meg ezek az értesítések."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Többé nem jelennek meg ezek az értesítések"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> értesítéskategória"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Az alkalmazás nem rendelkezik értesítési kategóriákkal"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index f2f4893..2fd5ded 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Kép a képben"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Cím nélküli program)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP bezárása"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Teljes képernyő"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 0ef1fcf..d3cd0639 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Անջատել"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n"<b>"5-րդ աստիճան"</b>" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"4-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"3-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n"<b>"2-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n"<b>"1-ին աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n"<b>"0-րդ աստիճան"</b>\n"- Արգելափակել հավելվածի բոլոր ծանուցումները"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Ծանուցումներ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Այս ծանուցումներն այլևս չեք ստանա։"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Այս ծանուցումներն այլևս չեք ստանա"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ծանուցման կատեգորիաներ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Այս հավելվածը ծանուցման կատեգորիաներ չունի"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-hy/strings_tv.xml b/packages/SystemUI/res/values-hy/strings_tv.xml
index 6274cd3..ac7711b 100644
--- a/packages/SystemUI/res/values-hy/strings_tv.xml
+++ b/packages/SystemUI/res/values-hy/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Նկարը նկարի մեջ"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Առանց վերնագրի ծրագիր)"</string>
<string name="pip_close" msgid="3480680679023423574">"Փակել PIP-ն"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Լիէկրան"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f7e3054..6269a8b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Nonaktif"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Dengan kontrol notifikasi daya, Anda dapt menyetel level kepentingan notifikasi aplikasi dari 0 sampai 5. \n\n"<b>"Level 5"</b>" \n- Muncul di atas daftar notifikasi \n- Izinkan interupsi layar penuh \n- Selalu intip pesan \n\n"<b>"Level 4"</b>" \n- Jangan interupsi layar penuh \n- Selalu intip pesan \n\n"<b>"Level 3"</b>" \n- Jangan interupsi layar penuh \n- Tak pernah intip pesan \n\n"<b>"Level 2"</b>" \n- Jangan interupsi layar penuh \n- Tak pernah intip pesan \n- Tanpa suara dan getaran \n\n"<b>"Level 1"</b>" \n- Jangan interupsi layar penuh \n- Tak pernah intip pesan \n- Tanpa suara atau getaran \n- Sembunyikan dari layar kunci dan bilah status \n- Muncul di bawah daftar notifikasi \n\n"<b>"Level 0"</b>" \n- Blokir semua notifikasi dari aplikasi"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifikasi"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Anda tidak akan mendapatkan notifikasi ini lagi."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Anda tidak akan mendapatkan notifikasi ini lagi"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kategori notifikasi"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Aplikasi ini tidak memiliki kategori notifikasi"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -644,7 +644,7 @@
<item msgid="1545641631806817203">"Papan klip"</item>
<item msgid="5742013440802239414">"Kode tombol"</item>
<item msgid="8802889973626281575">"Pengalih keyboard"</item>
- <item msgid="8175437057325747277">"Tidak Ada"</item>
+ <item msgid="8175437057325747277">"Tidak ada"</item>
</string-array>
<string-array name="nav_bar_layouts">
<item msgid="8077901629964902399">"Biasa"</item>
@@ -734,7 +734,7 @@
<string name="lockscreen_shortcut_right" msgid="3328683699505226536">"Pintasan kanan"</string>
<string name="lockscreen_unlock_left" msgid="2043092136246951985">"Pintasan kiri juga membuka kunci"</string>
<string name="lockscreen_unlock_right" msgid="1529992940510318775">"Pintasan kanan juga membuka kunci"</string>
- <string name="lockscreen_none" msgid="4783896034844841821">"Tidak Ada"</string>
+ <string name="lockscreen_none" msgid="4783896034844841821">"Tidak ada"</string>
<string name="tuner_launch_app" msgid="1527264114781925348">"Luncurkan <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="tuner_other_apps" msgid="4726596850501162493">"Aplikasi lainnya"</string>
<string name="tuner_circle" msgid="2340998864056901350">"Lingkaran"</string>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index eacaeb6..ca3b32f 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Gambar-dalam-Gambar"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program tanpa judul)"</string>
<string name="pip_close" msgid="3480680679023423574">"Tutup PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Layar penuh"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0dd6d12..94366bc 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Slökkt"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Með orkutilkynningastýringum geturðu stillt mikilvægi frá 0 upp í 5 fyrir tilkynningar forrita. \n\n"<b>"Stig 5"</b>" \n- Sýna efst á tilkynningalista \n- Leyfa truflun þegar birt er á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 4"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 3"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n\n"<b>"Stig 2"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n\n"<b>"Stig 1"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n- Fela á lásskjá og stöðustiku \n- Sýna neðst á tilkynningalista \n\n"<b>"Stig 0"</b>" \n- Setja allar tilkynningar frá forriti á bannlista"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Tilkynningar"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Þú færð þessar tilkynningar ekki framar."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Þú færð þessar tilkynningar ekki framar"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> tilkynningaflokkar"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Þetta forrit er ekki með tilkynningaflokka"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-is/strings_tv.xml b/packages/SystemUI/res/values-is/strings_tv.xml
index de001e0..2727548 100644
--- a/packages/SystemUI/res/values-is/strings_tv.xml
+++ b/packages/SystemUI/res/values-is/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Mynd í mynd"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Efni án titils)"</string>
<string name="pip_close" msgid="3480680679023423574">"Loka mynd í mynd"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Allur skjárinn"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6d53bd0..4d0e205 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"I controlli di gestione delle notifiche ti consentono di impostare un livello di importanza compreso tra 0 e 5 per le notifiche di un\'app. \n\n"<b>"Livello 5"</b>" \n- Mostra in cima all\'elenco di notifiche \n- Consenti l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 4"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 3"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n\n"<b>"Livello 2"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n\n"<b>"Livello 1"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n- Nascondi da schermata di blocco e barra di stato \n- Mostra in fondo all\'elenco di notifiche \n\n"<b>"Livello 0"</b>" \n- Blocca tutte le notifiche dell\'app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notifiche"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Non riceverai più queste notifiche."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Non riceverai più queste notifiche"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorie di notifica"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Questa app non ha categorie di notifica"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-it/strings_tv.xml b/packages/SystemUI/res/values-it/strings_tv.xml
index 66b74e4..629e306 100644
--- a/packages/SystemUI/res/values-it/strings_tv.xml
+++ b/packages/SystemUI/res/values-it/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programma senza titolo)"</string>
<string name="pip_close" msgid="3480680679023423574">"Chiudi PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Schermo intero"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f009a14..d0170908 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -552,7 +552,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"כבוי"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"לא תקבל את ההודעות האלה יותר."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"לא תקבל את ההודעות האלה יותר"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> קטגוריות של התראות"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"האפליקציה הזו לא תומכת בקטגוריות של הודעות"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index 9bc189b..b460bb7 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"תמונה בתוך תמונה"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(תוכנית ללא כותרת)"</string>
<string name="pip_close" msgid="3480680679023423574">"סגור PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"מסך מלא"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9f63e38..e8d8ee2 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"OFF"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"電源通知管理では、アプリの通知の重要度をレベル 0~5 で設定できます。\n\n"<b>"レベル 5"</b>" \n- 通知リストの一番上に表示する \n- 全画面表示を許可する \n- 常にポップアップする \n\n"<b>"レベル 4"</b>" \n- 全画面表示しない \n- 常にポップアップする \n\n"<b>"レベル 3"</b>" \n- 全画面表示しない \n- ポップアップしない \n\n"<b>"レベル 2"</b>" \n- 全画面表示しない \n- ポップアップしない \n- 音やバイブレーションを使用しない \n\n"<b>"レベル 1"</b>" \n- 全画面表示しない \n- ポップアップしない \n- 音やバイブレーションを使用しない \n- ロック画面やステータスバーに表示しない \n- 通知リストの一番下に表示する \n\n"<b>"レベル 0"</b>" \n- アプリからのすべての通知をブロックする"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"今後、この通知は配信されません。"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"今後、この通知は配信されません"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 個の通知カテゴリ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"このアプリでは通知カテゴリが設定されていません"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ja/strings_tv.xml b/packages/SystemUI/res/values-ja/strings_tv.xml
index d249326..134bb18 100644
--- a/packages/SystemUI/res/values-ja/strings_tv.xml
+++ b/packages/SystemUI/res/values-ja/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"PIP"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(無題の番組)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP を閉じる"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"全画面表示"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 3bb07cd..2da6462 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"გამორთული"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"შეტყობინებების მართვის საშუალებების მეშვეობით, შეგიძლიათ განსაზღვროთ აპის შეტყობინებების მნიშვნელობის დონე 0-დან 5-მდე დიაპაზონში. \n\n"<b>"დონე 5"</b>" \n— შეტყობინებათა სიის თავში ჩვენება \n— სრულეკრანიანი რეჟიმის შეფერხების დაშვება \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 4"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 3"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n\n"<b>"დონე 2"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n\n"<b>"დონე 1"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n— ჩაკეტილი ეკრანიდან და სტატუსის ზოლიდან დამალვა \n— შეტყობინებათა სიის ბოლოში ჩვენება \n\n"<b>"დონე 0"</b>" \n— აპის ყველა შეტყობინების დაბლოკვა"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"შეტყობინებები"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"ამ შეტყობინებებს აღარ მიიღებთ."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"ამ შეტყობინებებს აღარ მიიღებთ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"შეტყობინებების <xliff:g id="NUMBER">%d</xliff:g> კატეგორია"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ამ აპს შეტყობინებების კატეგორიები არ აქვს"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ka/strings_tv.xml b/packages/SystemUI/res/values-ka/strings_tv.xml
index 18931cc..1a97590 100644
--- a/packages/SystemUI/res/values-ka/strings_tv.xml
+++ b/packages/SystemUI/res/values-ka/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"სურათი სურათში"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(პროგრამის სათაურის გარეშე)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP-ის დახურვა"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"სრულ ეკრანზე"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 44d7bd8..54f376c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өшірулі"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Қуат хабарландыруының басқару элементтерімен қолданбаның хабарландырулары үшін 0-ден бастап 5-ке дейін маңыздылық деңгейін орнатуға болады. \n\n"<b>"5-деңгей"</b>" \n- Хабарландыру тізімінің ең басында көрсету \n- Толық экранға ашылуын рұқсат ету \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"4-деңгей"</b>" \n- Толық экранға шығармау \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"3-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n\n"<b>"2-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс және діріл шығармау \n\n"<b>"1-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс немесе діріл шығармау \n- Құлыпталған экраннан және күйін көрсету жолағынан жасыру \n- Хабарландыру тізімінің ең астында көрсету \n\n"<b>"0-деңгей"</b>" \n- Қолданбадағы барлық хабарландыруларға тыйым салу"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Хабарландырулар"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Сізге енді бұл хабарландырулар жіберілмейді."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Енді сізге бұл хабарландырулар жіберілмейді"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> хабарландыру санаттары"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Бұл қолданбада хабарландыру санаттары жоқ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-kk/strings_tv.xml b/packages/SystemUI/res/values-kk/strings_tv.xml
index 6e40b53..305ad2e 100644
--- a/packages/SystemUI/res/values-kk/strings_tv.xml
+++ b/packages/SystemUI/res/values-kk/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Сурет ішіндегі сурет"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Атаусыз бағдарлама)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP жабу"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Толық экран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index b9aaaeb..d53380e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"បិទ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ជាមួយអង្គគ្រប់គ្រងការជូនដំណឹងថាមពល អ្នកអាចកំណត់កម្រិតសំខាន់ពី 0 ទៅ 5 សម្រាប់ការជូនដំណឹងរបស់កម្មវិធី។ \n\n"<b>"កម្រិត 5"</b>" \n- បង្ហាញនៅផ្នែកខាងលើបញ្ជីជូនដំណឹង \n- អនុញ្ញាតការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 4"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 3"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 2"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n\n"<b>"កម្រិត 1"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n- លាក់ពីអេក្រង់ចាក់សោ និងរបារស្ថានភាព \n- បង្ហាញនៅផ្នែកខាងក្រោមបញ្ជីជូនដំណឹង \n\n"<b>"កម្រិត 0"</b>" \n- រារាំងការជូនដំណឹងទាំងអស់ពីកម្មវិធី"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ការជូនដំណឹង"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"អ្នកនឹងមិនទទួលបានការជូនដំណឹងទាំងនេះទៀតទេ។"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"អ្នកនឹងមិនទទួលបានការជូនដំណឹងទាំងនេះទៀតទេ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"ប្រភេទនៃការជូនដំណឹងចំនួន <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"កម្មវិធីនេះមិនមានប្រភេទនៃការជូនដំណឹងទេ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-km/strings_tv.xml b/packages/SystemUI/res/values-km/strings_tv.xml
index d0e8289..5da818e 100644
--- a/packages/SystemUI/res/values-km/strings_tv.xml
+++ b/packages/SystemUI/res/values-km/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"រូបភាពក្នុងរូបភាព"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(កម្មវិធីគ្មានចំណងជើង)"</string>
<string name="pip_close" msgid="3480680679023423574">"បិទ PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ពេញអេក្រង់"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 1d32f91..816aa44 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ಆಫ್"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ಪವರ್ ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳ ಮೂಲಕ, ನೀವು ಅಪ್ಲಿಕೇಶನ್ಗಳ ಅಧಿಸೂಚನೆಗಳನ್ನು 0 ರಿಂದ 5 ರವರೆಗಿನ ಹಂತಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಬಹುದು. \n\n"<b>"ಹಂತ 5"</b>" \n- ಮೇಲಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ಅನುಮತಿಸಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ \n\n"<b>"ಹಂತ 4"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ\n\n"<b>"ಹಂತ 3"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n\n"<b>"ಹಂತ 2"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n\n"<b>"ಹಂತ 1"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n- ಸ್ಥಿತಿ ಪಟ್ಟಿ ಮತ್ತು ಲಾಕ್ ಪರದೆಯಿಂದ ಮರೆಮಾಡಿ \n- ಕೆಳಗಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n\n"<b>"ಹಂತ 0"</b>" \n- ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ಅಧಿಸೂಚನೆಗಳು"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"ನೀವು ಇನ್ನು ಮುಂದೆ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆಯುವುದಿಲ್ಲ."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"ನೀವು ಇನ್ನು ಮುಂದೆ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆಯುವುದಿಲ್ಲ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ಅಧಿಸೂಚನೆ ವರ್ಗಗಳು"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಅಧಿಸೂಚನೆ ವರ್ಗಗಳನ್ನು ಹೊಂದಿಲ್ಲ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-kn/strings_tv.xml b/packages/SystemUI/res/values-kn/strings_tv.xml
index 13514c6..85fde1f 100644
--- a/packages/SystemUI/res/values-kn/strings_tv.xml
+++ b/packages/SystemUI/res/values-kn/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರ"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ಶೀರ್ಷಿಕೆ ರಹಿತ ಕಾರ್ಯಕ್ರಮ)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP ಮುಚ್ಚಿ"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ಪೂರ್ಣ ಪರದೆ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6aa58e6..6b3c329 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"사용 안함"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"전원 알림 컨트롤을 사용하면 앱 알림 관련 중요도를 0부터 5까지로 설정할 수 있습니다. \n\n"<b>"레벨 5"</b>" \n- 알림 목록 상단에 표시 \n- 전체 화면일 경우 알림 표시 허용 \n- 항상 엿보기 표시 \n\n"<b>"레벨 4"</b>" \n- 전체 화면에 알림 표시 금지 \n- 항상 엿보기 표시 \n\n"<b>"레벨 3"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n\n"<b>"레벨 2"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n\n"<b>"레벨 1"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n- 잠금 화면 및 상태 표시줄에서 숨김 \n- 알림 목록 하단에 표시 \n\n"<b>"레벨 0"</b>" \n- 앱의 모든 알림 차단"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"알림"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"더 이상 다음의 알림을 받지 않습니다."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"더 이상 다음의 알림을 받지 않습니다."</string>
<string name="notification_num_channels" msgid="2048144408999179471">"알림 카테고리 <xliff:g id="NUMBER">%d</xliff:g>개"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"이 앱에는 알림 카테고리가 없습니다."</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ko/strings_tv.xml b/packages/SystemUI/res/values-ko/strings_tv.xml
index c147048..7c3d5a4 100644
--- a/packages/SystemUI/res/values-ko/strings_tv.xml
+++ b/packages/SystemUI/res/values-ko/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"PIP 모드"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(제목 없는 프로그램)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP 닫기"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"전체화면"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index d737c26..ca2fb78 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өчүк"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Бул функциянын жардамы менен ар бир колдонмо үчүн эскертменин маанилүүлүк деңгээлин 0дон 5ке чейин койсоңуз болот. \n\n"<b>"5-деңгээл"</b>" \n- Эскертмелер тизмесинин башында көрсөтүлсүн \n- Эскертмелер толук экранда көрсөтүлсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"4-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"3-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n\n"<b>"2-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n\n"<b>"1-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n- Кулпуланган экрандан жана абал тилкесинен жашырылсын \n- Эскертмелер тизмесинин аягында көрсөтүлсүн \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык эскертмелер бөгөттөлсүн"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Эскертмелер"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Мындан ары бул эскертмелер сизге жөнөтүлбөйт."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Мындан ары бул эскертмелер сизге жөнөтүлбөйт"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Эскертмелердин <xliff:g id="NUMBER">%d</xliff:g> категориясы"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Бул колдонмонун эскертме категориялары жок"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ky/strings_tv.xml b/packages/SystemUI/res/values-ky/strings_tv.xml
index a095ee2..5687b41 100644
--- a/packages/SystemUI/res/values-ky/strings_tv.xml
+++ b/packages/SystemUI/res/values-ky/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Сүрөт ичиндеги сүрөт"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Аталышы жок программа)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP\'ти жабуу"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Толук экран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 4d2010a..e59fcac 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ປິດ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ດ້ວຍການຄວບຄຸມການແຈ້ງເຕືອນ, ທ່ານສາມາດຕັ້ງລະດັບຄວາມສຳຄັນຈາກ 0 ຮອດ 5 ໃຫ້ກັບການແຈ້ງເຕືອນແອັບໃດໜຶ່ງໄດ້. \n\n"<b>"ລະດັບ 5"</b>" \n- ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ \n- ອະນຸຍາດໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 4"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 3"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n\n"<b>"ລະດັບ 2"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n\n"<b>"ລະດັບ 1"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n- ເຊື່ອງຈາກໜ້າຈໍລັອກ ແລະ ແຖບສະຖານະ \n- ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນ \n\n"<b>"ລະດັບ 0"</b>" \n- ປິດກັ້ນການແຈ້ງເຕືອນທັງໝົດຈາກແອັບ"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ການແຈ້ງເຕືອນ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ໝວດໝູ່ການແຈ້ງເຕືອນ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ແອັບນີ້ບໍ່ມີໝວດໝູ່ການແຈ້ງເຕືອນ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-lo/strings_tv.xml b/packages/SystemUI/res/values-lo/strings_tv.xml
index 5ca9094..65367842 100644
--- a/packages/SystemUI/res/values-lo/strings_tv.xml
+++ b/packages/SystemUI/res/values-lo/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ໂປຣແກຣມບໍ່ມີຊື່)"</string>
<string name="pip_close" msgid="3480680679023423574">"ປິດ PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ເຕັມໜ້າຈໍ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 50f6b6b..2ded45c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -552,7 +552,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Išjungta"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Naudodami pranešimų valdiklius galite nustatyti programos pranešimų svarbos lygį nuo 0 iki 5. \n\n"<b>"5 lygis"</b>" \n– Rodyti pranešimų sąrašo viršuje \n– Leisti pertraukti, kai veikia viso ekrano režimas \n– Visada rodyti pranešimus \n\n"<b>"4 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Visada rodyti pranešimus \n\n"<b>"3 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n\n"<b>"2 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n\n"<b>"1 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n– Slėpti užrakinimo ekrane ir būsenos juostoje \n– Rodyti pranešimų sąrašo apačioje \n\n"<b>"0 lygis"</b>" \n– Blokuoti visus programos pranešimus"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Pranešimai"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Nebegausite šių pranešimų."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Nebegausite šių pranešimų"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Pranešimų kategorijų: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Šioje programoje nėra pranešimų kategorijų"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-lt/strings_tv.xml b/packages/SystemUI/res/values-lt/strings_tv.xml
index 124a7e3..2e6fa58 100644
--- a/packages/SystemUI/res/values-lt/strings_tv.xml
+++ b/packages/SystemUI/res/values-lt/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Vaizdas vaizde"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programa be pavadinimo)"</string>
<string name="pip_close" msgid="3480680679023423574">"Uždaryti PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Visas ekranas"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c997609..68345a4 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izslēgts"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Izmantojot barošanas paziņojumu vadīklas, varat lietotnes paziņojumiem iestatīt svarīguma līmeni (no 0 līdz 5). \n\n"<b>"5. līmenis"</b>" \n- Tiek rādīts paziņojumu saraksta augšdaļā \n- Tiek atļauta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"4. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"3. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n\n"<b>"2. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n\n"<b>"1. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n- Paziņojumi tiek paslēpti bloķēšanas ekrānā un statusa joslā \n- Paziņojumi tiek rādīti paziņojumu saraksta apakšdaļā \n\n"<b>"0. līmenis"</b>" \n- Visi lietotnes paziņojumi tiek bloķēti"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Paziņojumi"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Jūs vairs nesaņemsiet šos paziņojumus."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Jūs vairs nesaņemsiet šos paziņojumus"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> paziņojumu kategorijas"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Paziņojumu kategorijas šajā lietotnē nav pieejamas."</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-lv/strings_tv.xml b/packages/SystemUI/res/values-lv/strings_tv.xml
index ac9b1d6..474fe98 100644
--- a/packages/SystemUI/res/values-lv/strings_tv.xml
+++ b/packages/SystemUI/res/values-lv/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Attēls attēlā"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programma bez nosaukuma)"</string>
<string name="pip_close" msgid="3480680679023423574">"Aizvērt PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pilnekrāna režīms"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 91f7508..2496fe2 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Исклучено"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Со контролите за известувањата за напојување, може да поставите ниво на важност од 0 до 5 за известувањата на која било апликација. \n\n"<b>"Ниво 5"</b>" \n- Прикажувај на врвот на списокот со известувања \n- Дозволи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 4"</b>" \n- Спречи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 3"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n\n"<b>"Ниво 2"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n\n"<b>"Ниво 1"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n- Сокриј од заклучен екран и статусна лента \n- Прикажувај на дното на списокот со известувања \n\n"<b>"Ниво 0"</b>" \n- Блокирај ги сите известувања од апликацијата"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Известувања"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Веќе нема да ги добивате овие известувања."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Веќе нема да ги добивате овие известувања"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> категории известувања"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Апликацијава нема катерии известувања"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-mk/strings_tv.xml b/packages/SystemUI/res/values-mk/strings_tv.xml
index e9772bb..f12368b 100644
--- a/packages/SystemUI/res/values-mk/strings_tv.xml
+++ b/packages/SystemUI/res/values-mk/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Слика во слика"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Програма без наслов)"</string>
<string name="pip_close" msgid="3480680679023423574">"Затвори PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Цел екран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 7def7a5..ae59ce2 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ഓഫ്"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"പവർ അറിയിപ്പ് നിയന്ത്രണം ഉപയോഗിച്ച്, ഒരു ആപ്പിനായുള്ള അറിയിപ്പുകൾക്ക് 0 മുതൽ 5 വരെയുള്ള പ്രാധാന്യ ലെവലുകളിലൊന്ന് നിങ്ങൾക്ക് സജ്ജമാക്കാവുന്നതാണ്. \n\n"<b>"ലെവൽ 5"</b>" \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ മുകളിൽ കാണിക്കുക \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം അനുവദിക്കുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 4"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 3"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും സൃശ്യമാക്കരുത് \n\n"<b>"ലെവൽ 2"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n\n"<b>"ലെവൽ 1"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n- ലോക്ക് സ്ക്രീനിൽ നിന്നും സ്റ്റാറ്റസ് ബാറിൽ നിന്നും മറയ്ക്കുക \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ അടിയിൽ കാണിക്കുക \n\n"<b>"ലെവൽ 0"</b>" \n- ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"അറിയിപ്പുകൾ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"നിങ്ങൾക്ക് ഈ അറിയിപ്പുകൾ ഇനിയങ്ങോട്ട് ലഭിക്കില്ല."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"നിങ്ങൾക്ക് ഇനി ഈ അറിയിപ്പുകൾ ലഭിക്കില്ല"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> അറിയിപ്പ് വിഭാഗങ്ങൾ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ഈ ആപ്പിന് അറിയിപ്പ് വിഭാഗങ്ങളില്ല"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ml/strings_tv.xml b/packages/SystemUI/res/values-ml/strings_tv.xml
index 77763b6..1cf0689 100644
--- a/packages/SystemUI/res/values-ml/strings_tv.xml
+++ b/packages/SystemUI/res/values-ml/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ചിത്രത്തിനുള്ളിൽ ചിത്രം"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(പേരില്ലാത്ത പ്രോഗ്രാം)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP അടയ്ക്കുക"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"പൂര്ണ്ണ സ്ക്രീന്"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index fcc7903..6e17561 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Идэвхгүй"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Тэжээлийн мэдэгдлийн удирдлагын тусламжтайгаар та апп-н мэдэгдэлд 0-5 хүртэлх ач холбогдлын түвшин тогтоох боломжтой. \n\n"<b>"5-р түвшин"</b>" \n- Мэдэгдлийн жагсаалтын хамгийн дээр харуулна \n- Бүтэн дэлгэцэд саад болно \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"4-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд тогтмол гарч ирнэ \n\n"<b>"3-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n\n"<b>"2-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n\n"<b>"1-р түвшин"</b>" \n- Бүтэн дэлгэцэд саад болохоос сэргийлнэ \n- Дэлгэцэд хэзээ ч гарч ирэхгүй \n- Дуу болон чичиргээ хэзээ ч гаргахгүй \n- Түгжигдсэн дэлгэц болон статусын самбараас нууна \n- Мэдэгдлийн жагсаалтын доор харуулна \n\n"<b>"0-р түвшин"</b>" \n- Энэ апп-н бүх мэдэгдлийг блоклоно"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Мэдэгдэл"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ta цаашид мэдэгдэл авахгүй."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ta цаашид эдгээр мэдэгдлийг авахгүй"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> мэдэгдлийн ангилал"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Энэ апп-д мэдэгдлийн категори алга"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-mn/strings_tv.xml b/packages/SystemUI/res/values-mn/strings_tv.xml
index 2a591f0..bbc94c8 100644
--- a/packages/SystemUI/res/values-mn/strings_tv.xml
+++ b/packages/SystemUI/res/values-mn/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Зураг-доторх-Зураг"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Гарчиггүй хөтөлбөр)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP-г хаах"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Бүтэн дэлгэц"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8ded3da..9fc8132 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"पॉवर सूचना नियंत्रणांसह, आपण अॅपच्या सूचनांसाठी महत्त्व स्तर 0 ते 5 पर्यंत सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दर्शवा \n- पूर्ण स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n\n"<b>"स्तर 1"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना अवरोधित करा"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"आपल्याला यापुढे या सूचना प्राप्त होणार नाहीत."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"तुम्हाला यापुढे या सूचना प्राप्त होणार नाहीत"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> सूचना श्रेण्या"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"या अॅपला सूचना श्रेण्या नाहीत"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-mr/strings_tv.xml b/packages/SystemUI/res/values-mr/strings_tv.xml
index 8d1fc5c..aac2d5e 100644
--- a/packages/SystemUI/res/values-mr/strings_tv.xml
+++ b/packages/SystemUI/res/values-mr/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"चित्रा-मध्ये-चित्र"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(शीर्षक नसलेला कार्यक्रम)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP बंद करा"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रीन"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 2fe3b4d..d1b0d1b 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Mati"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Dengan kawalan pemberitahuan berkuasa, anda boleh menetapkan tahap kepentingan dari 0 hingga 5 untuk pemberitahuan apl. \n\n"<b>"Tahap 5"</b>" \n- Tunjukkan pada bahagian atas senarai pemberitahuan \n- Benarkan gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 4"</b>" \n- Halang gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 3"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n\n"<b>"Tahap 2"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi dan bergetar \n\n"<b>"Tahap 1"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi atau bergetar \n- Sembunyikan daripada skrin kunci dan bar status \n- Tunjukkan di bahagian bawah senarai pemberitahuan \n\n"<b>"Tahap 0"</b>" \n- Sekat semua pemberitahuan daripada apl"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Pemberitahuan"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Anda tidak akan menerima pemberitahuan ini lagi."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Anda tidak akan menerima pemberitahuan ini lagi"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kategori pemberitahuan"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Apl ini tiada kategori pemberitahuan"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ms/strings_tv.xml b/packages/SystemUI/res/values-ms/strings_tv.xml
index 0899da2..110ddca 100644
--- a/packages/SystemUI/res/values-ms/strings_tv.xml
+++ b/packages/SystemUI/res/values-ms/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Gambar dalam Gambar"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program tiada tajuk)"</string>
<string name="pip_close" msgid="3480680679023423574">"Tutup PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Skrin penuh"</string>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index fe5a0e0..f355880 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ပိတ်ပါ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများကိုအသုံးပြုပြီး အက်ပ်တစ်ခု၏ အကြောင်းကြားချက် အရေးပါမှု ၀ မှ ၅ အထိသတ်မှတ်ပေးနိုင်သည်။ \n\n"<b>"အဆင့် ၅"</b>" \n- အကြောင်းကြားချက်စာရင်း၏ ထိပ်ဆုံးတွင် ပြသည် \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်းကို ခွင့်ပြုသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၄"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၃"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n\n"<b>"အဆင့် ၂"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n\n"<b>"အဆင့် ၁"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n- လော့ခ်ချထားသည့် မျက်နှာပြင်နှင့် အခြေအနေဘားတန်းတို့တွင် မပြပါ \n- အကြောင်းကြားချက်စာရင်း အောက်ဆုံးတွင်ပြသည် \n\n"<b>"အဆင့် ၀"</b>" \n- အက်ပ်မှ အကြောင်းကြားချက်များ အားလုံးကို ပိတ်ဆို့သည်"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"အကြောင်းကြားချက်များ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"သင်သည် ဤအကြောင်းကြားချက်များကို လက်ခံရရှိတော့မည် မဟုတ်ပါ။"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"သင်သည် ဤအကြောင်းကြားချက်များကို နောက်ထပ် လက်ခံရရှိတော့မည် မဟုတ်ပါ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"အကြောင်းကြားချက် အမျိုးအစား <xliff:g id="NUMBER">%d</xliff:g> ခု"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ဤအက်ပ်တွင် အကြောင်းကြားချက် အမျိုးအစားများ မရှိပါ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-my/strings_tv.xml b/packages/SystemUI/res/values-my/strings_tv.xml
index f5d53aa..346e553 100644
--- a/packages/SystemUI/res/values-my/strings_tv.xml
+++ b/packages/SystemUI/res/values-my/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"တစ်ခုပေါ်တစ်ခု ထပ်၍ ဖွင့်ခြင်း"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ခေါင်းစဉ်မဲ့ အစီအစဉ်)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP ကိုပိတ်ပါ"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"မျက်နှာပြင် အပြည့်"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9715ac6..3dc0440 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Av"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med effektive varselinnstillinger kan du angi viktighetsnivåer fra 0 til 5 for appvarsler. \n\n"<b>"Nivå 5"</b>" \n– Vis øverst på varsellisten \n– Tillat forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 4"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 3"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n\n"<b>"Nivå 2"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri fort \n– Tillat aldri lyder eller vibrering \n\n"<b>"Nivå 1"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n– Tillat aldri lyder eller vibrering \n– Skjul fra låseskjermen og statusfeltet \n– Vis nederst på varsellisten \n\n"<b>"Nivå 0"</b>" \n– Blokkér alle varsler fra appen"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Varsler"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Du får ikke disse varslene lenger."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Du får ikke disse varslene lenger"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> varselkategorier"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Denne appen har ikke varselkategorier"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -701,7 +701,7 @@
<string name="dock_forced_resizable" msgid="5914261505436217520">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Appen støtter ikke delt skjerm."</string>
<string name="forced_resizable_secondary_display" msgid="4230857851756391925">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
- <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Appen støtter ikke oppstart på sekundære skjermer."</string>
+ <string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"Appen kan ikke kjøres på sekundære skjermer."</string>
<string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Åpne innstillingene."</string>
<string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Åpner hurtiginnstillingene."</string>
<string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Lukk hurtiginnstillingene."</string>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index 74774da..59758dd 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Bilde-i-bilde"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program uten tittel)"</string>
<string name="pip_close" msgid="3480680679023423574">"Lukk PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Fullskjerm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 585ae77..3187809 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"निष्क्रिय"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईं अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"सूचनाहरू"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"तपाईंले अबदेखि यी सूचनाहरू प्राप्त गर्नुहुने छैन।"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"तपाईंले अब उप्रान्त यी सूचनाहरू प्राप्त गर्नुहुने छैन"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> सूचनाका कोटिहरू"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"यस अनुप्रयोगमा सूचना सम्बन्धी कोटीहरू छैनन्"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ne/strings_tv.xml b/packages/SystemUI/res/values-ne/strings_tv.xml
index 8554a91..2c5c186 100644
--- a/packages/SystemUI/res/values-ne/strings_tv.xml
+++ b/packages/SystemUI/res/values-ne/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"तस्बिरभित्रको तस्बिर"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(शीर्षकविहीन कार्यक्रम)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP लाई बन्द गर्नुहोस्"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"पूर्ण स्क्रिन"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index d9de896..08de58c 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Uit"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelingsscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Meldingen"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Je ontvangt deze meldingen niet meer."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Je ontvangt deze meldingen niet meer"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> meldingscategorieën"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Deze app heeft geen meldingscategorieën"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-nl/strings_tv.xml b/packages/SystemUI/res/values-nl/strings_tv.xml
index 17c6270..fae484f 100644
--- a/packages/SystemUI/res/values-nl/strings_tv.xml
+++ b/packages/SystemUI/res/values-nl/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Beeld-in-beeld"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Naamloos programma)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP sluiten"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Volledig scherm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9c54aff..dd56b6e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ਬੰਦ"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ਪਾਵਰ ਸੂਚਨਾ ਕੰਟਰੋਲਾਂ ਨਾਲ, ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਦੀਆਂ ਸੂਚਨਾਵਾਂ ਲਈ ਮਹੱਤਤਾ ਪੱਧਰ ਨੂੰ 0 ਤੋਂ 5 ਤੱਕ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। \n\n"<b>"ਪੱਧਰ 5"</b>" \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਦੀ ਆਗਿਆ ਦਿਓ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 4"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 3"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 2"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਵੀ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n\n"<b>"ਪੱੱਧਰ 1"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n- ਲੌਕ ਸਕ੍ਰੀਨ ਅਤੇ ਸਥਿਤੀ ਪੱਟੀ ਤੋਂ ਲੁਕਾਓ \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 0"</b>" \n- ਐਪ ਤੋਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲੌਕ ਕਰੋ"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"ਸੂਚਨਾਵਾਂ"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"ਤੁਸੀਂ ਹੁਣ ਇਹ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰੋਂਗੇ।"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"ਤੁਹਾਨੂੰ ਹੁਣ ਇਹ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਨਹੀਂ ਹੋਣਗੀਆਂ"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ਸੂਚਨਾ ਸ਼੍ਰੇਣੀਆਂ"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ਇਸ ਐਪ ਵਿੱਚ ਸੂਚਨਾ ਸ਼੍ਰੇਣੀਆਂ ਨਹੀਂ ਹਨ"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -700,7 +700,7 @@
<string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g> ਸੂਚਨਾ: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="dock_forced_resizable" msgid="5914261505436217520">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
- <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰ ਸਕੇ।"</string>
+ <string name="forced_resizable_secondary_display" msgid="4230857851756391925">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
<string name="activity_launch_on_secondary_display_failed_text" msgid="7793821742158306742">"ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
<string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
<string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਖੋਲ੍ਹੋ।"</string>
diff --git a/packages/SystemUI/res/values-pa/strings_tv.xml b/packages/SystemUI/res/values-pa/strings_tv.xml
index b6d9759..245fc44 100644
--- a/packages/SystemUI/res/values-pa/strings_tv.xml
+++ b/packages/SystemUI/res/values-pa/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ਸਿਰਲੇਖ-ਰਹਿਤ ਪ੍ਰੋਗਰਾਮ)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP ਬੰਦ ਕਰੋ"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c23d0d0..02ad8ca 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -552,7 +552,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Wył."</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Dzięki zaawansowanym ustawieniom możesz określić poziom ważności powiadomień z aplikacji w skali od 0 do 5. \n\n"<b>"Poziom 5"</b>" \n– Pokazuj u góry listy powiadomień \n– Zezwalaj na powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 4"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 3"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n\n"<b>"Poziom 2"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n\n"<b>"Poziom 1"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n– Ukrywaj na ekranie blokady i pasku stanu \n– Pokazuj u dołu listy powiadomień \n\n"<b>"Poziom 0"</b>" \n– Blokuj wszystkie powiadomienia aplikacji"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Powiadomienia"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Nie będziesz już otrzymywać tych powiadomień."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Nie będziesz już otrzymywać tych powiadomień"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Kategorie powiadomień: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ta aplikacja nie ma kategorii powiadomień"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 1148efd..7e0afd9 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Obraz w obrazie"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program bez tytułu)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zamknij PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Pełny ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 4e712d7..66d0b27 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Você deixará de receber essas notificações"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorias de notificação"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Este app não tem categorias de notificação"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
index b55275f..7bcb965 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(programa sem título)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Tela cheia"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 5db30bb..822a0c0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da aplicação"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Já não recebe estas notificações."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Deixará de receber estas notificações"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorias de notificação"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicação não tem categorias de notificação"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
index 915e22f..a621877 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Imagem na imagem"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Sem título do programa)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ecrã inteiro"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 4e712d7..66d0b27 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Você deixará de receber essas notificações"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorias de notificação"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Este app não tem categorias de notificação"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-pt/strings_tv.xml b/packages/SystemUI/res/values-pt/strings_tv.xml
index b55275f..7bcb965 100644
--- a/packages/SystemUI/res/values-pt/strings_tv.xml
+++ b/packages/SystemUI/res/values-pt/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(programa sem título)"</string>
<string name="pip_close" msgid="3480680679023423574">"Fechar PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Tela cheia"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bf87937..a04d72d7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -552,7 +552,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Dezactivate"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Folosind comenzile de gestionare a notificărilor, puteți să setați un nivel de importanță de la 0 la 5 pentru notificările unei aplicații. \n\n"<b>"Nivelul 5"</b>" \n– Se afișează la începutul listei de notificări \n– Se permite întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 4"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 3"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n\n"<b>"Nivelul 2"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n\n"<b>"Nivelul 1"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n– Se ascunde în ecranul de blocare și în bara de stare \n– Se afișează la finalul listei de notificări \n\n"<b>"Nivelul 0"</b>" \n– Se blochează toate notificările din aplicație"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Notificări"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Nu veți mai primi aceste notificări."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Nu veți mai primi aceste notificări"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> categorii de notificări"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Această aplicație nu are categorii de notificare"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ro/strings_tv.xml b/packages/SystemUI/res/values-ro/strings_tv.xml
index 048b224..3ca7540 100644
--- a/packages/SystemUI/res/values-ro/strings_tv.xml
+++ b/packages/SystemUI/res/values-ro/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program fără titlu)"</string>
<string name="pip_close" msgid="3480680679023423574">"Închideți PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ecran complet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 09e1bcb..35a54d2a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Отключено"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"С помощью этой функции вы можете устанавливать уровень важности уведомлений от 0 до 5 для каждого приложения.\n\n"<b>"Уровень 5"</b>\n"‒ Помещать уведомления в начало списка.\n‒ Показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 4\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 3\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\nУровень 2\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\nУровень 1\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\n‒ Не показывать на экране блокировки и в строке состояния.\n‒ Помещать уведомления в конец списка.\nУровень 0\n"<b></b>\n"‒ Блокировать все уведомления приложения."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Уведомления"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больше не будете получать эти уведомления."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Вы больше не будете получать эти уведомления"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Категорий оповещений: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"В приложении нет категорий уведомлений"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index 41e24c7..e0c55d1 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Картинка в картинке"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Без названия)"</string>
<string name="pip_close" msgid="3480680679023423574">"\"Кадр в кадре\" – выйти"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Во весь экран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 5024bfc..4ce15ed 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ක්රියාවිරහිතයි"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"බල දැනුම්දීම් පාලන සමගින්, ඔබට යෙදුමක දැනුම්දීම් සඳහා වැදගත්කම 0 සිට 5 දක්වා සැකසිය හැකිය. \n\n"<b>"5 මට්ටම"</b>" \n- දැනුම්දීම් ලැයිස්තුවේ ඉහළින්ම පෙන්වන්න \n- පූර්ණ තිර බාධාවට ඉඩ දෙන්න \n- සැම විට එබී බලන්න \n\n"<b>"4 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- සැම විට එබී බලන්න \n\n"<b>"3 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n\n"<b>"2 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n- කිසි විටක හඬ සහ කම්පනය සිදු නොකරන්න \n\n"<b>"1 මට්ටම"</b>" \n- පූර්ණ තිර බාධාව වළක්වන්න \n- කිසි විටක එබී නොබලන්න \n- කිසි විටක හඬ සහ කම්පනය සිදු නොකරන්න \n- අගුලු තිරය සහ තත්ත්ව තීරුව වෙතින් සඟවන්න \n- දැනුම්දීම් ලැයිස්තුවේ පහළින්ම පෙන්වන්න \n\n"<b>"0 මට්ටම"</b>" \n- යෙදුම වෙතින් වන සියලු දැනුම් දීම් සඟවන්න."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"දැනුම් දීම්"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"ඔබ තවදුරටත් මෙම දැනුම්දීම් නොලැබෙනු ඇත."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"ඔබට තවදුරටත් මෙම දැනුම්දීම් නොලැබෙනු ඇත"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"දැනුම්දීම් කාණ්ඩ <xliff:g id="NUMBER">%d</xliff:g>ක්"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"මෙම යෙදුම හට දැනුම්දීම් ප්රවර්ග නොමැත"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-si/strings_tv.xml b/packages/SystemUI/res/values-si/strings_tv.xml
index f4178fd..f4f15a3 100644
--- a/packages/SystemUI/res/values-si/strings_tv.xml
+++ b/packages/SystemUI/res/values-si/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"පින්තූරය-තුළ-පින්තූරය"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(මාතෘකාවක් නැති වැඩසටහන)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP වසන්න"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"සම්පූර්ණ තිරය"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1ef815c..e6fa563 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuté"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Pomocou ovládacích prvkov zobrazovania upozornení môžete nastaviť pre upozornenia aplikácie úroveň dôležitosti od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazovať v hornej časti zoznamu upozornení. \n– Povoliť prerušenia na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 4"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 3"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n\n"<b>"Úroveň 2"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n\n"<b>"Úroveň 1"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n– Skryť na uzamknutej obrazovke a v stavovom riadku. \n– Zobraziť v dolnej časti zoznamu upozornení. \n\n"<b>"Úroveň 0"</b>" \n– Blokovať všetky upozornenia z aplikácie."</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Upozornenia"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Takéto upozornenia už nebudete dostávať."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Tieto upozornenia už nebudete dostávať"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Počet kategórií upozornení: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Táto aplikácia nemá kategórie upozornení"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-sk/strings_tv.xml b/packages/SystemUI/res/values-sk/strings_tv.xml
index 196c6e1..1279ecf 100644
--- a/packages/SystemUI/res/values-sk/strings_tv.xml
+++ b/packages/SystemUI/res/values-sk/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Obraz v obraze"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program bez názvu)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zavrieť režim PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Celá obrazovka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7336185..816aa61 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izklopljeno"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"S kontrolniki za pomebnost obvestila je mogoče za obvestila aplikacije nastaviti stopnjo pomembnosti od 0 do 5. \n\n"<b>"Stopnja 5"</b>" \n– Prikaz na vrhu seznama obvestil \n– Omogočanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 4"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 3"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n\n"<b>"Stopnja 2"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n\n"<b>"Stopnja 1"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n– Skrivanje na zaklenjenem zaslonu in v vrstici stanja \n– Prikaz na dnu seznama obvestil \n\n"<b>"Stopnja 0"</b>" \n– Blokiranje vseh obvestil aplikacije"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Obvestila"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Teh obvestil ne boste več prejemali."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Teh obvestil ne boste več prejemali"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Št. kategorij obvestil: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ta aplikacija nima kategorij obvestil"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -758,8 +758,8 @@
<string name="notification_channel_screenshot" msgid="6314080179230000938">"Posnetki zaslona"</string>
<string name="notification_channel_general" msgid="4525309436693914482">"Splošna sporočila"</string>
<string name="notification_channel_storage" msgid="3077205683020695313">"Shramba"</string>
- <string name="instant_apps" msgid="6647570248119804907">"Aplikacije brez nameščanja"</string>
- <string name="instant_apps_message" msgid="8116608994995104836">"Aplikacij brez nameščanja ni treba namestiti."</string>
+ <string name="instant_apps" msgid="6647570248119804907">"Nenamestljive aplikacije"</string>
+ <string name="instant_apps_message" msgid="8116608994995104836">"Nenamestljivih aplikacij ni treba namestiti."</string>
<string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
<string name="go_to_web" msgid="1106022723459948514">"Pojdi v splet"</string>
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podatki"</string>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index b8423e6..8c2e33d 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Slika v sliki"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program brez naslova)"</string>
<string name="pip_close" msgid="3480680679023423574">"Zapri način PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Celozaslonsko"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c54ce53..e451efc6 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Joaktiv"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Me kontrollet e njoftimit të energjisë, mund të caktosh një nivel rëndësie nga 0 në 5 për njoftimet e një aplikacioni. \n\n"<b>"Niveli 5"</b>" \n- Shfaq në krye të listës së njoftimeve \n- Lejo ndërprerjen e ekranit të plotë \n- Gjithmonë shfaq shpejt \n\n"<b>"Niveli 4"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Gijthmonë shfaq shpejt \n\n"<b>"Niveli 3"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n\n"<b>"Niveli 2"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull dhe dridhje \n\n"<b>"Niveli 1"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull ose dridhje \n- Fshih nga ekrani i kyçjes dhe shiriti i statusit \n- Shfaq në fund të listës së njoftimeve \n\n"<b>"Niveli 0"</b>" \n- Blloko të gjitha njoftimet nga aplikacioni"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Njoftime"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Këto njoftime nuk do t\'i marrësh më."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Këto njoftime nuk do t\'i marrësh më"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> kategori njoftimesh"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ky aplikacion nuk ka kategori njoftimesh"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-sq/strings_tv.xml b/packages/SystemUI/res/values-sq/strings_tv.xml
index 12ab06e..8c76832 100644
--- a/packages/SystemUI/res/values-sq/strings_tv.xml
+++ b/packages/SystemUI/res/values-sq/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Figurë brenda figurës"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Program pa titull)"</string>
<string name="pip_close" msgid="3480680679023423574">"Mbyll PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Ekrani i plotë"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e9445ff..2e9005d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -473,7 +473,7 @@
<string name="hidden_notifications_title" msgid="7139628534207443290">"Брже добијајте обавештења"</string>
<string name="hidden_notifications_text" msgid="2326409389088668981">"Прегледајте их пре откључавања"</string>
<string name="hidden_notifications_cancel" msgid="3690709735122344913">"Не, хвала"</string>
- <string name="hidden_notifications_setup" msgid="41079514801976810">"Подеси"</string>
+ <string name="hidden_notifications_setup" msgid="41079514801976810">"Активирај"</string>
<string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
<string name="volume_zen_end_now" msgid="3179845345429841822">"Прекини одмах"</string>
<string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Искључено"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Помоћу напредних контрола за обавештења можете да подесите ниво важности од 0. до 5. за обавештења апликације. \n\n"<b>"5. ниво"</b>" \n– Приказују се у врху листе обавештења \n- Дозволи прекид режима целог екрана \n– Увек завируј \n\n"<b>"4. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Увек завируј \n\n"<b>"3. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n\n"<b>"2. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n\n"<b>"1. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n– Сакриј на закључаном екрану и статусној траци \n– Приказују се у дну листе обавештења \n\n"<b>"0. ниво"</b>" \n– Блокирај сва обавештења из апликације"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Обавештења"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Више нећете да добијате ова обавештења."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Више нећете добијати ова обавештења"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Категорија обавештења: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ова апликација нема категорије обавештења"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
@@ -739,7 +739,7 @@
<string name="lockscreen_unlock_left" msgid="2043092136246951985">"И лева пречица откључава"</string>
<string name="lockscreen_unlock_right" msgid="1529992940510318775">"И десна пречица откључава"</string>
<string name="lockscreen_none" msgid="4783896034844841821">"Ништа"</string>
- <string name="tuner_launch_app" msgid="1527264114781925348">"Покретање <xliff:g id="APP">%1$s</xliff:g>"</string>
+ <string name="tuner_launch_app" msgid="1527264114781925348">"Покрени <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="tuner_other_apps" msgid="4726596850501162493">"Друге апликације"</string>
<string name="tuner_circle" msgid="2340998864056901350">"Круг"</string>
<string name="tuner_plus" msgid="6792960658533229675">"Плус"</string>
diff --git a/packages/SystemUI/res/values-sr/strings_tv.xml b/packages/SystemUI/res/values-sr/strings_tv.xml
index fac72d4..3e0431f 100644
--- a/packages/SystemUI/res/values-sr/strings_tv.xml
+++ b/packages/SystemUI/res/values-sr/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Слика у слици"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Програм без наслова)"</string>
<string name="pip_close" msgid="3480680679023423574">"Затвори PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Цео екран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 99e8f32..09d2cf2 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"På"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Med aviseringsinställningarna kan du ange prioritetsnivå från 0 till 5 för aviseringar från en app. \n\n"<b>"Nivå 5"</b>" \n– Visa högst upp i aviseringslistan\n– Tillåt avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 4"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 3"</b>" \n- Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n\n"<b>"Nivå 2"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n\n"<b>"Nivå 1"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n– Visa inte på låsskärmen och i statusfältet \n– Visa längst ned i aviseringslistan \n\n"<b>"Nivå 0"</b>" \n– Blockera alla aviseringar från appen"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Aviseringar"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Inga fler aviseringar av det här slaget visas."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Inga fler aviseringar av det här slaget visas"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> aviseringskategorier"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Det finns inga aviseringskategorier i appen"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index 3c33e8b1..d503e54 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Bild-i-bild"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Namnlöst program)"</string>
<string name="pip_close" msgid="3480680679023423574">"Stäng PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Helskärm"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 286eba3..619ac5e 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Imezimwa"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ukiwa na udhibiti wa arifa, unaweza kuweka kiwango cha umuhimu wa arifa za programu kuanzia 0 hadi 5. \n\n"<b>"Kiwango cha 5"</b>" \n- Onyesha katika sehemu ya juu ya orodha ya arifa \n- Ruhusu ukatizaji wa skrini nzima \n- Ruhusu arifa za kuchungulia kila wakati\n\n"<b>"Kiwango cha 4"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Ruhusu arifa za kuchungulia kila wakati \n\n"<b>"Kiwango cha 3"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia\n\n"<b>"Kiwango cha 2"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti au mtetemo \n\n"<b>"Kiwango cha 1"</b>" \n- Zuia ukatizaji wa skrini nzima \n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti na mtetemo \n- Usionyeshe skrini iliyofungwa na sehemu ya arifa \n- Onyesha katika sehemu ya chini ya orodha ya arifa \n\n"<b>"Kiwango cha 0"</b>" \n- Zuia arifa zote kutoka programu"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Arifa"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Hutapokea arifa hizi tena."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Hutapokea arifa hizi tena"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Aina <xliff:g id="NUMBER">%d</xliff:g> za arifa"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Programu hii haina aina za arifa"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-sw/strings_tv.xml b/packages/SystemUI/res/values-sw/strings_tv.xml
index 8811959..713a691 100644
--- a/packages/SystemUI/res/values-sw/strings_tv.xml
+++ b/packages/SystemUI/res/values-sw/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picha ndani ya picha"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Programu isiyo na jina)"</string>
<string name="pip_close" msgid="3480680679023423574">"Funga PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Skrini nzima"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 6300d8c..3b924eb 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"முடக்கத்தில்"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ஆற்றல்மிக்க அறிவிப்புக் கட்டுப்பாடுகள் மூலம், பயன்பாட்டின் அறிவிப்புகளுக்கு முக்கியத்துவ நிலையை (0-5) அமைக்கலாம். \n\n"<b>"நிலை 5"</b>" \n- அறிவிப்புப் பட்டியலின் மேலே காட்டும் \n- முழுத் திரைக் குறுக்கீட்டை அனுமதிக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 4"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 3"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n\n"<b>"நிலை 2"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது, அதிர்வுறாது \n\n"<b>"நிலை 1"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது அல்லது அதிர்வுறாது \n- பூட்டுத்திரை மற்றும் நிலைப்பட்டியிலிருந்து மறைக்கும் \n- அறிவிப்புகள் பட்டியலின் கீழே காட்டும் \n\n"<b>"நிலை 0"</b>" \n- பயன்பாட்டின் எல்லா அறிவிப்புகளையும் தடுக்கும்"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"அறிவிப்புகள்"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"இந்த அறிவிப்புகளை இனி பெறமாட்டீர்கள்."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"இந்த அறிவிப்புகளை இனி பெறமாட்டீர்கள்"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> அறிவிப்பு வகைகள்"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"இந்தப் பயன்பாட்டில் அறிவிப்பு வகைகள் இல்லை"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ta/strings_tv.xml b/packages/SystemUI/res/values-ta/strings_tv.xml
index a54bd87..5ddab56 100644
--- a/packages/SystemUI/res/values-ta/strings_tv.xml
+++ b/packages/SystemUI/res/values-ta/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"பிக்ச்சர் இன் பிக்ச்சர்"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(தலைப்பு இல்லை)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIPஐ மூடு"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"முழுத்திரை"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 3900f26..88721ce 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ఆఫ్లో ఉన్నాయి"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"పవర్ నోటిఫికేషన్ నియంత్రణలతో, మీరు అనువర్తన నోటిఫికేషన్ల కోసం ప్రాముఖ్యత స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ జాబితా పైభాగంలో చూపబడతాయి \n- పూర్తి స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్ మరియు స్థితి పట్టీ నుండి దాచబడతాయి \n- నోటిఫికేషన్ జాబితా దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- అనువర్తనం నుండి అన్ని నోటిఫికేషన్లు బ్లాక్ చేయబడతాయి"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"నోటిఫికేషన్లు"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"మీరు ఇకపై ఈ నోటిఫికేషన్లను పొందరు."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"మీరు ఇకపై ఈ నోటిఫికేషన్లను పొందరు"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> నోటిఫికేషన్ వర్గాలు"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"ఈ అనువర్తనానికి నోటిఫికేషన్ వర్గాలు లేవు"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-te/strings_tv.xml b/packages/SystemUI/res/values-te/strings_tv.xml
index 3ead9f6..9f2ea4e 100644
--- a/packages/SystemUI/res/values-te/strings_tv.xml
+++ b/packages/SystemUI/res/values-te/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"చిత్రంలో చిత్రం"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(శీర్షిక లేని ప్రోగ్రామ్)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIPని మూసివేయి"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"పూర్తి స్క్రీన్"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 76d2b8e..aaaae5f 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ปิด"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"ส่วนควบคุมการแจ้งเตือนแบบเปิด/ปิดช่วยให้คุณตั้งค่าระดับความสำคัญสำหรับการแจ้งเตือนของแอปได้ตั้งแต่ระดับ 0-5 \n\n"<b>"ระดับ 5"</b>" \n- แสดงที่ด้านบนของรายการแจ้งเตือน \n- อนุญาตให้รบกวนแบบเต็มหน้าจอ \n- อนุญาตให้แสดงชั่วครู่ \n\n"<b>"ระดับ 4"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- แสดงชั่วครู่เสมอ \n\n"<b>"ระดับ 3"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n\n"<b>"ระดับ 2"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n- ไม่ส่งเสียงหรือสั่นเลย \n\n"<b>"ระดับ 1"</b>" \n- ป้องกันการรบกวนแบบเต็มหน้าจอ \n- ไม่แสดงชั่วครู่เลย \n- ไม่ส่งเสียงหรือสั่นเลย \n- ซ่อนจากหน้าจอล็อกและแถบสถานะ \n- แสดงที่ด้านล่างของรายการแจ้งเตือน \n\n"<b>"ระดับ 0"</b>" \n- บล็อกการแจ้งเตือนทั้งหมดจากแอป"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"การแจ้งเตือน"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"คุณจะไม่ได้รับการแจ้งเตือนเหล่านี้อีก"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"คุณจะไม่ได้รับการแจ้งเตือนเหล่านี้อีก"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"หมวดหมู่การแจ้งเตือน <xliff:g id="NUMBER">%d</xliff:g> หมวด"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"แอปนี้ไม่มีหมวดหมู่การแจ้งเตือน"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-th/strings_tv.xml b/packages/SystemUI/res/values-th/strings_tv.xml
index 22bb321..3a5eba1 100644
--- a/packages/SystemUI/res/values-th/strings_tv.xml
+++ b/packages/SystemUI/res/values-th/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"การแสดงผลหลายแหล่งพร้อมกัน"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(ไม่มีชื่อรายการ)"</string>
<string name="pip_close" msgid="3480680679023423574">"ปิด PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"เต็มหน้าจอ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 5c4647e..12470c1 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Naka-off"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Sa pamamagitan ng mga kontrol sa notification ng power, magagawa mong itakda ang antas ng kahalagahan ng mga notification ng isang app mula 0 hanggang 5. \n\n"<b>"Antas 5"</b>" \n- Ipakita sa itaas ng listahan ng notification \n- Payagan ang pag-istorbo kapag full screen \n- Palaging sumilip \n\n"<b>"Antas 4"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Palaging sumilip \n\n"<b>"Antas 3"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n\n"<b>"Antas 2"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n- Huwag kailanman tumunog o mag-vibrate \n\n"<b>"Antas 1"</b>" \n- Pigilan ang pag-istorbo kapag full screen \n- Huwag kailanman sumilip \n- Huwag kailanman tumunog o mag-vibrate \n- Itago sa lock screen at status bar \n- Ipakita sa ibaba ng listahan ng notification \n\n"<b>"Antas 0"</b>" \n- I-block ang lahat ng notification mula sa app"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Mga Notification"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Hindi mo na matatanggap ang mga notification na ito."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Hindi ka na makakatanggap ng ganitong mga notification"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> (na) kategorya ng notification"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Walang kategorya ng notification ang app na ito"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-tl/strings_tv.xml b/packages/SystemUI/res/values-tl/strings_tv.xml
index 4d2f85a..8420c45 100644
--- a/packages/SystemUI/res/values-tl/strings_tv.xml
+++ b/packages/SystemUI/res/values-tl/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Picture-in-Picture"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Walang pamagat na programa)"</string>
<string name="pip_close" msgid="3480680679023423574">"Isara ang PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Full screen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7baae25..a9f6fb5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kapalı"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Güç bildirim kontrolleriyle, bir uygulamanın bildirimleri için 0 ile 5 arasında bir önem düzeyi ayarlayabilirsiniz. \n\n"<b>"5. Düzey"</b>" \n- Bildirim listesinin en üstünde gösterilsin \n- Tam ekran kesintisine izin verilsin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"4. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"3. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n\n"<b>"2. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman belirmesin \n- Hiçbir zaman ses çıkarmasın ve titreştirmesin \n\n"<b>"1. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n- Hiçbir zaman ses çıkarmasın veya titreştirmesin \n- Kilit ekranından ve durum çubuğundan gizlensin \n- Bildirim listesinin en altında gösterilsin \n\n"<b>"0. Düzey"</b>" \n- Uygulamadan gelen tüm bildirimler engellensin"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirimler"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirimleri artık almayacaksınız."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Bu bildirimleri artık almayacaksınız"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> bildirim kategorisi"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Bu uygulamanın bildirim kategorisi yok"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index 85b0269..ec2c784 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Ekran İçinde Ekran"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Başlıksız program)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP\'yi kapat"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Tam ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 54decf9..05896a5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -554,7 +554,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Вимк."</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"За допомогою елементів керування сповіщеннями ви можете налаштувати пріоритет сповіщень додатка – від 0 до 5 рівня. \n\n"<b>"Рівень 5"</b>\n"- Показувати сповіщення вгорі списку \n- Виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 4"</b>\n"- Не виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 3"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n\n"<b>"Рівень 2"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n\n"<b>"Рівень 1"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n- Не показувати на заблокованому екрані та в рядку стану \n- Показувати сповіщення внизу списку \n\n"<b>"Рівень 0"</b>\n"- Блокувати всі сповіщення з додатка"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Сповіщення"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ви більше не отримуватимете ці сповіщення."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ви більше не отримуватимете ці сповіщення"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"Категорії сповіщень (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"У цьому додатку немає категорій сповіщень"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-uk/strings_tv.xml b/packages/SystemUI/res/values-uk/strings_tv.xml
index f30155c..af96291 100644
--- a/packages/SystemUI/res/values-uk/strings_tv.xml
+++ b/packages/SystemUI/res/values-uk/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Картинка в картинці"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Програма без назви)"</string>
<string name="pip_close" msgid="3480680679023423574">"Закрити PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"На весь екран"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 06e99a1..a388478 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"آف"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"پاور اطلاع کنٹرولز کے ساتھ آپ کسی ایپ کی اطلاعات کیلئے 0 سے 5 تک اہمیت کی سطح سیٹ کر سکتے ہیں۔ \n\n"<b>"سطح 5"</b>\n"- اطلاعات کی فہرست کے اوپر دکھائیں \n- پوری اسکرین کی مداخلت کی اجازت دیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 4"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 3"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n\n"<b>"سطح 2"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n- کبھی آواز اور ارتعاش پیدا نہ کرنا \n\n"<b>" سطح 1"</b>\n"- پوری اسکرین کی مداخلت کو روکنا \n- کبھی نہ جھانکنا \n- کبھی بھی آواز یا ارتعاش پیدا نہ کرنا\n- مقفل اسکرین اور اسٹیٹس بار سے چھپانا \n - اطلاع کی فہرست کی نیچے دکھانا \n\n"<b>"سطح 0"</b>\n"- ایپ سے تمام اطلاعات مسدود کریں"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"اطلاعات"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"آپ کو یہ اطلاعات مزید نہیں ملیں گی۔"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"آپ کو یہ اطلاعات مزید نہیں ملیں گی"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"اطلاع کے <xliff:g id="NUMBER">%d</xliff:g> زمرے"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"اس ایپ میں اطلاعاتی زمرے نہیں ہیں"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-ur/strings_tv.xml b/packages/SystemUI/res/values-ur/strings_tv.xml
index 0dec84c..b547bee 100644
--- a/packages/SystemUI/res/values-ur/strings_tv.xml
+++ b/packages/SystemUI/res/values-ur/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"تصویر میں تصویر"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(بلا عنوان پروگرام)"</string>
<string name="pip_close" msgid="3480680679023423574">"PIP بند کریں"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"فُل اسکرین"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 658aeea..451d1de 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"O‘chiq"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Bildirishnomalar uchun kengaytirilgan boshqaruv yordamida ilova bildirishnomalarining muhimlik darajasini (0-5) sozlash mumkin. \n\n"<b>"5-daraja"</b>" \n- Bildirishnomani ro‘yxatning boshida ko‘rsatish \n- To‘liq ekranli bildirishnomalarni ko‘rsatish \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"4-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"3-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n\n"<b>"2-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n\n"<b>"1-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n- Ekran qulfi va holat qatorida ko‘rsatmaslik \n- Bildirishnomani ro‘yxatning oxirida ko‘rsatish \n\n"<b>"0-daraja"</b>" \n- Ilovadan keladigan barcha bildirishnomalarni bloklash"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirishnomalar"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ushbu bildirishnomalar endi ko‘rsatilmaydi."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ushbu bildirishnomalar endi ko‘rsatilmaydi"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> ta bildirishnoma turkumi"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Bu ilovada bildirishnomalar turkumi yo‘q"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-uz/strings_tv.xml b/packages/SystemUI/res/values-uz/strings_tv.xml
index efa894a..dc1e1452 100644
--- a/packages/SystemUI/res/values-uz/strings_tv.xml
+++ b/packages/SystemUI/res/values-uz/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Tasvir ustida tasvir"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Nomsiz)"</string>
<string name="pip_close" msgid="3480680679023423574">"Kadr ichida kadr – chiqish"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"To‘liq ekran"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e4959fe..0b23a6f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Tắt"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Với các kiểm soát thông báo nguồn, bạn có thể đặt cấp độ quan trọng từ 0 đến 5 cho các thông báo của ứng dụng. \n\n"<b>"Cấp 5"</b>" \n- Hiển thị ở đầu danh sách thông báo \n- Cho phép gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 4"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 3"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n\n"<b>"Cấp 2"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n\n"<b>"Cấp 1"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n- Ẩn khỏi màn hình khóa và thanh trạng thái \n- Hiển thị ở cuối danh sách thông báo \n\n"<b>"Cấp 0"</b>" \n- Chặn tất cả các thông báo từ ứng dụng"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Thông báo"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Bạn sẽ không nhận được những thông báo này nữa."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Bạn sẽ không nhận được những thông báo này nữa"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> danh mục thông báo"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Ứng dụng này không có loại thông báo"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-vi/strings_tv.xml b/packages/SystemUI/res/values-vi/strings_tv.xml
index 17afa0d..31a1428 100644
--- a/packages/SystemUI/res/values-vi/strings_tv.xml
+++ b/packages/SystemUI/res/values-vi/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Ảnh trong ảnh"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Không có chương trình tiêu đề)"</string>
<string name="pip_close" msgid="3480680679023423574">"Đóng PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Toàn màn hình"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 96c81c0..e56486c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"关闭"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"利用高级通知设置,您可以为应用通知设置从 0 级到 5 级的重要程度等级。\n\n"<b>"5 级"</b>" \n- 在通知列表顶部显示 \n- 允许全屏打扰 \n- 一律短暂显示通知 \n\n"<b>"4 级"</b>" \n- 禁止全屏打扰 \n- 一律短暂显示通知 \n\n"<b>"3 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n\n"<b>"2 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n- 一律不发出声音或振动 \n\n"<b>"1 级"</b>" \n- 禁止全屏打扰 \n- 一律不短暂显示通知 \n- 一律不发出声音或振动 \n- 不在锁定屏幕和状态栏中显示 \n- 在通知列表底部显示 \n\n"<b>"0 级"</b>" \n- 屏蔽应用的所有通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"您将不会再收到这类通知。"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"您将不会再收到这类通知"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 个通知类别"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"此应用没有通知类别"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
index 7b1136f..577186b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"画中画"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(节目没有标题)"</string>
<string name="pip_close" msgid="3480680679023423574">"关闭画中画"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"全屏"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index af7f769..8b37751 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -22,7 +22,7 @@
<string name="app_label" msgid="7164937344850004466">"系統使用者介面"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"從清單中移除"</string>
- <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資訊"</string>
+ <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"應用程式資料"</string>
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"您最近的螢幕顯示在這裡"</string>
<string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"關閉最近使用的應用程式"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
@@ -200,7 +200,7 @@
<string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"飛行模式已開啟。"</string>
<string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"飛行模式已關閉。"</string>
<string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飛行模式已開啟。"</string>
- <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"開啟「請勿騷擾」,僅限優先。"</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"開啟「請勿騷擾」,只限優先。"</string>
<string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"開啟「請勿騷擾」,完全靜音。"</string>
<string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"開啟「請勿騷擾」,只限鬧鐘。"</string>
<string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"請勿騷擾。"</string>
@@ -269,7 +269,7 @@
<string name="start_dreams" msgid="5640361424498338327">"螢幕保護程式"</string>
<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_priority_label" msgid="483232950670692036">"只限優先"</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>
@@ -369,7 +369,7 @@
<string name="camera_hint" msgid="7939688436797157483">"從圖示快速滑動即可使用相機功能"</string>
<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_priority" msgid="6426766465363855505">"只限優先"</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>
@@ -550,7 +550,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"通知控制項讓您設定應用程式通知的重要性 (0 至 5 級)。\n\n"<b>"第 5 級"</b>" \n- 在通知清單頂部顯示 \n- 允許全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 4 級"</b>" \n- 阻止全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 3 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n\n"<b>"第 2 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n\n"<b>"第 1 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n- 從上鎖畫面和狀態列中隱藏 \n- 在通知清單底部顯示 \n\n"<b>"第 0 級"</b>" \n- 封鎖所有應用程式通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"您不會再收到這些通知。"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"您不會再收到這些通知"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 個通知類別"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"此應用程式沒有通知類別"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index 13eab22..953d6e4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"畫中畫"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(沒有標題的節目)"</string>
<string name="pip_close" msgid="3480680679023423574">"關閉 PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"全螢幕"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 1559d07..0c13b71 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"只要使用電源通知控制項,你就能為應用程式通知設定從 0 到 5 的重要性等級。\n\n"<b>"等級 5"</b>" \n- 顯示在通知清單頂端 \n- 允許全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 4"</b>" \n- 禁止全螢幕通知 \n- 一律允許短暫顯示通知 \n\n"<b>"等級 3"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n\n"<b>"等級 2"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n\n"<b>"等級 1"</b>" \n- 禁止全螢幕通知 \n- 一律不允許短暫顯示通知 \n- 一律不發出音效或震動 \n- 在鎖定畫面和狀態列中隱藏 \n- 顯示在通知清單底端 \n\n"<b>"等級 0"</b>" \n- 封鎖應用程式的所有通知"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"你不會再收到這類通知。"</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"你不會再收到這類通知"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> 個通知類別"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"這個應用程式沒有通知類別"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
index 9634ada..faa9484 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"子母畫面"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(無標題的節目)"</string>
<string name="pip_close" msgid="3480680679023423574">"關閉子母畫面"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"全螢幕"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 3f0dde6..4851163 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -548,7 +548,7 @@
<string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Valiwe"</string>
<string name="power_notification_controls_description" msgid="4372459941671353358">"Ngezilawuli zesaziso zamandla, ungasetha ileveli ebalulekile kusuka ku-0 kuya ku-5 kusuka kuzaziso zohlelo lokusebenza. \n\n"<b>"Ileveli 5"</b>" \n- Ibonisa phezulu kuhlu lwesaziso \n- Vumela ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 4"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 3"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n\n"<b>"Ileveli 2"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo nokudlidliza \n\n"<b>"Ileveli 1"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo noma ukudlidliza \n- Fihla kusuka kusikrini sokukhiya nebha yesimo \n- Bonisa phansi kohlu lwesaziso \n\n"<b>"Ileveli 0"</b>" \n- Vimbela zonke izaziso kusuka kuhlelo lokusebenza"</string>
<string name="notification_header_default_channel" msgid="7506845022070889909">"Izaziso"</string>
- <string name="notification_channel_disabled" msgid="5805874247999578073">"Ngeke usathola lezi zaziso."</string>
+ <string name="notification_channel_disabled" msgid="2139193533791840539">"Ngeke usathola izaziso"</string>
<string name="notification_num_channels" msgid="2048144408999179471">"<xliff:g id="NUMBER">%d</xliff:g> izigaba zesaziso"</string>
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Lolu hlelo lokusebenza alunazo izigaba zesaziso"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
diff --git a/packages/SystemUI/res/values-zu/strings_tv.xml b/packages/SystemUI/res/values-zu/strings_tv.xml
index 827ec70..26155e4 100644
--- a/packages/SystemUI/res/values-zu/strings_tv.xml
+++ b/packages/SystemUI/res/values-zu/strings_tv.xml
@@ -19,6 +19,8 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="notification_channel_tv_pip" msgid="134047986446577723">"Isithombe-esithombeni"</string>
+ <string name="pip_notification_unknown_title" msgid="6289156118095849438">"(Alukho uhlelo lwesihloko)"</string>
<string name="pip_close" msgid="3480680679023423574">"Vala i-PIP"</string>
<string name="pip_fullscreen" msgid="8604643018538487816">"Iskrini esigcwele"</string>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index a57b17e..ce57bf9 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -124,9 +124,8 @@
<declare-styleable name="PluginInflateContainer">
<attr name="viewType" format="string" />
</declare-styleable>
- <declare-styleable name="ScrimView">
- <!-- The initial color for the scrim. -->
- <attr name="scrimColor" format="color" />
- </declare-styleable>
+
+ <attr name="lightIconTheme" format="reference" />
+ <attr name="darkIconTheme" format="reference" />
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 8896e6f..3ef28bd 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -32,7 +32,6 @@
<color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
<color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white -->
<color name="qs_detail_transition">#66FFFFFF</color>
- <color name="scrim_behind_color">@android:color/black</color>
<color name="status_bar_clock_color">#FFFFFFFF</color>
<color name="qs_user_detail_icon_muted">#FFFFFFFF</color> <!-- not so muted after all -->
<color name="qs_tile_disabled_color">#9E9E9E</color> <!-- 38% black -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 97e180c..99c6227 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -792,7 +792,7 @@
<!-- The bottom margin of the expand container when there are actions.
Equal to pip_action_size - pip_action_padding. -->
- <dimen name="pip_expand_container_edge_margin">36dp</dimen>
+ <dimen name="pip_expand_container_edge_margin">30dp</dimen>
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 66476d13..0d777f6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1195,6 +1195,9 @@
<!-- Indication on the keyguard that appears when a trust agents unlocks the device. [CHAR LIMIT=40] -->
<string name="keyguard_indication_trust_granted">Unlocked for <xliff:g id="user_name" example="John Doe">%1$s</xliff:g></string>
+ <!-- Indication on the keyguard that appears when a trust agent is active and available. [CHAR LIMIT=40] -->
+ <string name="keyguard_indication_trust_managed"><xliff:g id="trust_agent" example="Smart Lock">%1$s</xliff:g> is running</string>
+
<!-- Indication on the keyguard that appears when the user disables trust agents until the next time they unlock manually. [CHAR LIMIT=NONE] -->
<string name="keyguard_indication_trust_disabled">Device will stay locked until you manually unlock</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9650cea..44da876 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -290,7 +290,14 @@
<style name="Animation.StatusBar">
</style>
- <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+ <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+ <item name="lightIconTheme">@style/DualToneLightTheme</item>
+ <item name="darkIconTheme">@style/DualToneDarkTheme</item>
+ </style>
+ <style name="qs_theme" parent="systemui_theme">
+ <item name="lightIconTheme">@style/QSIconTheme</item>
+ <item name="darkIconTheme">@style/QSIconTheme</item>
+ </style>
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:colorAccent">@color/remote_input_accent</item>
@@ -346,6 +353,11 @@
<item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
<item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
</style>
+ <style name="QSIconTheme">
+ <item name="backgroundColor">?android:attr/textColorHint</item>
+ <item name="fillColor">?android:attr/textColorPrimary</item>
+ <item name="singleToneColor">?android:attr/textColorPrimary</item>
+ </style>
<style name="TextAppearance.Volume">
<item name="android:textStyle">normal</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 47290ec..e7acbb3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -164,7 +164,7 @@
private int mRingMode;
private int mPhoneState;
private boolean mKeyguardIsVisible;
-
+ private boolean mKeyguardGoingAway;
private boolean mGoingToSleep;
private boolean mBouncer;
private boolean mBootCompleted;
@@ -412,6 +412,14 @@
}
}
+ /**
+ * Updates KeyguardUpdateMonitor's internal state to know if keyguard is goingAway
+ * @param goingAway
+ */
+ public void setKeyguardGoingAway(boolean goingAway) {
+ mKeyguardGoingAway = goingAway;
+ }
+
private void onFingerprintAuthenticated(int userId) {
Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated");
mUserFingerprintAuthenticated.put(userId, true);
@@ -512,6 +520,12 @@
}
}
+ if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+ mLockPatternUtils.requireStrongAuth(
+ LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ getCurrentUser());
+ }
+
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1117,7 +1131,8 @@
}
private boolean shouldListenForFingerprint() {
- return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer || mGoingToSleep)
+ return (mKeyguardIsVisible || !mDeviceInteractive ||
+ (mBouncer && !mKeyguardGoingAway) || mGoingToSleep)
&& (!mSwitchingUser && !isFingerprintDisabled(getCurrentUser()) ||
mEnableNextFingerprint);
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 911ef24..9dd39d4 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,25 +17,28 @@
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.TypedValue;
import android.database.ContentObserver;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
-
import android.widget.TextView;
+
+import com.android.settingslib.Utils;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -63,6 +66,12 @@
private int mLevel;
private boolean mForceShowPercent;
+ private int mDarkModeBackgroundColor;
+ private int mDarkModeFillColor;
+
+ private int mLightModeBackgroundColor;
+ private int mLightModeFillColor;
+
public BatteryMeterView(Context context) {
this(context, null, 0);
}
@@ -98,6 +107,16 @@
addView(mBatteryIconView, mlp);
updateShowPercent();
+
+ Context dualToneDarkTheme = new ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.darkIconTheme));
+ Context dualToneLightTheme = new ContextThemeWrapper(context,
+ Utils.getThemeAttr(context, R.attr.lightIconTheme));
+ mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
+ mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
+ mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
+ mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
+
// Init to not dark at all.
onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
}
@@ -107,11 +126,6 @@
updateShowPercent();
}
- // StatusBarIconController reaches in here and adjusts the layout parameters of the icon
- public ImageView getBatteryIconView() {
- return mBatteryIconView;
- }
-
@Override
public boolean hasOverlappingRendering() {
return false;
@@ -170,7 +184,7 @@
private void updatePercentText() {
if (mBatteryPercentView != null) {
mBatteryPercentView.setText(
- NumberFormat.getPercentInstance().format(mLevel/100f));
+ NumberFormat.getPercentInstance().format(mLevel / 100f));
}
}
@@ -224,8 +238,13 @@
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
- mDrawable.setDarkIntensity(DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0);
- setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+ float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+ int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
+ mDarkModeFillColor);
+ int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
+ mDarkModeBackgroundColor);
+ mDrawable.setColors(foreground, background);
+ setTextColor(foreground);
}
public void setTextColor(int color) {
@@ -235,8 +254,8 @@
}
}
- public void setRawColors(int fgColor, int bgColor) {
- mDrawable.setColors(fgColor, bgColor);
+ private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+ return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
}
private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 79db544..5197c95 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -272,6 +272,8 @@
mProviders.put(TunablePaddingService.class, () -> new TunablePaddingService());
+ mProviders.put(UiOffloadThread.class, UiOffloadThread::new);
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 9b74cd6..cdad8ae 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -23,7 +23,7 @@
public interface RecentsComponent {
void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
- void toggleRecents(Display display);
+ void toggleRecents();
void preloadRecents();
void showNextAffiliatedTask();
void showPrevAffiliatedTask();
diff --git a/packages/SystemUI/src/com/android/systemui/UiOffloadThread.java b/packages/SystemUI/src/com/android/systemui/UiOffloadThread.java
new file mode 100644
index 0000000..82fd9b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/UiOffloadThread.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * Thread that offloads work from the UI thread but that is still perceptible to the user, so the
+ * priority is the same as the main thread.
+ */
+public class UiOffloadThread {
+
+ private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
+
+ public Future<?> submit(Runnable runnable) {
+ return mExecutorService.submit(runnable);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 1abea37..a129ace 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -30,7 +30,10 @@
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.systemui.Dependency;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.analytics.DataCollector;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.StatusBarState;
import java.io.PrintWriter;
@@ -63,6 +66,7 @@
private final DataCollector mDataCollector;
private final HumanInteractionClassifier mHumanInteractionClassifier;
private final AccessibilityManager mAccessibilityManager;
+ private final UiOffloadThread mUiOffloadThread;
private static FalsingManager sInstance = null;
@@ -86,6 +90,7 @@
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
mDataCollector = DataCollector.getInstance(mContext);
mHumanInteractionClassifier = HumanInteractionClassifier.getInstance(mContext);
+ mUiOffloadThread = Dependency.get(UiOffloadThread.class);
mScreenOn = context.getSystemService(PowerManager.class).isInteractive();
mContext.getContentResolver().registerContentObserver(
@@ -130,7 +135,11 @@
private void sessionExitpoint(boolean force) {
if (mSessionActive && (force || !shouldSessionBeActive())) {
mSessionActive = false;
- mSensorManager.unregisterListener(this);
+
+ // This can be expensive, and doesn't need to happen on the main thread.
+ mUiOffloadThread.submit(() -> {
+ mSensorManager.unregisterListener(this);
+ });
}
}
@@ -154,7 +163,11 @@
for (int sensorType : sensors) {
Sensor s = mSensorManager.getDefaultSensor(sensorType);
if (s != null) {
- mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
+
+ // This can be expensive, and doesn't need to happen on the main thread.
+ mUiOffloadThread.submit(() -> {
+ mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
+ });
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index d61ac21..cf87fca 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -130,6 +130,7 @@
}
verifyLastTimeTick();
mAlarmManager.cancel(mTimeTick);
+ mTimeTickScheduled = false;
}
private void verifyLastTimeTick() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
index 262d29d..745f312 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/DismissCallbackRegistry.java
@@ -17,6 +17,10 @@
package com.android.systemui.keyguard;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.systemui.Dependency;
+import com.android.systemui.UiOffloadThread;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import java.util.ArrayList;
@@ -26,6 +30,7 @@
public class DismissCallbackRegistry {
private final ArrayList<DismissCallbackWrapper> mDismissCallbacks = new ArrayList<>();
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
public void addCallback(IKeyguardDismissCallback callback) {
mDismissCallbacks.add(new DismissCallbackWrapper(callback));
@@ -33,14 +38,16 @@
public void notifyDismissCancelled() {
for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
- mDismissCallbacks.get(i).notifyDismissCancelled();
+ DismissCallbackWrapper callback = mDismissCallbacks.get(i);
+ mUiOffloadThread.submit(callback::notifyDismissCancelled);
}
mDismissCallbacks.clear();
}
public void notifyDismissSucceeded() {
for (int i = mDismissCallbacks.size() - 1; i >= 0; i--) {
- mDismissCallbacks.get(i).notifyDismissSucceeded();
+ DismissCallbackWrapper callback = mDismissCallbacks.get(i);
+ mUiOffloadThread.submit(callback::notifyDismissSucceeded);
}
mDismissCallbacks.clear();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 2504e36..b977dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -51,6 +51,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.System;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.EventLog;
@@ -76,9 +77,13 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.phone.FingerprintUnlockController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -162,6 +167,7 @@
private static final int NOTIFY_SCREEN_TURNED_ON = 15;
private static final int NOTIFY_SCREEN_TURNED_OFF = 16;
private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 17;
+ private static final int SET_SWITCHING_USER = 18;
/**
* The default amount of time we stay awake (used for all key input)
@@ -194,6 +200,7 @@
private AlarmManager mAlarmManager;
private AudioManager mAudioManager;
private StatusBarManager mStatusBarManager;
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
private boolean mSystemReady;
private boolean mBootCompleted;
@@ -1198,18 +1205,20 @@
updateInputRestrictedLocked();
}
}
+
private void updateInputRestrictedLocked() {
boolean inputRestricted = isInputRestricted();
if (mInputRestricted != inputRestricted) {
mInputRestricted = inputRestricted;
int size = mKeyguardStateCallbacks.size();
for (int i = size - 1; i >= 0; i--) {
+ final IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
try {
- mKeyguardStateCallbacks.get(i).onInputRestrictedStateChanged(inputRestricted);
+ callback.onInputRestrictedStateChanged(inputRestricted);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onDeviceProvisioned", e);
if (e instanceof DeadObjectException) {
- mKeyguardStateCallbacks.remove(i);
+ mKeyguardStateCallbacks.remove(callback);
}
}
}
@@ -1398,7 +1407,11 @@
}
public void setSwitchingUser(boolean switching) {
- KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(switching);
+ Trace.beginSection("KeyguardViewMediator#setSwitchingUser");
+ mHandler.removeMessages(SET_SWITCHING_USER);
+ Message msg = mHandler.obtainMessage(SET_SWITCHING_USER, switching ? 1 : 0, 0);
+ mHandler.sendMessage(msg);
+ Trace.endSection();
}
/**
@@ -1538,6 +1551,11 @@
Log.w(TAG, "Timeout while waiting for activity drawn!");
Trace.endSection();
break;
+ case SET_SWITCHING_USER:
+ Trace.beginSection("KeyguardViewMediator#handleMessage SET_SWITCHING_USER");
+ KeyguardUpdateMonitor.getInstance(mContext).setSwitchingUser(msg.arg1 != 0);
+ Trace.endSection();
+ break;
}
}
};
@@ -1559,9 +1577,11 @@
private void handleKeyguardDone() {
Trace.beginSection("KeyguardViewMediator#handleKeyguardDone");
final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
- if (mLockPatternUtils.isSecure(currentUser)) {
- mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
- }
+ mUiOffloadThread.submit(() -> {
+ if (mLockPatternUtils.isSecure(currentUser)) {
+ mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
+ }
+ });
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
synchronized (this) {
resetKeyguardDonePendingLocked();
@@ -1601,10 +1621,12 @@
final UserHandle currentUser = new UserHandle(currentUserId);
final UserManager um = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
- for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
- mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
- }
- getLockPatternUtils().userPresent(currentUserId);
+ mUiOffloadThread.submit(() -> {
+ for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
+ mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
+ }
+ getLockPatternUtils().userPresent(currentUserId);
+ });
} else {
mBootSendUserPresent = true;
}
@@ -1649,11 +1671,18 @@
if (mAudioManager == null) return;
mUiSoundsStreamType = mAudioManager.getUiSoundsStreamType();
}
- // If the stream is muted, don't play the sound
- if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
- mLockSoundStreamId = mLockSounds.play(soundId,
- mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
+ mUiOffloadThread.submit(() -> {
+ // If the stream is muted, don't play the sound
+ if (mAudioManager.isStreamMute(mUiSoundsStreamType)) return;
+
+ int id = mLockSounds.play(soundId,
+ mLockSoundVolume, mLockSoundVolume, 1/*priortiy*/, 0/*loop*/, 1.0f/*rate*/);
+ synchronized (this) {
+ mLockSoundStreamId = id;
+ }
+ });
+
}
}
@@ -1661,13 +1690,13 @@
playSound(mTrustedSoundId);
}
- private void updateActivityLockScreenState() {
- Trace.beginSection("KeyguardViewMediator#updateActivityLockScreenState");
- try {
- ActivityManager.getService().setLockScreenShown(mShowing);
- } catch (RemoteException e) {
- }
- Trace.endSection();
+ private void updateActivityLockScreenState(boolean showing) {
+ mUiOffloadThread.submit(() -> {
+ try {
+ ActivityManager.getService().setLockScreenShown(showing);
+ } catch (RemoteException e) {
+ }
+ });
}
/**
@@ -1696,7 +1725,6 @@
mHideAnimationRun = false;
adjustStatusBarLocked();
userActivity();
-
mShowKeyguardWakeLock.release();
}
mKeyguardDisplayManager.show();
@@ -1723,6 +1751,7 @@
flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
}
+ mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);
// Don't actually hide the Keyguard at the moment, wait for window
// manager until it tells us it's safe to do so with
// startKeyguardExitAnimation.
@@ -1798,12 +1827,13 @@
mWakeAndUnlocking = false;
setShowingLocked(false);
+ mDismissCallbackRegistry.notifyDismissSucceeded();
mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
- mDismissCallbackRegistry.notifyDismissSucceeded();
sendUserPresentBroadcast();
+ mUpdateMonitor.setKeyguardGoingAway(false /* goingAway */);
}
Trace.endSection();
}
@@ -1835,7 +1865,10 @@
}
if (!(mContext instanceof Activity)) {
- mStatusBarManager.disable(flags);
+ final int finalFlags = flags;
+ mUiOffloadThread.submit(() -> {
+ mStatusBarManager.disable(finalFlags);
+ });
}
}
}
@@ -2033,18 +2066,21 @@
mShowing = showing;
int size = mKeyguardStateCallbacks.size();
for (int i = size - 1; i >= 0; i--) {
+ IKeyguardStateCallback callback = mKeyguardStateCallbacks.get(i);
try {
- mKeyguardStateCallbacks.get(i).onShowingStateChanged(showing);
+ callback.onShowingStateChanged(showing);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to call onShowingStateChanged", e);
if (e instanceof DeadObjectException) {
- mKeyguardStateCallbacks.remove(i);
+ mKeyguardStateCallbacks.remove(callback);
}
}
}
updateInputRestrictedLocked();
- mTrustManager.reportKeyguardShowingChanged();
- updateActivityLockScreenState();
+ mUiOffloadThread.submit(() -> {
+ mTrustManager.reportKeyguardShowingChanged();
+ });
+ updateActivityLockScreenState(showing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 5eb483d..f198229 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -64,7 +64,7 @@
options.setTaskOverlay(true, false /* canResume */);
final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT);
- if (result >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(result)) {
// OK
} else {
// Starting the activity inside the task failed. We can't be sure why, so to be
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index da2d38f..0da4681 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,9 +16,11 @@
package com.android.systemui.pip.phone;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -33,6 +35,8 @@
import android.view.WindowManagerGlobal;
import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.ExpandPipEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.CommandQueue;
@@ -65,7 +69,7 @@
*/
TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
- public void onActivityPinned(String packageName) {
+ public void onActivityPinned(String packageName, int taskId) {
if (!checkCurrentUserId(false /* debug */)) {
return;
}
@@ -186,6 +190,7 @@
mInputConsumerController);
mNotificationController = new PipNotificationController(context, mActivityManager,
mTouchHandler.getMotionHelper());
+ EventBus.getDefault().register(this);
}
/**
@@ -196,6 +201,26 @@
}
/**
+ * Expands the PIP.
+ */
+ public final void onBusEvent(ExpandPipEvent event) {
+ if (event.clearThumbnailWindows) {
+ try {
+ StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
+ if (stackInfo != null && stackInfo.taskIds != null) {
+ SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
+ for (int taskId : stackInfo.taskIds) {
+ ssp.cancelThumbnailTransition(taskId);
+ }
+ }
+ } catch (RemoteException e) {
+ // Do nothing
+ }
+ }
+ mTouchHandler.getMotionHelper().expandPip(false /* skipAnimation */);
+ }
+
+ /**
* Sent from KEYCODE_WINDOW handler in PhoneWindowManager, to request the menu to be shown.
*/
public void showPictureInPictureMenu() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 65f24cf..013b9ac 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -63,6 +63,8 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.HidePipMenuEvent;
import java.util.ArrayList;
import java.util.Collections;
@@ -221,9 +223,9 @@
protected void onUserLeaveHint() {
super.onUserLeaveHint();
- // If another task is starting on top of the menu, then finish it so that it can be
+ // If another task is starting on top of the menu, then hide and finish it so that it can be
// recreated on the top next time it starts
- finish();
+ hideMenu();
}
@Override
@@ -231,6 +233,7 @@
super.onStop();
cancelDelayedFinish();
+ EventBus.getDefault().unregister(this);
}
@Override
@@ -290,6 +293,19 @@
// Do nothing
}
+ public final void onBusEvent(HidePipMenuEvent event) {
+ if (mMenuState != MENU_STATE_NONE) {
+ // If the menu is visible in either the closed or full state, then hide the menu and
+ // trigger the animation trigger afterwards
+ event.getAnimationTrigger().increment();
+ hideMenu(() -> {
+ mHandler.post(() -> {
+ event.getAnimationTrigger().decrement();
+ });
+ }, true /* notifyMenuVisibility */);
+ }
+ }
+
private void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
boolean allowMenuTimeout) {
mAllowMenuTimeout = allowMenuTimeout;
@@ -303,7 +319,6 @@
mMenuContainerAnimator.cancel();
}
notifyMenuStateChange(menuState);
- updateExpandButtonFromBounds(stackBounds, movementBounds);
mMenuContainerAnimator = new AnimatorSet();
ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
mMenuContainer.getAlpha(), 1f);
@@ -374,11 +389,16 @@
private void updateFromIntent(Intent intent) {
mToControllerMessenger = intent.getParcelableExtra(EXTRA_CONTROLLER_MESSENGER);
notifyActivityCallback(mMessenger);
+
+ // Register for HidePipMenuEvents once we notify the controller of this activity
+ EventBus.getDefault().register(this);
+
ParceledListSlice actions = intent.getParcelableExtra(EXTRA_ACTIONS);
if (actions != null) {
mActions.clear();
mActions.addAll(actions.getList());
}
+
final int menuState = intent.getIntExtra(EXTRA_MENU_STATE, MENU_STATE_NONE);
if (menuState != MENU_STATE_NONE) {
Rect stackBounds = intent.getParcelableExtra(EXTRA_STACK_BOUNDS);
@@ -388,24 +408,6 @@
}
}
- private void updateExpandButtonFromBounds(Rect stackBounds, Rect movementBounds) {
- if (stackBounds == null) {
- return;
- }
-
- boolean isLandscapePip = stackBounds.width() > stackBounds.height();
- boolean left = stackBounds.left < movementBounds.centerX();
- boolean top = stackBounds.top < movementBounds.centerY();
- boolean expandL = (left && top) || (!left && !top);
- int iconResId;
- if (isLandscapePip) {
- iconResId = expandL ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
- } else {
- iconResId = expandL ? R.drawable.pip_expand_pl : R.drawable.pip_expand_pr;
- }
- mExpandButton.setImageResource(iconResId);
- }
-
private void setActions(Rect stackBounds, List<RemoteAction> actions) {
mActions.clear();
mActions.addAll(actions);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 5afa53f..e310847 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -27,6 +27,7 @@
import android.content.pm.ParceledListSlice;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
@@ -36,6 +37,9 @@
import android.view.IWindowManager;
import com.android.systemui.pip.phone.PipMediaController.ActionListener;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.HidePipMenuEvent;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -119,6 +123,7 @@
// The dismiss fraction update is sent frequently, so use a temporary bundle for the message
private Bundle mTmpDismissFractionData = new Bundle();
+ private ReferenceCountedTrigger mOnAttachDecrementTrigger;
private boolean mStartActivityRequested;
private Messenger mToActivityMessenger;
private Messenger mMessenger = new Messenger(new Handler() {
@@ -157,6 +162,10 @@
case MESSAGE_UPDATE_ACTIVITY_CALLBACK: {
mToActivityMessenger = msg.replyTo;
mStartActivityRequested = false;
+ if (mOnAttachDecrementTrigger != null) {
+ mOnAttachDecrementTrigger.decrement();
+ mOnAttachDecrementTrigger = null;
+ }
// Mark the menu as invisible once the activity finishes as well
if (mToActivityMessenger == null) {
onMenuStateChanged(MENU_STATE_NONE, true /* resize */);
@@ -181,6 +190,8 @@
mActivityManager = activityManager;
mMediaController = mediaController;
mInputConsumerController = inputConsumerController;
+
+ EventBus.getDefault().register(this);
}
public void onActivityPinned() {
@@ -244,7 +255,9 @@
public void showMenu(int menuState, Rect stackBounds, Rect movementBounds,
boolean allowMenuTimeout) {
if (DEBUG) {
- Log.d(TAG, "showMenu() hasActivity=" + (mToActivityMessenger != null));
+ Log.d(TAG, "showMenu() state=" + menuState
+ + " hasActivity=" + (mToActivityMessenger != null)
+ + " callers=\n" + Debug.getCallers(5, " "));
}
if (mToActivityMessenger != null) {
Bundle data = new Bundle();
@@ -288,7 +301,9 @@
*/
public void hideMenu() {
if (DEBUG) {
- Log.d(TAG, "hideMenu() hasActivity=" + (mToActivityMessenger != null));
+ Log.d(TAG, "hideMenu() state=" + mMenuState
+ + " hasActivity=" + (mToActivityMessenger != null)
+ + " callers=\n" + Debug.getCallers(5, " "));
}
if (mToActivityMessenger != null) {
Message m = Message.obtain();
@@ -311,13 +326,6 @@
}
/**
- * @return the current menu state.
- */
- public int getMenuState() {
- return mMenuState;
- }
-
- /**
* Sets the menu actions to the actions provided by the current PiP activity.
*/
public void setAppActions(ParceledListSlice appActions) {
@@ -435,6 +443,15 @@
mMenuState = menuState;
}
+ public final void onBusEvent(HidePipMenuEvent event) {
+ if (mStartActivityRequested) {
+ // If the menu has been start-requested, but not actually started, then we defer the
+ // trigger callback until the menu has started and called back to the controller
+ mOnAttachDecrementTrigger = event.getAnimationTrigger();
+ mOnAttachDecrementTrigger.increment();
+ }
+ }
+
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 590e3c6..9fa7ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -34,6 +34,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
@@ -54,6 +55,7 @@
public class PipMotionHelper {
private static final String TAG = "PipMotionHelper";
+ private static final boolean DEBUG = false;
private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
@@ -150,6 +152,10 @@
* Resizes the pinned stack back to fullscreen.
*/
void expandPip(boolean skipAnimation) {
+ if (DEBUG) {
+ Log.d(TAG, "expandPip: skipAnimation=" + skipAnimation
+ + " callers=\n" + Debug.getCallers(5, " "));
+ }
cancelAnimations();
mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
@@ -171,6 +177,9 @@
* Dismisses the pinned stack.
*/
void dismissPip() {
+ if (DEBUG) {
+ Log.d(TAG, "dismissPip: callers=\n" + Debug.getCallers(5, " "));
+ }
cancelAnimations();
mMenuController.hideMenuWithoutResize();
mHandler.post(() -> {
@@ -419,6 +428,10 @@
* Directly resizes the PiP to the given {@param bounds}.
*/
private void resizePipUnchecked(Rect toBounds) {
+ if (DEBUG) {
+ Log.d(TAG, "resizePipUnchecked: toBounds=" + toBounds
+ + " callers=\n" + Debug.getCallers(5, " "));
+ }
if (!toBounds.equals(mBounds)) {
mVsyncChoreographer.scheduleAtSfVsync(() -> {
try {
@@ -435,6 +448,10 @@
* Directly resizes the PiP to the given {@param bounds}.
*/
private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) {
+ if (DEBUG) {
+ Log.d(TAG, "resizeAndAnimatePipUnchecked: toBounds=" + toBounds
+ + " duration=" + duration + " callers=\n" + Debug.getCallers(5, " "));
+ }
if (!toBounds.equals(mBounds)) {
mHandler.post(() -> {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 199b027..c35fdd5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -484,14 +484,15 @@
// Try and restore the PiP to the closest edge, using the saved snap fraction
// if possible
if (resize) {
- // This is a very special case: when the menu is expanded and visible, navigating to
- // another activity can trigger auto-enter PiP, and if the revealed activity has a
- // forced rotation set, then the controller will get updated with the new rotation
- // of the display. However, at the same time, SystemUI will try to hide the menu by
- // creating an animation to the normal bounds which are now stale. In such a case
- // we defer the animation to the normal bounds until after the next
- // onMovementBoundsChanged() call to get the bounds in the new orientation
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
+ // This is a very special case: when the menu is expanded and visible,
+ // navigating to another activity can trigger auto-enter PiP, and if the
+ // revealed activity has a forced rotation set, then the controller will get
+ // updated with the new rotation of the display. However, at the same time,
+ // SystemUI will try to hide the menu by creating an animation to the normal
+ // bounds which are now stale. In such a case we defer the animation to the
+ // normal bounds until after the next onMovementBoundsChanged() call to get the
+ // bounds in the new orientation
try {
int displayRotation = mPinnedStackController.getDisplayRotation();
if (mDisplayRotation != displayRotation) {
@@ -510,6 +511,9 @@
mSavedSnapFraction = -1f;
}
} else {
+ // If resizing is not allowed, then the PiP should be frozen until the transition
+ // ends as well
+ setTouchEnabled(false);
mSavedSnapFraction = -1f;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 6667b71..1c5da4d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -34,7 +34,6 @@
import android.os.Debug;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -43,7 +42,6 @@
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -109,7 +107,7 @@
private IWindowManager mWindowManager;
private MediaSessionManager mMediaSessionManager;
private int mState = STATE_NO_PIP;
- private int mResumeResizePinnedStackRunnable = STATE_NO_PIP;
+ private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
private final Handler mHandler = new Handler();
private List<Listener> mListeners = new ArrayList<>();
private List<MediaListener> mMediaListeners = new ArrayList<>();
@@ -130,7 +128,7 @@
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
- resizePinnedStack(mResumeResizePinnedStackRunnable);
+ resizePinnedStack(mResumeResizePinnedStackRunnableState);
}
};
private final Runnable mClosePipRunnable = new Runnable() {
@@ -278,7 +276,7 @@
* Shows the picture-in-picture menu if an activity is in picture-in-picture mode.
*/
public void showPictureInPictureMenu() {
- if (mState == STATE_PIP) {
+ if (getState() == STATE_PIP) {
resizePinnedStack(STATE_PIP_MENU);
}
}
@@ -352,14 +350,15 @@
void resizePinnedStack(int state) {
if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state, new Exception());
boolean wasStateNoPip = (mState == STATE_NO_PIP);
- mResumeResizePinnedStackRunnable = state;
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onPipResizeAboutToStart();
}
if (mSuspendPipResizingReason != 0) {
+ mResumeResizePinnedStackRunnableState = state;
if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring"
+ " mSuspendPipResizingReason=" + mSuspendPipResizingReason
- + " mResumeResizePinnedStackRunnable=" + mResumeResizePinnedStackRunnable);
+ + " mResumeResizePinnedStackRunnableState="
+ + mResumeResizePinnedStackRunnableState);
return;
}
mState = state;
@@ -392,6 +391,16 @@
}
/**
+ * @return the current state, or the pending state if the state change was previously suspended.
+ */
+ private int getState() {
+ if (mSuspendPipResizingReason != 0) {
+ return mResumeResizePinnedStackRunnableState;
+ }
+ return mState;
+ }
+
+ /**
* Returns the default PIP bound.
*/
public Rect getPipBounds() {
@@ -459,7 +468,7 @@
}
private void handleMediaResourceGranted(String[] packageNames) {
- if (mState == STATE_NO_PIP) {
+ if (getState() == STATE_NO_PIP) {
mLastPackagesResourceGranted = packageNames;
} else {
boolean requestedFromLastPackages = false;
@@ -482,7 +491,7 @@
private void updateMediaController(List<MediaController> controllers) {
MediaController mediaController = null;
- if (controllers != null && mState != STATE_NO_PIP && mPipComponentName != null) {
+ if (controllers != null && getState() != STATE_NO_PIP && mPipComponentName != null) {
for (int i = controllers.size() - 1; i >= 0; i--) {
MediaController controller = controllers.get(i);
// We assumes that an app with PIPable activity
@@ -571,7 +580,7 @@
if (!checkCurrentUserId(DEBUG)) {
return;
}
- if (mState != STATE_NO_PIP) {
+ if (getState() != STATE_NO_PIP) {
boolean hasPip = false;
StackInfo stackInfo = getPinnedStackInfo();
@@ -593,7 +602,7 @@
return;
}
}
- if (mState == STATE_PIP) {
+ if (getState() == STATE_PIP) {
Rect bounds = isSettingsShown() ? mSettingsPipBounds : mDefaultPipBounds;
if (mPipBounds != bounds) {
mPipBounds = bounds;
@@ -603,7 +612,7 @@
}
@Override
- public void onActivityPinned(String packageName) {
+ public void onActivityPinned(String packageName, int taskId) {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
if (!checkCurrentUserId(DEBUG)) {
return;
@@ -645,7 +654,7 @@
if (!checkCurrentUserId(DEBUG)) {
return;
}
- switch (mState) {
+ switch (getState()) {
case STATE_PIP_MENU:
showPipMenu();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5b54d85..30240c3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -168,8 +168,7 @@
void onConfigurationChanged(Context context) {
Resources res = context.getResources();
mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
- mDefaultIconResId = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
- ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
+ mDefaultIconResId = R.drawable.pip_expand;
if (mNotified) {
// update notification
notifyPipNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 5cf049a..3f090f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -33,6 +34,7 @@
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.R.id;
+import com.android.systemui.R.style;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -67,6 +69,7 @@
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
+ inflater =inflater.cloneInContext(new ContextThemeWrapper(getContext(), R.style.qs_theme));
return inflater.inflate(R.layout.qs_panel, container, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index d3bd89f..72dd2da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -324,14 +324,14 @@
@Override
public void toggleRecentApps() {
- toggleRecents(mContext.getSystemService(WindowManager.class).getDefaultDisplay());
+ toggleRecents();
}
/**
* Toggles the Recents activity.
*/
@Override
- public void toggleRecents(Display display) {
+ public void toggleRecents() {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4e17bc9..65b7d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -62,6 +62,7 @@
import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.ActivityUnpinnedEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
@@ -203,8 +204,12 @@
Recents.getSystemServices().removeTask(task.persistentId);
}
}
- Settings.Secure.putLongForUser(RecentsActivity.this.getContentResolver(),
- Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, currentTime, currentUser);
+ Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
+ currentTime, currentUser);
+
+ // Clear the last PiP task time, it's an edge case and we'd rather it
+ // not relaunch the PiP task if the user double taps
+ RecentsImpl.clearLastPipTime();
}
}
}
@@ -222,6 +227,10 @@
getApplicationContext()).onActionEnd(
LatencyTracker.ACTION_TOGGLE_RECENTS));
}
+ DejankUtils.postAfterTraversal(() -> {
+ Recents.getTaskLoader().startLoader(RecentsActivity.this);
+ Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
+ });
return true;
}
};
@@ -378,8 +387,6 @@
mRecentsView.onStart();
// Notify of the next draw
mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
-
- Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
}
@Override
@@ -395,6 +402,7 @@
* Reloads the stack views upon launching Recents.
*/
private void reloadStackView() {
+
// If the Recents component has preloaded a load plan, then use that to prevent
// reconstructing the task stack
RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -501,28 +509,7 @@
public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
super.onMultiWindowModeChanged(isInMultiWindowMode);
- // Reload the task stack completely
- RecentsConfiguration config = Recents.getConfiguration();
- RecentsActivityLaunchState launchState = config.getLaunchState();
- RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
- loader.preloadTasks(loadPlan, -1 /* runningTaskId */,
- false /* includeFrontMostExcludedTask */);
-
- RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
- loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
- loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
-
- TaskStack stack = loadPlan.getTaskStack();
- int numStackTasks = stack.getStackTaskCount();
- boolean showDeferredAnimation = numStackTasks > 0;
-
- EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
- false /* fromDeviceOrientationChange */, false /* fromDisplayDensityChange */,
- numStackTasks > 0));
- EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
- showDeferredAnimation, stack));
+ reloadTaskStack(isInMultiWindowMode, true /* sendConfigChangedEvent */);
}
@Override
@@ -824,6 +811,41 @@
mRecentsView.invalidate();
}
+ public final void onBusEvent(final ActivityUnpinnedEvent event) {
+ if (mIsVisible) {
+ // Skip the configuration change event as the PiP activity does not actually affect the
+ // config of recents
+ reloadTaskStack(isInMultiWindowMode(), false /* sendConfigChangedEvent */);
+ }
+ }
+
+ private void reloadTaskStack(boolean isInMultiWindowMode, boolean sendConfigChangedEvent) {
+ // Reload the task stack completely
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, -1 /* runningTaskId */,
+ false /* includeFrontMostExcludedTask */);
+
+ RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+ loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+ loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+ loader.loadTasks(this, loadPlan, loadOpts);
+
+ TaskStack stack = loadPlan.getTaskStack();
+ int numStackTasks = stack.getStackTaskCount();
+ boolean showDeferredAnimation = numStackTasks > 0;
+
+ if (sendConfigChangedEvent) {
+ EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
+ false /* fromDeviceOrientationChange */, false /* fromDisplayDensityChange */,
+ numStackTasks > 0));
+ }
+ EventBus.getDefault().send(new MultiWindowStateChangedEvent(isInMultiWindowMode,
+ showDeferredAnimation, stack));
+ }
+
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index a7f6b70..5b8ed94 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -29,6 +29,10 @@
public boolean launchedWithAltTab;
public boolean launchedFromApp;
+ // Set if the activity that we launched from entered PiP during the transition into Recents
+ public boolean launchedFromPipApp;
+ // Set if the next activity that quick-switch will launch is the PiP activity
+ public boolean launchedWithNextPipApp;
public boolean launchedFromBlacklistedApp;
public boolean launchedFromHome;
public boolean launchedViaDragGesture;
@@ -41,6 +45,8 @@
launchedFromHome = false;
launchedFromApp = false;
launchedFromBlacklistedApp = false;
+ launchedFromPipApp = false;
+ launchedWithNextPipApp = false;
launchedToTaskId = -1;
launchedWithAltTab = false;
launchedViaDragGesture = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 2b812a5..e229c90 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -35,15 +35,18 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.Log;
import android.util.MutableBoolean;
+import android.util.Pair;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.Toast;
+
+import com.google.android.collect.Lists;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
@@ -57,6 +60,9 @@
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
+import com.android.systemui.recents.events.component.ActivityPinnedEvent;
+import com.android.systemui.recents.events.component.ActivityUnpinnedEvent;
+import com.android.systemui.recents.events.component.HidePipMenuEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
@@ -71,6 +77,8 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskGrouping;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.RecentsTransitionHelper;
+import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm.VisibilityReport;
import com.android.systemui.recents.views.TaskStackView;
@@ -127,6 +135,7 @@
// previous one.
VisibilityReport visibilityReport;
synchronized (mDummyStackView) {
+ mDummyStackView.getStack().removeAllTasks(false /* notifyStackChanges */);
mDummyStackView.setTasks(plan.getTaskStack(), false /* allowNotify */);
updateDummyStackViewLayout(plan.getTaskStack(),
getWindowRect(null /* windowRectOverride */));
@@ -151,12 +160,31 @@
}
@Override
+ public void onActivityPinned(String packageName, int taskId) {
+ // This time needs to be fetched the same way the last active time is fetched in
+ // {@link TaskRecord#touchActiveTime}
+ Recents.getConfiguration().getLaunchState().launchedFromPipApp = true;
+ Recents.getConfiguration().getLaunchState().launchedWithNextPipApp = false;
+ EventBus.getDefault().send(new ActivityPinnedEvent(taskId));
+ consumeInstanceLoadPlan();
+ sLastPipTime = System.currentTimeMillis();
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ EventBus.getDefault().send(new ActivityUnpinnedEvent());
+ sLastPipTime = -1;
+ }
+
+ @Override
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, snapshot));
}
}
protected static RecentsTaskLoadPlan sInstanceLoadPlan;
+ // Stores the last pinned task time
+ protected static long sLastPipTime = -1;
protected Context mContext;
protected Handler mHandler;
@@ -477,7 +505,8 @@
// Launch the task
ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID);
+ mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
+ null /* resultListener */);
}
/**
@@ -550,7 +579,8 @@
// Launch the task
ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID);
+ mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
+ null /* resultListener */);
}
public void showNextAffiliatedTask() {
@@ -593,6 +623,20 @@
}
/**
+ * @return the time at which a task last entered picture-in-picture.
+ */
+ public static long getLastPipTime() {
+ return sLastPipTime;
+ }
+
+ /**
+ * Clears the time at which a task last entered picture-in-picture.
+ */
+ public static void clearLastPipTime() {
+ sLastPipTime = -1;
+ }
+
+ /**
* Reloads all the resources for the current configuration.
*/
private void reloadResources() {
@@ -632,7 +676,7 @@
windowRect.bottom -= systemInsets.bottom;
systemInsets.bottom = 0;
}
- calculateWindowStableInsets(systemInsets, windowRect);
+ calculateWindowStableInsets(systemInsets, windowRect, displayRect);
windowRect.offsetTo(0, 0);
synchronized (mDummyStackView) {
@@ -674,6 +718,7 @@
updateDummyStackViewLayout(stack, windowRect);
if (stack != null) {
TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
+ mDummyStackView.getStack().removeAllTasks(false /* notifyStackChanges */);
mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
// Get the width of a task view so that we know how wide to draw the header bar.
if (useGridLayout) {
@@ -721,8 +766,7 @@
* Given the stable insets and the rect for our window, calculates the insets that affect our
* window.
*/
- private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect) {
- Rect displayRect = Recents.getSystemServices().getDisplayRect();
+ private void calculateWindowStableInsets(Rect inOutInsets, Rect windowRect, Rect displayRect) {
// Display rect without insets - available app space
Rect appRect = new Rect(displayRect);
@@ -772,8 +816,9 @@
/**
* Creates the activity options for an app->recents transition.
*/
- private ActivityOptions getThumbnailTransitionActivityOptions(
- ActivityManager.RunningTaskInfo runningTask, Rect windowOverrideRect) {
+ private Pair<ActivityOptions, AppTransitionAnimationSpecsFuture>
+ getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask,
+ Rect windowOverrideRect) {
if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
ArrayList<Task> tasks;
@@ -804,23 +849,27 @@
}
AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
specs.toArray(specsArray);
- return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- specsArray, mHandler, null, this);
+ return new Pair<>(ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+ specsArray, mHandler, null, this), null);
} else {
// Update the destination rect
Task toTask = new Task();
TaskViewTransform toTransform = getThumbnailTransitionTransform(mDummyStackView, toTask,
windowOverrideRect);
- Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
- mThumbTransitionBitmapCache);
- if (thumbnail != null) {
- RectF toTaskRect = toTransform.rect;
- return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
- (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, null);
- }
- // If both the screenshot and thumbnail fails, then just fall back to the default transition
- return getUnknownTransitionActivityOptions();
+
+ RectF toTaskRect = toTransform.rect;
+ AppTransitionAnimationSpecsFuture future =
+ new RecentsTransitionHelper(mContext).getAppTransitionFuture(
+ () -> {
+ Rect rect = new Rect();
+ toTaskRect.round(rect);
+ Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
+ mThumbTransitionBitmapCache);
+ return Lists.newArrayList(new AppTransitionAnimationSpec(
+ toTask.key.id, thumbnail, rect));
+ });
+ return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
+ mHandler, future.getFuture(), null, false /* scaleUp */), future);
}
}
@@ -919,6 +968,9 @@
launchState.launchedFromHome = !useThumbnailTransition && !mLaunchedWhileDocking;
launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
launchState.launchedFromBlacklistedApp = launchState.launchedFromApp && isBlacklisted;
+ launchState.launchedFromPipApp = false;
+ launchState.launchedWithNextPipApp =
+ stack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime());
launchState.launchedViaDockGesture = mLaunchedWhileDocking;
launchState.launchedViaDragGesture = mDraggingInRecents;
launchState.launchedToTaskId = runningTaskId;
@@ -943,30 +995,31 @@
launchState.launchedNumVisibleThumbnails = stackVr.numVisibleThumbnails;
if (!animate) {
- startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1));
+ startRecentsActivity(ActivityOptions.makeCustomAnimation(mContext, -1, -1),
+ null /* future */);
return;
}
- ActivityOptions opts;
+ Pair<ActivityOptions, AppTransitionAnimationSpecsFuture> pair;
if (isBlacklisted) {
- opts = getUnknownTransitionActivityOptions();
+ pair = new Pair<>(getUnknownTransitionActivityOptions(), null);
} else if (useThumbnailTransition) {
// Try starting with a thumbnail transition
- opts = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
+ pair = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
} else {
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition
- opts = hasRecentTasks
- ? getHomeTransitionActivityOptions()
- : getUnknownTransitionActivityOptions();
+ pair = new Pair<>(hasRecentTasks
+ ? getHomeTransitionActivityOptions()
+ : getUnknownTransitionActivityOptions(), null);
}
- startRecentsActivity(opts);
+ startRecentsActivity(pair.first, pair.second);
mLastToggleTime = SystemClock.elapsedRealtime();
}
private Rect getWindowRectOverride(int growTarget) {
if (growTarget == DividerView.INVALID_RECENTS_GROW_TARGET) {
- return null;
+ return SystemServicesProxy.getInstance(mContext).getWindowRect();
}
Rect result = new Rect();
Rect displayRect = Recents.getSystemServices().getDisplayRect();
@@ -979,19 +1032,23 @@
/**
* Starts the recents activity.
*/
- private void startRecentsActivity(ActivityOptions opts) {
+ private void startRecentsActivity(ActivityOptions opts,
+ final AppTransitionAnimationSpecsFuture future) {
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-
- if (opts != null) {
- mContext.startActivityAsUser(intent, opts.toBundle(), UserHandle.CURRENT);
- } else {
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- }
- EventBus.getDefault().send(new RecentsActivityStartingEvent());
+ Recents.getSystemServices().startActivityAsUserAsync(intent, opts);
+ HidePipMenuEvent hideMenuEvent = new HidePipMenuEvent();
+ hideMenuEvent.addPostAnimationCallback(() -> {
+ Recents.getSystemServices().startActivityAsUserAsync(intent, opts);
+ EventBus.getDefault().send(new RecentsActivityStartingEvent());
+ if (future != null) {
+ future.precacheSpecs();
+ }
+ });
+ EventBus.getDefault().send(hideMenuEvent);
}
/**** OnAnimationFinishedListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index a737505..d7abb38 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -810,6 +810,11 @@
private void queueEvent(final Event event) {
ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());
if (eventHandlers == null) {
+ // This is just an optimization to return early if there are no handlers. However, we
+ // should still ensure that we call pre/post dispatch callbacks so that AnimatedEvents
+ // are still cleaned up correctly if a listener has not been registered to handle them
+ event.onPreDispatch();
+ event.onPostDispatch();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java
new file mode 100644
index 0000000..75bfd7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowEmptyViewEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when the stack should be hidden and the empty view shown.
+ */
+public class ShowEmptyViewEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java
new file mode 100644
index 0000000..f4d2fcf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityPinnedEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when an activity is pinned.
+ */
+public class ActivityPinnedEvent extends EventBus.Event {
+
+ public final int taskId;
+
+ public ActivityPinnedEvent(int taskId) {
+ this.taskId = taskId;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java
new file mode 100644
index 0000000..48c5f0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ActivityUnpinnedEvent.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when an activity is unpinned.
+ */
+public class ActivityUnpinnedEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ExpandPipEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ExpandPipEvent.java
new file mode 100644
index 0000000..8fe4975
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ExpandPipEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the PiP should be expanded due to being relaunched.
+ */
+public class ExpandPipEvent extends EventBus.Event {
+ public final boolean clearThumbnailWindows = true;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java
new file mode 100644
index 0000000..ce4f207
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/HidePipMenuEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.component;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the PiP menu should be hidden.
+ */
+public class HidePipMenuEvent extends EventBus.AnimatedEvent {
+ // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index f431517..a155a71 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -26,7 +26,9 @@
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.AppGlobals;
@@ -56,15 +58,18 @@
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IRemoteCallback;
-import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
@@ -81,7 +86,9 @@
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.pip.tv.PipMenuActivity;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
@@ -95,6 +102,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -124,6 +133,8 @@
PackageManager mPm;
IconDrawableFactory mDrawableFactory;
IPackageManager mIpm;
+ private final IDreamManager mDreamManager;
+ private final Context mContext;
AssistUtils mAssistUtils;
WindowManager mWm;
IWindowManager mIwm;
@@ -144,6 +155,8 @@
private final Handler mHandler = new H();
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+
/**
* An abstract class to track task stack changes.
* Classes should implement this instead of {@link android.app.ITaskStackListener}
@@ -156,7 +169,7 @@
public void onTaskStackChangedBackground() { }
public void onTaskStackChanged() { }
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
- public void onActivityPinned(String packageName) { }
+ public void onActivityPinned(String packageName, int taskId) { }
public void onActivityUnpinned() { }
public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
public void onPinnedStackAnimationStarted() { }
@@ -211,9 +224,9 @@
}
@Override
- public void onActivityPinned(String packageName) throws RemoteException {
+ public void onActivityPinned(String packageName, int taskId) throws RemoteException {
mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
- mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, packageName).sendToTarget();
+ mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, taskId, 0, packageName).sendToTarget();
}
@Override
@@ -278,6 +291,7 @@
/** Private constructor */
private SystemServicesProxy(Context context) {
+ mContext = context.getApplicationContext();
mAccm = AccessibilityManager.getInstance(context);
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mIam = ActivityManager.getService();
@@ -289,6 +303,8 @@
mIwm = WindowManagerGlobal.getWindowManagerService();
mKgm = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mUm = UserManager.get(context);
+ mDreamManager = IDreamManager.Stub.asInterface(
+ ServiceManager.checkService(DreamService.DREAM_SERVICE));
mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
mHasFreeformWorkspaceSupport =
@@ -442,9 +458,18 @@
* Returns the top running task.
*/
public ActivityManager.RunningTaskInfo getRunningTask() {
- List<ActivityManager.RunningTaskInfo> tasks = mAm.getRunningTasks(1);
+ // Note: The set of running tasks from the system is ordered by recency
+ List<ActivityManager.RunningTaskInfo> tasks = mAm.getRunningTasks(10);
if (tasks != null && !tasks.isEmpty()) {
- return tasks.get(0);
+ // Find the first task in a valid stack, we ignore everything from the Recents and PiP
+ // stacks
+ for (int i = 0; i < tasks.size(); i++) {
+ ActivityManager.RunningTaskInfo task = tasks.get(i);
+ int stackId = task.stackId;
+ if (stackId != RECENTS_STACK_ID && stackId != PINNED_STACK_ID) {
+ return task;
+ }
+ }
}
return null;
}
@@ -466,13 +491,20 @@
if (mIam == null) return false;
try {
- ActivityManager.StackInfo homeStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.HOME_STACK_ID);
- ActivityManager.StackInfo fullscreenStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
- ActivityManager.StackInfo recentsStackInfo = mIam.getStackInfo(
- ActivityManager.StackId.RECENTS_STACK_ID);
-
+ List<StackInfo> stackInfos = mIam.getAllStackInfos();
+ ActivityManager.StackInfo homeStackInfo = null;
+ ActivityManager.StackInfo fullscreenStackInfo = null;
+ ActivityManager.StackInfo recentsStackInfo = null;
+ for (int i = 0; i < stackInfos.size(); i++) {
+ StackInfo stackInfo = stackInfos.get(i);
+ if (stackInfo.stackId == HOME_STACK_ID) {
+ homeStackInfo = stackInfo;
+ } else if (stackInfo.stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ fullscreenStackInfo = stackInfo;
+ } else if (stackInfo.stackId == RECENTS_STACK_ID) {
+ recentsStackInfo = stackInfo;
+ }
+ }
boolean homeStackVisibleNotOccluded = isStackNotOccluded(homeStackInfo,
fullscreenStackInfo);
boolean recentsStackVisibleNotOccluded = isStackNotOccluded(recentsStackInfo,
@@ -755,10 +787,12 @@
* Sends a message to close other system windows.
*/
public void sendCloseSystemWindows(String reason) {
- try {
- mIam.closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
+ mUiOffloadThread.submit(() -> {
+ try {
+ mIam.closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ });
}
/**
@@ -1000,6 +1034,9 @@
public int getCurrentUser() {
if (mAm == null) return 0;
+ // This must call through ActivityManager, as the SystemServicesProxy can be called in a
+ // secondary user's SystemUI process, and KeyguardUpdateMonitor is only updated in the
+ // primary user's SystemUI process
return mAm.getCurrentUser();
}
@@ -1104,32 +1141,50 @@
}
}
+ public void startActivityAsUserAsync(Intent intent, ActivityOptions opts) {
+ mUiOffloadThread.submit(() -> mContext.startActivityAsUser(intent,
+ opts != null ? opts.toBundle() : null, UserHandle.CURRENT));
+ }
+
/** Starts an activity from recents. */
- public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options, int stackId) {
- if (mIam != null) {
- try {
- if (taskKey.stackId == DOCKED_STACK_ID) {
- // We show non-visible docked tasks in Recents, but we always want to launch
- // them in the fullscreen stack.
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
- } else if (stackId != INVALID_STACK_ID){
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchStackId(stackId);
- }
- mIam.startActivityFromRecents(
- taskKey.id, options == null ? null : options.toBundle());
- return true;
- } catch (Exception e) {
- Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
- }
+ public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
+ ActivityOptions options, int stackId,
+ @Nullable final StartActivityFromRecentsResultListener resultListener) {
+ if (mIam == null) {
+ return;
}
- return false;
+ if (taskKey.stackId == DOCKED_STACK_ID) {
+ // We show non-visible docked tasks in Recents, but we always want to launch
+ // them in the fullscreen stack.
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
+ } else if (stackId != INVALID_STACK_ID) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchStackId(stackId);
+ }
+ final ActivityOptions finalOptions = options;
+
+ // Execute this from another thread such that we can do other things (like caching the
+ // bitmap for the thumbnail) while AM is busy starting our activity.
+ mUiOffloadThread.submit(() -> {
+ try {
+ mIam.startActivityFromRecents(
+ taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
+ if (resultListener != null) {
+ mHandler.post(() -> resultListener.onStartActivityResult(true));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, context.getString(
+ R.string.recents_launch_error_message, taskName), e);
+ if (resultListener != null) {
+ mHandler.post(() -> resultListener.onStartActivityResult(false));
+ }
+ }
+ });
}
/** Starts an in-place animation on the front most application windows. */
@@ -1247,6 +1302,37 @@
}
}
+ public boolean isDreaming() {
+ try {
+ return mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query dream manager.", e);
+ }
+ return false;
+ }
+
+ public void awakenDreamsAsync() {
+ mUiOffloadThread.submit(() -> {
+ try {
+ mDreamManager.awaken();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ public void updateOverviewLastStackActiveTimeAsync(long newLastStackActiveTime,
+ int currentUserId) {
+ mUiOffloadThread.submit(() -> {
+ Settings.Secure.putLongForUser(mContext.getContentResolver(),
+ Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, newLastStackActiveTime, currentUserId);
+ });
+ }
+
+ public interface StartActivityFromRecentsResultListener {
+ void onStartActivityResult(boolean succeeded);
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -1283,7 +1369,7 @@
}
case ON_ACTIVITY_PINNED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityPinned((String) msg.obj);
+ mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1);
}
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
index be8da9f..974139a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
@@ -50,6 +50,7 @@
private boolean mLoading;
private boolean mVisible;
private boolean mFlingingFast;
+ private boolean mTaskLoadQueueIdle;
public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper) {
mMainThreadHandler = new Handler(looper);
@@ -71,13 +72,22 @@
updateLoading();
}
+ /**
+ * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
+ * starting this queue until the other queue is idling.
+ */
+ public void setTaskLoadQueueIdle(boolean idle) {
+ mTaskLoadQueueIdle = idle;
+ updateLoading();
+ }
+
@VisibleForTesting
boolean isLoading() {
return mLoading;
}
private void updateLoading() {
- setLoading(mVisible && !mFlingingFast);
+ setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
}
private void setLoading(boolean loading) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 4b53cd1..ed09640 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -33,6 +33,7 @@
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
@@ -86,7 +87,7 @@
mCurrentQuietProfiles.clear();
if (currentUserId == UserHandle.USER_CURRENT) {
- currentUserId = ActivityManager.getCurrentUser();
+ currentUserId = SystemServicesProxy.getInstance(mContext).getCurrentUser();
}
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
List<UserInfo> profiles = userManager.getProfiles(currentUserId);
@@ -217,8 +218,8 @@
affiliatedTasks.put(taskKey.id, taskKey);
}
if (newLastStackActiveTime != -1) {
- Settings.Secure.putLongForUser(mContext.getContentResolver(),
- Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, newLastStackActiveTime, currentUserId);
+ Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
+ newLastStackActiveTime, currentUserId);
}
// Initialize the stacks
@@ -315,9 +316,8 @@
for (int i = 0; i < users.size(); i++) {
int userId = users.get(i).id;
if (userId != currentUserId) {
- Settings.Secure.putLongForUser(mContext.getContentResolver(),
- Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime,
- userId);
+ Recents.getSystemServices().updateOverviewLastStackActiveTimeAsync(
+ legacyLastStackActiveTime, userId);
}
}
return legacyLastStackActiveTime;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 802cb831..15e1739 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -28,6 +28,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.Trace;
import android.util.Log;
import android.util.LruCache;
@@ -48,6 +49,7 @@
* A Task load queue
*/
class TaskResourceLoadQueue {
+
ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
/** Adds a new task to the load queue */
@@ -101,32 +103,41 @@
Bitmap mDefaultThumbnail;
BitmapDrawable mDefaultIcon;
+ boolean mStarted;
boolean mCancelled;
boolean mWaitingOnLoadQueue;
+ private final OnIdleChangedListener mOnIdleChangedListener;
+
/** Constructor, creates a new loading thread that loads task resources in the background */
public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
TaskKeyLruCache<Drawable> iconCache, Bitmap defaultThumbnail,
- BitmapDrawable defaultIcon) {
+ BitmapDrawable defaultIcon, OnIdleChangedListener onIdleChangedListener) {
mLoadQueue = loadQueue;
mIconCache = iconCache;
mDefaultThumbnail = defaultThumbnail;
mDefaultIcon = defaultIcon;
mMainThreadHandler = new Handler();
+ mOnIdleChangedListener = onIdleChangedListener;
mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
mLoadThread.start();
mLoadThreadHandler = new Handler(mLoadThread.getLooper());
- mLoadThreadHandler.post(this);
}
/** Restarts the loader thread */
void start(Context context) {
mContext = context;
mCancelled = false;
- // Notify the load thread to start loading
- synchronized(mLoadThread) {
- mLoadThread.notifyAll();
+ if (!mStarted) {
+ // Start loading on the load thread
+ mStarted = true;
+ mLoadThreadHandler.post(this);
+ } else {
+ // Notify the load thread to start loading again
+ synchronized (mLoadThread) {
+ mLoadThread.notifyAll();
+ }
}
}
@@ -169,7 +180,11 @@
synchronized(mLoadQueue) {
try {
mWaitingOnLoadQueue = true;
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(true));
mLoadQueue.wait();
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(false));
mWaitingOnLoadQueue = false;
} catch (InterruptedException ie) {
ie.printStackTrace();
@@ -230,6 +245,10 @@
}
}
}
+
+ interface OnIdleChangedListener {
+ void onIdleChanged(boolean idle);
+ }
}
/**
@@ -298,15 +317,16 @@
// Initialize the proxy, cache and loaders
int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
+ mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
+ Looper.getMainLooper());
mLoadQueue = new TaskResourceLoadQueue();
mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
mClearActivityInfoOnEviction);
mActivityInfoCache = new LruCache(numRecentTasks);
- mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon);
- mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
- Looper.getMainLooper());
+ mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon,
+ mHighResThumbnailLoader::setTaskLoadQueueIdle);
}
/** Returns the size of the app icon cache. */
@@ -338,7 +358,12 @@
/** Preloads recents tasks using the specified plan to store the output. */
public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
boolean includeFrontMostExcludedTask) {
- plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
+ try {
+ Trace.beginSection("preloadPlan");
+ plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
+ } finally {
+ Trace.endSection();
+ }
}
/** Begins loading the heavy task data according to the specified options. */
@@ -360,9 +385,6 @@
mTempCache.evictAll();
if (!opts.onlyLoadForCache) {
mNumVisibleTasksLoaded = opts.numVisibleTasks;
-
- // Start the loader
- mLoader.start(context);
}
}
@@ -608,6 +630,13 @@
}
/**
+ * Starts loading tasks.
+ */
+ public void startLoader(Context ctx) {
+ mLoader.start(ctx);
+ }
+
+ /**
* Stops the task loader and clears all queued, pending task loads.
*/
private void stopLoader() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 9b25ef8..6e3be09 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -229,7 +229,8 @@
* Notifies when a task has been removed from the stack.
*/
void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
- AnimationProps animation, boolean fromDockGesture);
+ AnimationProps animation, boolean fromDockGesture,
+ boolean dismissRecentsIfAllRemoved);
/**
* Notifies when all tasks have been removed from the stack.
@@ -631,13 +632,22 @@
* how they should update themselves.
*/
public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
+ removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */);
+ }
+
+ /**
+ * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+ * how they should update themselves.
+ */
+ public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture,
+ boolean dismissRecentsIfAllRemoved) {
if (mStackTaskList.contains(t)) {
removeTaskImpl(mStackTaskList, t);
Task newFrontMostTask = getStackFrontMostTask(false /* includeFreeform */);
if (mCb != null) {
// Notify that a task has been removed
mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
- fromDockGesture);
+ fromDockGesture, dismissRecentsIfAllRemoved);
}
}
mRawTaskList.remove(t);
@@ -646,19 +656,27 @@
/**
* Removes all tasks from the stack.
*/
- public void removeAllTasks() {
+ public void removeAllTasks(boolean notifyStackChanges) {
ArrayList<Task> tasks = mStackTaskList.getTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
Task t = tasks.get(i);
removeTaskImpl(mStackTaskList, t);
mRawTaskList.remove(t);
}
- if (mCb != null) {
+ if (mCb != null && notifyStackChanges) {
// Notify that all tasks have been removed
mCb.onStackTasksRemoved(this);
}
}
+
+ /**
+ * @see #setTasks(Context, List, boolean, boolean)
+ */
+ public void setTasks(Context context, TaskStack stack, boolean notifyStackChanges) {
+ setTasks(context, stack.mRawTaskList, notifyStackChanges);
+ }
+
/**
* Sets a few tasks in one go, without calling any callbacks.
*
@@ -723,7 +741,8 @@
Task newFrontMostTask = getStackFrontMostTask(false);
for (int i = 0; i < removedTaskCount; i++) {
mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
- AnimationProps.IMMEDIATE, false /* fromDockGesture */);
+ AnimationProps.IMMEDIATE, false /* fromDockGesture */,
+ true /* dismissRecentsIfAllRemoved */);
}
// Only callback for the newly added tasks after this stack has been updated
@@ -854,21 +873,46 @@
}
/**
+ * Returns whether the next launch target should actually be the PiP task.
+ */
+ public boolean isNextLaunchTargetPip(long lastPipTime) {
+ Task launchTarget = getLaunchTarget();
+ Task nextLaunchTarget = getNextLaunchTargetRaw();
+ if (nextLaunchTarget != null && lastPipTime > 0) {
+ // If the PiP time is more recent than the next launch target, then launch the PiP task
+ return lastPipTime > nextLaunchTarget.key.lastActiveTime;
+ } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) {
+ // Otherwise, if there is no next launch target, but there is a PiP, then launch
+ // the PiP task
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns the task in stack tasks which should be launched next if Recents are toggled
- * again, or null if there is no task to be launched.
+ * again, or null if there is no task to be launched. Callers should check
+ * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the
+ * stack.
*/
public Task getNextLaunchTarget() {
+ Task nextLaunchTarget = getNextLaunchTargetRaw();
+ if (nextLaunchTarget != null) {
+ return nextLaunchTarget;
+ }
+ return getStackTasks().get(getTaskCount() - 1);
+ }
+
+ private Task getNextLaunchTargetRaw() {
int taskCount = getTaskCount();
if (taskCount == 0) {
return null;
}
int launchTaskIndex = indexOfStackTask(getLaunchTarget());
- if (launchTaskIndex != -1) {
- launchTaskIndex = Math.max(0, launchTaskIndex - 1);
- } else {
- launchTaskIndex = getTaskCount() - 1;
+ if (launchTaskIndex != -1 && launchTaskIndex > 0) {
+ return getStackTasks().get(launchTaskIndex - 1);
}
- return getStackTasks().get(launchTaskIndex);
+ return null;
}
/** Returns the index of this task in this current task stack */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 8882cab..d7d264e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -101,57 +101,49 @@
*/
public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
final TaskStackView stackView, final TaskView taskView,
- final boolean screenPinningRequested, final Rect bounds, final int destinationStack) {
- final ActivityOptions opts = ActivityOptions.makeBasic();
- if (bounds != null) {
- opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
- }
+ final boolean screenPinningRequested, final int destinationStack) {
final ActivityOptions.OnAnimationStartedListener animStartedListener;
- final IAppTransitionAnimationSpecsFuture transitionFuture;
+ final AppTransitionAnimationSpecsFuture transitionFuture;
if (taskView != null) {
- transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() {
- @Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
- return composeAnimationSpecs(task, stackView, destinationStack);
- }
- });
- animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
- @Override
- public void onAnimationStarted() {
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
- EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
- stackView.cancelAllTaskViewAnimations();
- if (screenPinningRequested) {
- // Request screen pinning after the animation runs
- mStartScreenPinningRunnable.taskId = task.key.id;
- mHandler.postDelayed(mStartScreenPinningRunnable, 350);
- }
+ // Fetch window rect here already in order not to be blocked on lock contention in WM
+ // when the future calls it.
+ final Rect windowRect = Recents.getSystemServices().getWindowRect();
+ transitionFuture = getAppTransitionFuture(
+ () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect));
+ animStartedListener = () -> {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ stackView.cancelAllTaskViewAnimations();
+
+ if (screenPinningRequested) {
+ // Request screen pinning after the animation runs
+ mStartScreenPinningRunnable.taskId = task.key.id;
+ mHandler.postDelayed(mStartScreenPinningRunnable, 350);
}
};
} else {
// This is only the case if the task is not on screen (scrolled offscreen for example)
transitionFuture = null;
- animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
- @Override
- public void onAnimationStarted() {
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
- EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
- stackView.cancelAllTaskViewAnimations();
- }
+ animStartedListener = () -> {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ stackView.cancelAllTaskViewAnimations();
};
}
+ final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
+ mHandler, transitionFuture != null ? transitionFuture.future : null,
+ animStartedListener, true /* scaleUp */);
if (taskView == null) {
// If there is no task view, then we do not need to worry about animating out occluding
// task views, and we can launch immediately
- startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener,
- destinationStack);
+ startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
} else {
LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
screenPinningRequested);
@@ -160,14 +152,13 @@
@Override
public void run() {
startTaskActivity(stack, task, taskView, opts, transitionFuture,
- animStartedListener, destinationStack);
+ destinationStack);
}
});
EventBus.getDefault().send(launchStartedEvent);
} else {
EventBus.getDefault().send(launchStartedEvent);
- startTaskActivity(stack, task, taskView, opts, transitionFuture,
- animStartedListener, destinationStack);
+ startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
}
}
Recents.getSystemServices().sendCloseSystemWindows(
@@ -199,30 +190,31 @@
* @param destinationStack id of the stack to put the task into.
*/
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
- ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
- final OnAnimationStartedListener animStartedListener, int destinationStack) {
+ ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
+ int destinationStack) {
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack)) {
- // Keep track of the index of the task launch
- int taskIndexFromFront = 0;
- int taskIndex = stack.indexOfStackTask(task);
- if (taskIndex > -1) {
- taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
- }
- EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
- } else {
- // Dismiss the task if we fail to launch it
- if (taskView != null) {
- taskView.dismissTask();
- }
+ ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack,
+ succeeded -> {
+ if (succeeded) {
+ // Keep track of the index of the task launch
+ int taskIndexFromFront = 0;
+ int taskIndex = stack.indexOfStackTask(task);
+ if (taskIndex > -1) {
+ taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+ }
+ EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
+ } else {
+ // Dismiss the task if we fail to launch it
+ if (taskView != null) {
+ taskView.dismissTask();
+ }
- // Keep track of failed launches
- EventBus.getDefault().send(new LaunchTaskFailedEvent());
- }
-
+ // Keep track of failed launches
+ EventBus.getDefault().send(new LaunchTaskFailedEvent());
+ }
+ });
if (transitionFuture != null) {
- ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture,
- wrapStartedListener(animStartedListener), true /* scaleUp */);
+ mHandler.post(transitionFuture::precacheSpecs);
}
}
@@ -231,21 +223,18 @@
*
* @param composer The implementation that composes the specs on the UI thread.
*/
- public IAppTransitionAnimationSpecsFuture getAppTransitionFuture(
+ public AppTransitionAnimationSpecsFuture getAppTransitionFuture(
final AnimationSpecComposer composer) {
synchronized (this) {
mAppTransitionAnimationSpecs = SPECS_WAITING;
}
- return new IAppTransitionAnimationSpecsFuture.Stub() {
+ IAppTransitionAnimationSpecsFuture future = new IAppTransitionAnimationSpecsFuture.Stub() {
@Override
public AppTransitionAnimationSpec[] get() throws RemoteException {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (RecentsTransitionHelper.this) {
- mAppTransitionAnimationSpecs = composer.composeSpecs();
- RecentsTransitionHelper.this.notifyAll();
- }
+ mHandler.post(() -> {
+ synchronized (RecentsTransitionHelper.this) {
+ mAppTransitionAnimationSpecs = composer.composeSpecs();
+ RecentsTransitionHelper.this.notifyAll();
}
});
synchronized (RecentsTransitionHelper.this) {
@@ -265,6 +254,7 @@
}
}
};
+ return new AppTransitionAnimationSpecsFuture(composer, future);
}
/**
@@ -283,7 +273,7 @@
* Composes the animation specs for all the tasks in the target stack.
*/
private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
- final TaskStackView stackView, final int destinationStack) {
+ final TaskStackView stackView, final int destinationStack, Rect windowRect) {
// Ensure we have a valid target stack id
final int targetStackId = destinationStack != INVALID_STACK_ID ?
destinationStack : task.key.stackId;
@@ -309,8 +299,7 @@
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
} else {
mTmpTransform.fillIn(taskView);
- stackLayout.transformToScreenCoordinates(mTmpTransform,
- null /* windowOverrideRect */);
+ stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
mTmpTransform, true /* addHeaderBitmap */);
if (spec != null) {
@@ -430,4 +419,34 @@
public interface AnimationSpecComposer {
List<AppTransitionAnimationSpec> composeSpecs();
}
+
+ /**
+ * Class to be returned from {@link #composeAnimationSpec} that gives access to both the future
+ * and the anonymous class used for composing.
+ */
+ public class AppTransitionAnimationSpecsFuture {
+
+ private final AnimationSpecComposer composer;
+ private final IAppTransitionAnimationSpecsFuture future;
+
+ private AppTransitionAnimationSpecsFuture(AnimationSpecComposer composer,
+ IAppTransitionAnimationSpecsFuture future) {
+ this.composer = composer;
+ this.future = future;
+ }
+
+ public IAppTransitionAnimationSpecsFuture getFuture() {
+ return future;
+ }
+
+ /**
+ * Manually generates and caches the spec such that they are already available when the
+ * future needs.
+ */
+ public void precacheSpecs() {
+ synchronized (RecentsTransitionHelper.this) {
+ mAppTransitionAnimationSpecs = composer.composeSpecs();
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 6879436..978533c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -25,19 +25,16 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.view.AppTransitionAnimationSpec;
-import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
-import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.widget.FrameLayout;
@@ -60,7 +57,9 @@
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
+import com.android.systemui.recents.events.activity.ShowEmptyViewEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.component.ExpandPipEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
@@ -75,13 +74,13 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
+import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.google.android.colorextraction.ColorExtractor;
import com.google.android.colorextraction.drawable.GradientDrawable;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -259,6 +258,12 @@
/** Launches the task that recents was launched from if possible */
public boolean launchPreviousTask() {
+ if (Recents.getConfiguration().getLaunchState().launchedFromPipApp) {
+ // If the app auto-entered PiP on the way to Recents, then just re-expand it
+ EventBus.getDefault().send(new ExpandPipEvent());
+ return true;
+ }
+
if (mTaskStackView != null) {
Task task = getStack().getLaunchTarget();
if (task != null) {
@@ -451,8 +456,7 @@
public final void onBusEvent(LaunchTaskEvent event) {
mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
- event.taskView, event.screenPinningRequested, event.targetTaskBounds,
- event.targetTaskStack);
+ event.taskView, event.screenPinningRequested, event.targetTaskStack);
}
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
@@ -534,7 +538,7 @@
};
final Rect taskRect = getTaskRect(event.taskView);
- IAppTransitionAnimationSpecsFuture future =
+ AppTransitionAnimationSpecsFuture future =
mTransitionHelper.getAppTransitionFuture(
new AnimationSpecComposer() {
@Override
@@ -543,7 +547,7 @@
event.taskView, taskRect);
}
});
- ssp.overridePendingAppTransitionMultiThumbFuture(future,
+ ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
mTransitionHelper.wrapStartedListener(startedListener),
true /* scaleUp */);
@@ -650,6 +654,10 @@
updateStack(event.stack, false /* setStackViewTasks */);
}
+ public final void onBusEvent(ShowEmptyViewEvent event) {
+ showEmptyView(R.string.recents_empty_message);
+ }
+
/**
* Shows the stack action button.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 7ba705e..8135034 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -562,7 +562,8 @@
mMinScrollP = 0;
mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
Math.max(0, mFocusedRange.getAbsoluteX(maxBottomNormX)));
- if (launchState.launchedFromHome) {
+ if (launchState.launchedFromHome || launchState.launchedFromPipApp
+ || launchState.launchedWithNextPipApp) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
} else {
mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
@@ -581,8 +582,8 @@
mMinScrollP = 0;
mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
- boolean scrollToFront = launchState.launchedFromHome ||
- launchState.launchedViaDockGesture;
+ boolean scrollToFront = launchState.launchedFromHome || launchState.launchedFromPipApp
+ || launchState.launchedWithNextPipApp || launchState.launchedViaDockGesture;
if (launchState.launchedFromBlacklistedApp) {
mInitialScrollP = mMaxScrollP;
} else if (launchState.launchedWithAltTab) {
@@ -608,6 +609,8 @@
mTaskIndexOverrideMap.clear();
boolean scrollToFront = launchState.launchedFromHome ||
+ launchState.launchedFromPipApp ||
+ launchState.launchedWithNextPipApp ||
launchState.launchedFromBlacklistedApp ||
launchState.launchedViaDockGesture;
if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 18a9bab..5f9a8f5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -57,6 +57,7 @@
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
+import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
@@ -72,7 +73,11 @@
import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
+import com.android.systemui.recents.events.activity.ShowEmptyViewEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.component.ActivityPinnedEvent;
+import com.android.systemui.recents.events.component.ExpandPipEvent;
+import com.android.systemui.recents.events.component.HidePipMenuEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
@@ -379,8 +384,7 @@
// Only notify if we are already initialized, otherwise, everything will pick up all the
// new and old tasks when we next layout
- mStack.setTasks(getContext(), stack.computeAllTasksList(),
- allowNotifyStackChanges && isInitialized);
+ mStack.setTasks(getContext(), stack, allowNotifyStackChanges && isInitialized);
}
/** Returns the task stack. */
@@ -1496,7 +1500,7 @@
*/
@Override
public void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
- AnimationProps animation, boolean fromDockGesture) {
+ AnimationProps animation, boolean fromDockGesture, boolean dismissRecentsIfAllRemoved) {
if (mFocusedTask == removedTask) {
resetFocusedTask(removedTask);
}
@@ -1527,9 +1531,13 @@
// If there are no remaining tasks, then just close recents
if (mStack.getTaskCount() == 0) {
- EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
- ? R.string.recents_empty_message
- : R.string.recents_empty_message_dismissed_all));
+ if (dismissRecentsIfAllRemoved) {
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
+ ? R.string.recents_empty_message
+ : R.string.recents_empty_message_dismissed_all));
+ } else {
+ EventBus.getDefault().send(new ShowEmptyViewEvent());
+ }
}
}
@@ -1802,14 +1810,36 @@
return;
}
- final Task launchTask = mStack.getNextLaunchTarget();
- if (launchTask != null) {
- launchTask(launchTask);
- MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
- launchTask.key.getComponent().toString());
- } else if (mStack.getTaskCount() == 0) {
- // If there are no tasks, then just hide recents back to home.
- EventBus.getDefault().send(new HideRecentsEvent(false, true));
+ if (mStack.getTaskCount() == 0) {
+ if (RecentsImpl.getLastPipTime() != -1) {
+ EventBus.getDefault().send(new ExpandPipEvent());
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+ "pip");
+ } else {
+ // If there are no tasks, then just hide recents back to home.
+ EventBus.getDefault().send(new HideRecentsEvent(false, true));
+ }
+ return;
+ }
+
+ if (!Recents.getConfiguration().getLaunchState().launchedFromPipApp
+ && mStack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime())) {
+ // If the launch task is in the pinned stack, then expand the PiP now
+ EventBus.getDefault().send(new ExpandPipEvent());
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK, "pip");
+ } else {
+ final Task launchTask = mStack.getNextLaunchTarget();
+ if (launchTask != null) {
+ // Defer launching the task until the PiP menu has been dismissed (if it is
+ // showing at all)
+ HidePipMenuEvent hideMenuEvent = new HidePipMenuEvent();
+ hideMenuEvent.addPostAnimationCallback(() -> {
+ launchTask(launchTask);
+ });
+ EventBus.getDefault().send(hideMenuEvent);
+ MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
+ launchTask.key.getComponent().toString());
+ }
}
}
@@ -1871,7 +1901,7 @@
R.string.accessibility_recents_all_items_dismissed));
// Remove all tasks and delete the task data for all tasks
- mStack.removeAllTasks();
+ mStack.removeAllTasks(true /* notifyStackChanges */);
for (int i = tasks.size() - 1; i >= 0; i--) {
EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
}
@@ -2217,11 +2247,23 @@
}
}
+ public final void onBusEvent(ActivityPinnedEvent event) {
+ // If an activity enters PiP while Recents is open, remove the stack task associated with
+ // the new PiP task
+ Task removeTask = mStack.findTaskWithId(event.taskId);
+ if (removeTask != null) {
+ // In this case, we remove the task, but if the last task is removed, don't dismiss
+ // Recents to home
+ mStack.removeTask(removeTask, AnimationProps.IMMEDIATE, false /* fromDockGesture */,
+ false /* dismissRecentsIfAllRemoved */);
+ }
+ updateLayoutAlgorithm(false /* boundScroll */);
+ updateToInitialState();
+ }
+
public void reloadOnConfigurationChange() {
mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
-
- boolean hasDockedTask = Recents.getSystemServices().hasDockedTask();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 8f24ec7..0c77036 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1159,7 +1159,7 @@
*/
public int growsRecents() {
boolean result = mGrowRecents
- && mWindowManagerProxy.getDockSide() == WindowManager.DOCKED_TOP
+ && mDockSide == WindowManager.DOCKED_TOP
&& getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
if (result) {
return getSnapAlgorithm().getMiddleTarget().position;
@@ -1169,7 +1169,7 @@
}
public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
- if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
+ if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
&& getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
&& getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
mState.growAfterRecentsDrawn = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index be221bb..bf89b01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -279,7 +279,9 @@
public void toggleRecentApps() {
synchronized (mLock) {
mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS);
- mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget();
+ Message msg = mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index de2bdde..49c3f7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar;
-import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -207,7 +206,16 @@
*
* @return {@code null} or an empty string if a trust indication text should not be shown.
*/
- protected String getTrustIndication() {
+ protected String getTrustGrantedIndication() {
+ return null;
+ }
+
+ /**
+ * Returns the indication text indicating that trust is currently being managed.
+ *
+ * @return {@code null} or an empty string if a trust managed text should not be shown.
+ */
+ protected String getTrustManagedIndication() {
return null;
}
@@ -280,17 +288,18 @@
}
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- int userId = ActivityManager.getCurrentUser();
- String trustIndication = getTrustIndication();
+ int userId = KeyguardUpdateMonitor.getCurrentUser();
+ String trustGrantedIndication = getTrustGrantedIndication();
+ String trustManagedIndication = getTrustManagedIndication();
if (!mUserManager.isUserUnlocked(userId)) {
mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
mTextView.setTextColor(Color.WHITE);
} else if (!TextUtils.isEmpty(mTransientIndication)) {
mTextView.switchIndication(mTransientIndication);
mTextView.setTextColor(mTransientTextColor);
- } else if (!TextUtils.isEmpty(trustIndication)
+ } else if (!TextUtils.isEmpty(trustGrantedIndication)
&& updateMonitor.getUserHasTrust(userId)) {
- mTextView.switchIndication(trustIndication);
+ mTextView.switchIndication(trustGrantedIndication);
mTextView.setTextColor(Color.WHITE);
} else if (mPowerPluggedIn) {
String indication = computePowerIndication();
@@ -299,7 +308,11 @@
}
mTextView.switchIndication(indication);
mTextView.setTextColor(Color.WHITE);
-
+ } else if (!TextUtils.isEmpty(trustManagedIndication)
+ && updateMonitor.getUserTrustIsManaged(userId)
+ && !updateMonitor.getUserHasTrust(userId)) {
+ mTextView.switchIndication(trustManagedIndication);
+ mTextView.setTextColor(Color.WHITE);
} else {
mTextView.switchIndication(mRestingIndication);
mTextView.setTextColor(Color.WHITE);
@@ -379,6 +392,9 @@
};
public void setDozing(boolean dozing) {
+ if (mDozing == dozing) {
+ return;
+ }
mDozing = dozing;
updateIndication();
updateDisclosure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 4feaf5c..7062216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -115,25 +115,6 @@
mPm = pm;
mAppSettingsClickListener = onAppSettingsClick;
mStartingUserImportance = startingUserImportance;
- int numTotalChannels = 1;
- numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
- pkg, mAppUid, false /* includeDeleted */);
- if (mNotificationChannels.isEmpty()) {
- throw new IllegalArgumentException("bindNotification requires at least one channel");
- } else {
- if (mNotificationChannels.size() == 1) {
- mSingleNotificationChannel = mNotificationChannels.get(0);
- // Special behavior for the Default channel if no other channels have been defined.
- mIsSingleDefaultChannel =
- (mSingleNotificationChannel.getId()
- .equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
- numTotalChannels <= 1);
- } else {
- mSingleNotificationChannel = null;
- mIsSingleDefaultChannel = false;
- }
- }
-
mAppName = mPkg;
Drawable pkgicon = null;
CharSequence channelNameText = "";
@@ -155,6 +136,24 @@
}
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
+ int numTotalChannels = iNotificationManager.getNumNotificationChannelsForPackage(
+ pkg, mAppUid, false /* includeDeleted */);
+ if (mNotificationChannels.isEmpty()) {
+ throw new IllegalArgumentException("bindNotification requires at least one channel");
+ } else {
+ if (mNotificationChannels.size() == 1) {
+ mSingleNotificationChannel = mNotificationChannels.get(0);
+ // Special behavior for the Default channel if no other channels have been defined.
+ mIsSingleDefaultChannel =
+ (mSingleNotificationChannel.getId()
+ .equals(NotificationChannel.DEFAULT_CHANNEL_ID) &&
+ numTotalChannels <= 1);
+ } else {
+ mSingleNotificationChannel = null;
+ mIsSingleDefaultChannel = false;
+ }
+ }
+
String channelsDescText;
mNumChannelsView = findViewById(R.id.num_channels_desc);
if (mIsSingleDefaultChannel) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 8588668..a6c0cd1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -140,6 +140,9 @@
mDrawable = drawable;
mDrawable.setCallback(this);
mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
+ mDrawable.setAlpha((int) (255 * mViewAlpha));
+ setDrawAsSrc(mDrawAsSrc);
+ updateScreenSize();
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 7162b31..f1d3e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -23,9 +23,11 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -33,6 +35,7 @@
import android.view.ViewStub;
import android.view.WindowManager;
import android.widget.LinearLayout;
+
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -41,6 +44,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
+import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NavigationBarView;
@@ -62,6 +66,7 @@
private CarBatteryController mCarBatteryController;
private BatteryMeterView mBatteryMeterView;
+ private Drawable mNotificationPanelBackground;
private ConnectedDeviceSignalController mConnectedDeviceSignalController;
private CarNavigationBarView mNavigationBarView;
@@ -91,17 +96,18 @@
protected void makeStatusBarView() {
super.makeStatusBarView();
+ mNotificationPanelBackground = getDefaultWallpaper();
+ mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
+
FragmentHostManager manager = FragmentHostManager.get(mStatusBarWindow);
manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
- mBatteryMeterView = ((BatteryMeterView) fragment.getView().findViewById(
- R.id.battery));
+ mBatteryMeterView = fragment.getView().findViewById(R.id.battery);
// By default, the BatteryMeterView should not be visible. It will be toggled
// when a device has connected by bluetooth.
mBatteryMeterView.setVisibility(View.GONE);
- ViewStub stub = (ViewStub) fragment.getView().findViewById(
- R.id.connected_device_signals_stub);
+ ViewStub stub = fragment.getView().findViewById(R.id.connected_device_signals_stub);
View signalsView = stub.inflate();
// When a ViewStub if inflated, it does not respect the margins on the
@@ -256,7 +262,7 @@
if (userSwitcherController.useFullscreenUserSwitcher()) {
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
userSwitcherController,
- (ViewStub) mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
+ mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub));
} else {
super.createUserSwitcher();
}
@@ -314,6 +320,27 @@
return startActivityWithOptions(intent, options.toBundle());
}
+ @Override
+ protected boolean shouldPeek(NotificationData.Entry entry, StatusBarNotification sbn) {
+ // Because space is usually constrained in the auto use-case, there should not be a
+ // pinned notification when the shade has been expanded. Ensure this by not pinning any
+ // notification if the shade is already opened.
+ if (mPanelExpanded) {
+ return false;
+ }
+
+ return super.shouldPeek(entry, sbn);
+ }
+
+ @Override
+ public void animateExpandNotificationsPanel() {
+ // Because space is usually constrained in the auto use-case, there should not be a
+ // pinned notification when the shade has been expanded. Ensure this by removing all heads-
+ // up notifications.
+ mHeadsUpManager.removeAllHeadsUpEntries();
+ super.animateExpandNotificationsPanel();
+ }
+
/**
* Ensures that relevant child views are appropriately recreated when the device's density
* changes.
@@ -322,5 +349,17 @@
protected void onDensityOrFontScaleChanged() {
super.onDensityOrFontScaleChanged();
mController.onDensityOrFontScaleChanged();
+
+ // Need to update the background on density changed in case the change was due to night
+ // mode.
+ mNotificationPanelBackground = getDefaultWallpaper();
+ mScrimController.setScrimBehindDrawable(mNotificationPanelBackground);
+ }
+
+ /**
+ * Returns the {@link Drawable} that represents the wallpaper that the user has currently set.
+ */
+ private Drawable getDefaultWallpaper() {
+ return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index f6bd14c..80854ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -24,10 +24,10 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.support.annotation.VisibleForTesting;
-import android.support.v4.graphics.ColorUtils;
import android.support.v7.graphics.Palette;
import android.util.LayoutDirection;
+import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import java.util.List;
@@ -40,10 +40,31 @@
/**
* The fraction below which we select the vibrant instead of the light/dark vibrant color
*/
- private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 0.75f;
+ private static final float POPULATION_FRACTION_FOR_MORE_VIBRANT = 1.0f;
+
+ /**
+ * Minimum saturation that a muted color must have if there exists if deciding between two
+ * colors
+ */
+ private static final float MIN_SATURATION_WHEN_DECIDING = 0.19f;
+
+ /**
+ * Minimum fraction that any color must have to be picked up as a text color
+ */
+ private static final double MINIMUM_IMAGE_FRACTION = 0.002;
+
+ /**
+ * The population fraction to select the dominant color as the text color over a the colored
+ * ones.
+ */
+ private static final float POPULATION_FRACTION_FOR_DOMINANT = 0.01f;
+
+ /**
+ * The population fraction to select a white or black color as the background over a color.
+ */
private static final float POPULATION_FRACTION_FOR_WHITE_OR_BLACK = 2.5f;
private static final float BLACK_MAX_LIGHTNESS = 0.08f;
- private static final float WHITE_MIN_LIGHTNESS = 0.92f;
+ private static final float WHITE_MIN_LIGHTNESS = 0.90f;
private static final int RESIZE_BITMAP_AREA = 150 * 150;
private final ImageGradientColorizer mColorizer;
private final Context mContext;
@@ -108,8 +129,11 @@
.resizeBitmapArea(RESIZE_BITMAP_AREA);
Palette palette = paletteBuilder.generate();
backgroundColor = findBackgroundColorAndFilter(palette);
- // we want the full region again
- paletteBuilder.setRegion(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ // we want most of the full region again, slightly shifted to the right
+ float textColorStartWidthFraction = 0.4f;
+ paletteBuilder.setRegion((int) (bitmap.getWidth() * textColorStartWidthFraction), 0,
+ bitmap.getWidth(),
+ bitmap.getHeight());
if (mFilteredBackgroundHsl != null) {
paletteBuilder.addFilter((rgb, hsl) -> {
// at least 10 degrees hue difference
@@ -119,78 +143,7 @@
}
paletteBuilder.addFilter(mBlackWhiteFilter);
palette = paletteBuilder.generate();
- int foregroundColor;
- if (ColorUtils.calculateLuminance(backgroundColor) > 0.5) {
- Palette.Swatch first = palette.getDarkVibrantSwatch();
- Palette.Swatch second = palette.getVibrantSwatch();
- if (first != null && second != null) {
- int firstPopulation = first.getPopulation();
- int secondPopulation = second.getPopulation();
- if (firstPopulation / secondPopulation
- < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
- foregroundColor = second.getRgb();
- } else {
- foregroundColor = first.getRgb();
- }
- } else if (first != null) {
- foregroundColor = first.getRgb();
- } else if (second != null) {
- foregroundColor = second.getRgb();
- } else {
- first = palette.getMutedSwatch();
- second = palette.getDarkMutedSwatch();
- if (first != null && second != null) {
- float firstSaturation = first.getHsl()[1];
- float secondSaturation = second.getHsl()[1];
- if (firstSaturation > secondSaturation) {
- foregroundColor = first.getRgb();
- } else {
- foregroundColor = second.getRgb();
- }
- } else if (first != null) {
- foregroundColor = first.getRgb();
- } else if (second != null) {
- foregroundColor = second.getRgb();
- } else {
- foregroundColor = Color.BLACK;
- }
- }
- } else {
- Palette.Swatch first = palette.getLightVibrantSwatch();
- Palette.Swatch second = palette.getVibrantSwatch();
- if (first != null && second != null) {
- int firstPopulation = first.getPopulation();
- int secondPopulation = second.getPopulation();
- if (firstPopulation / secondPopulation
- < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
- foregroundColor = second.getRgb();
- } else {
- foregroundColor = first.getRgb();
- }
- } else if (first != null) {
- foregroundColor = first.getRgb();
- } else if (second != null) {
- foregroundColor = second.getRgb();
- } else {
- first = palette.getMutedSwatch();
- second = palette.getLightMutedSwatch();
- if (first != null && second != null) {
- float firstSaturation = first.getHsl()[1];
- float secondSaturation = second.getHsl()[1];
- if (firstSaturation > secondSaturation) {
- foregroundColor = first.getRgb();
- } else {
- foregroundColor = second.getRgb();
- }
- } else if (first != null) {
- foregroundColor = first.getRgb();
- } else if (second != null) {
- foregroundColor = second.getRgb();
- } else {
- foregroundColor = Color.WHITE;
- }
- }
- }
+ int foregroundColor = selectForegroundColor(backgroundColor, palette);
builder.setColorPalette(backgroundColor, foregroundColor);
} else {
int id = mIsLowPriority
@@ -205,6 +158,95 @@
}
}
+ private int selectForegroundColor(int backgroundColor, Palette palette) {
+ if (NotificationColorUtil.isColorLight(backgroundColor)) {
+ return selectForegroundColorForSwatches(palette.getDarkVibrantSwatch(),
+ palette.getVibrantSwatch(),
+ palette.getDarkMutedSwatch(),
+ palette.getMutedSwatch(),
+ palette.getDominantSwatch(),
+ Color.BLACK);
+ } else {
+ return selectForegroundColorForSwatches(palette.getLightVibrantSwatch(),
+ palette.getVibrantSwatch(),
+ palette.getLightMutedSwatch(),
+ palette.getMutedSwatch(),
+ palette.getDominantSwatch(),
+ Color.WHITE);
+ }
+ }
+
+ private int selectForegroundColorForSwatches(Palette.Swatch moreVibrant,
+ Palette.Swatch vibrant, Palette.Swatch moreMutedSwatch, Palette.Swatch mutedSwatch,
+ Palette.Swatch dominantSwatch, int fallbackColor) {
+ Palette.Swatch coloredCandidate = selectVibrantCandidate(moreVibrant, vibrant);
+ if (coloredCandidate == null) {
+ coloredCandidate = selectMutedCandidate(mutedSwatch, moreMutedSwatch);
+ }
+ if (coloredCandidate != null) {
+ if (dominantSwatch == coloredCandidate) {
+ return coloredCandidate.getRgb();
+ } else if ((float) coloredCandidate.getPopulation() / dominantSwatch.getPopulation()
+ < POPULATION_FRACTION_FOR_DOMINANT
+ && dominantSwatch.getHsl()[1] > MIN_SATURATION_WHEN_DECIDING) {
+ return dominantSwatch.getRgb();
+ } else {
+ return coloredCandidate.getRgb();
+ }
+ } else if (hasEnoughPopulation(dominantSwatch)) {
+ return dominantSwatch.getRgb();
+ } else {
+ return fallbackColor;
+ }
+ }
+
+ private Palette.Swatch selectMutedCandidate(Palette.Swatch first,
+ Palette.Swatch second) {
+ boolean firstValid = hasEnoughPopulation(first);
+ boolean secondValid = hasEnoughPopulation(second);
+ if (firstValid && secondValid) {
+ float firstSaturation = first.getHsl()[1];
+ float secondSaturation = second.getHsl()[1];
+ float populationFraction = first.getPopulation() / (float) second.getPopulation();
+ if (firstSaturation * populationFraction > secondSaturation) {
+ return first;
+ } else {
+ return second;
+ }
+ } else if (firstValid) {
+ return first;
+ } else if (secondValid) {
+ return second;
+ }
+ return null;
+ }
+
+ private Palette.Swatch selectVibrantCandidate(Palette.Swatch first, Palette.Swatch second) {
+ boolean firstValid = hasEnoughPopulation(first);
+ boolean secondValid = hasEnoughPopulation(second);
+ if (firstValid && secondValid) {
+ int firstPopulation = first.getPopulation();
+ int secondPopulation = second.getPopulation();
+ if (firstPopulation / (float) secondPopulation
+ < POPULATION_FRACTION_FOR_MORE_VIBRANT) {
+ return second;
+ } else {
+ return first;
+ }
+ } else if (firstValid) {
+ return first;
+ } else if (secondValid) {
+ return second;
+ }
+ return null;
+ }
+
+ private boolean hasEnoughPopulation(Palette.Swatch swatch) {
+ // We want a fraction that is at least 1% of the image
+ return swatch != null
+ && (swatch.getPopulation() / (float) RESIZE_BITMAP_AREA > MINIMUM_IMAGE_FRACTION);
+ }
+
private int findBackgroundColorAndFilter(Palette palette) {
// by default we use the dominant palette
Palette.Swatch dominantSwatch = palette.getDominantSwatch();
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 41a60e2..037e901 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -100,6 +100,7 @@
public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+ public static final String CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = "lift_to_launch_ml";
public static final String EXTRA_CAMERA_LAUNCH_SOURCE
= "com.android.systemui.camera_launch_source";
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 2124011..95f32bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -18,6 +18,7 @@
import android.app.ActivityManager;
import android.content.Context;
+import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
@@ -55,6 +56,7 @@
protected final ViewGroup mContainer;
private final FalsingManager mFalsingManager;
private final DismissCallbackRegistry mDismissCallbackRegistry;
+ private final Handler mHandler;
protected KeyguardHostView mKeyguardView;
protected ViewGroup mRoot;
private boolean mShowingSoon;
@@ -66,6 +68,7 @@
mBouncerPromptReason = mCallback.getBouncerPromptReason();
}
};
+ private final Runnable mRemoveViewRunnable = this::removeView;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -77,6 +80,7 @@
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
mFalsingManager = FalsingManager.getInstance(mContext);
mDismissCallbackRegistry = dismissCallbackRegistry;
+ mHandler = new Handler();
}
public void show(boolean resetSecuritySelection) {
@@ -179,10 +183,14 @@
mKeyguardView.cancelDismissAction();
mKeyguardView.cleanUp();
}
- if (destroyView) {
- removeView();
- } else if (mRoot != null) {
+ if (mRoot != null) {
mRoot.setVisibility(View.INVISIBLE);
+ if (destroyView) {
+
+ // We have a ViewFlipper that unregisters a broadcast when being detached, which may
+ // be slow because of AM lock contention during unlocking. We can delay it a bit.
+ mHandler.postDelayed(mRemoveViewRunnable, 50);
+ }
}
}
@@ -226,6 +234,7 @@
}
protected void ensureView() {
+ mHandler.removeCallbacks(mRemoveViewRunnable);
if (mRoot == null) {
inflateView();
}
@@ -233,6 +242,7 @@
protected void inflateView() {
removeView();
+ mHandler.removeCallbacks(mRemoveViewRunnable);
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
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 1fd329c..8d9d461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,16 +36,15 @@
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.Display;
-import android.view.IDockedStackListener.Stub;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
@@ -336,8 +335,10 @@
mAccessibilityIcon = getDrawable(ctx, R.drawable.ic_sysbar_accessibility_button,
R.drawable.ic_sysbar_accessibility_button_dark);
- Context darkContext = new ContextThemeWrapper(ctx, R.style.DualToneDarkTheme);
- Context lightContext = new ContextThemeWrapper(ctx, R.style.DualToneLightTheme);
+ int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+ int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+ Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+ Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
mImeIcon = getDrawable(darkContext, lightContext,
R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
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 4581204..52838b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -128,8 +128,7 @@
protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
NotificationData notificationData, boolean showAmbient) {
- if (notificationData.isAmbient(entry.key) && !showAmbient
- && !NotificationData.showNotificationEvenIfUnprovisioned(entry.notification)) {
+ if (notificationData.isAmbient(entry.key) && !showAmbient) {
return false;
}
if (!StatusBar.isTopLevelChild(entry)) {
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 9cc3d81..290119b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2390,6 +2390,8 @@
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
} else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+ } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER;
} else {
// Default.
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 e378e871..9d1d038 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -34,10 +34,9 @@
import android.widget.FrameLayout;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.DejankUtils;
-import com.android.systemui.EventLogTags;
-import com.android.systemui.Interpolators;
import com.android.keyguard.LatencyTracker;
+import com.android.systemui.DejankUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
@@ -833,6 +832,14 @@
}
}
+ // If we are closing the panel and we are almost there due to a slow decelerating
+ // interpolator, abort the animation.
+ if (mExpandedHeight < 1f && mExpandedHeight != 0f && mClosing) {
+ mExpandedHeight = 0f;
+ if (mHeightAnimator != null) {
+ mHeightAnimator.end();
+ }
+ }
mExpandedFraction = Math.min(1f,
fhWithoutOverExpansion == 0 ? 0 : mExpandedHeight / fhWithoutOverExpansion);
onHeightUpdated(mExpandedHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 41fb5f7..f3ba5aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -58,6 +58,7 @@
import com.android.systemui.DockedStackExistsListener;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -128,6 +129,7 @@
private final KeyguardMonitor mKeyguardMonitor;
private final LocationController mLocationController;
private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
// Assume it's all good unless we hear otherwise. We don't always seem
// to get broadcasts that it *is* there.
@@ -472,30 +474,38 @@
}
private void updateManagedProfile() {
- try {
- final boolean showIcon;
- final int userId = ActivityManager.getService().getLastResumedActivityUserId();
- if (mUserManager.isManagedProfile(userId) && !mKeyguardMonitor.isShowing()) {
- showIcon = true;
- mIconController.setIcon(mSlotManagedProfile,
- R.drawable.stat_sys_managed_profile_status,
- mContext.getString(R.string.accessibility_managed_profile));
- } else if (mManagedProfileInQuietMode) {
- showIcon = true;
- mIconController.setIcon(mSlotManagedProfile,
- R.drawable.stat_sys_managed_profile_status_off,
- mContext.getString(R.string.accessibility_managed_profile));
- } else {
- showIcon = false;
+ // getLastResumedActivityUserId needds to acquire the AM lock, which may be contended in
+ // some cases. Since it doesn't really matter here whether it's updated in this frame
+ // or in the next one, we call this method from our UI offload thread.
+ mUiOffloadThread.submit(() -> {
+ final int userId;
+ try {
+ userId = ActivityManager.getService().getLastResumedActivityUserId();
+ boolean isManagedProfile = mUserManager.isManagedProfile(userId);
+ mHandler.post(() -> {
+ final boolean showIcon;
+ if (isManagedProfile && !mKeyguardMonitor.isShowing()) {
+ showIcon = true;
+ mIconController.setIcon(mSlotManagedProfile,
+ R.drawable.stat_sys_managed_profile_status,
+ mContext.getString(R.string.accessibility_managed_profile));
+ } else if (mManagedProfileInQuietMode) {
+ showIcon = true;
+ mIconController.setIcon(mSlotManagedProfile,
+ R.drawable.stat_sys_managed_profile_status_off,
+ mContext.getString(R.string.accessibility_managed_profile));
+ } else {
+ showIcon = false;
+ }
+ if (mManagedProfileIconVisible != showIcon) {
+ mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
+ mManagedProfileIconVisible = showIcon;
+ }
+ });
+ } catch (RemoteException e) {
+ Log.w(TAG, "updateManagedProfile: ", e);
}
- if (mManagedProfileIconVisible != showIcon) {
- mIconController.setIconVisibility(mSlotManagedProfile, showIcon);
- mManagedProfileIconVisible = showIcon;
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "updateManagedProfile: ", ex);
- // ignore
- }
+ });
}
private void updateForegroundInstantApps() {
@@ -503,26 +513,22 @@
ArraySet<Pair<String, Integer>> notifs = new ArraySet<>(mCurrentNotifs);
IPackageManager pm = AppGlobals.getPackageManager();
mCurrentNotifs.clear();
- try {
- ArraySet<Integer> stacksToCheck = new ArraySet<>();
- int[] STACKS_TO_CHECK = new int[]{
- StackId.FULLSCREEN_WORKSPACE_STACK_ID,
- StackId.DOCKED_STACK_ID,
- };
- int focusedId = ActivityManager.getService().getFocusedStackId();
- if (focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID
- || focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID) {
- checkStack(StackId.FULLSCREEN_WORKSPACE_STACK_ID, notifs, noMan, pm);
+ mUiOffloadThread.submit(() -> {
+ try {
+ int focusedId = ActivityManager.getService().getFocusedStackId();
+ if (focusedId == StackId.FULLSCREEN_WORKSPACE_STACK_ID) {
+ checkStack(StackId.FULLSCREEN_WORKSPACE_STACK_ID, notifs, noMan, pm);
+ }
+ if (mDockedStackExists) {
+ checkStack(StackId.DOCKED_STACK_ID, notifs, noMan, pm);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
}
- if (mDockedStackExists) {
- checkStack(StackId.DOCKED_STACK_ID, notifs, noMan, pm);
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- // Cancel all the leftover notifications that don't have a foreground process anymore.
- notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
- new UserHandle(v.second)));
+ // Cancel all the leftover notifications that don't have a foreground process anymore.
+ notifs.forEach(v -> noMan.cancelAsUser(v.first, SystemMessage.NOTE_INSTANT_APPS,
+ new UserHandle(v.second)));
+ });
}
private void checkStack(int stackId, ArraySet<Pair<String, Integer>> notifs,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 916b603..970d1de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -121,12 +121,12 @@
public void onPanelCollapsed() {
super.onPanelCollapsed();
// Close the status bar in the next frame so we can show the end of the animation.
- DejankUtils.postAfterTraversal(mHideExpandedRunnable);
+ post(mHideExpandedRunnable);
mIsFullyOpenedPanel = false;
}
public void removePendingHideExpandedRunnables() {
- DejankUtils.removeCallbacks(mHideExpandedRunnable);
+ removeCallbacks(mHideExpandedRunnable);
}
@Override
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 1799bc9..4541d07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.util.TypedValue;
@@ -260,6 +261,14 @@
: SCRIM_IN_FRONT_ALPHA;
}
+ /**
+ * Sets the given drawable as the background of the scrim that shows up behind the
+ * notifications.
+ */
+ public void setScrimBehindDrawable(Drawable drawable) {
+ mScrimBehind.setDrawable(drawable);
+ }
+
protected void scheduleUpdate() {
if (mUpdatePending) return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 805450e..01bab3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -95,6 +95,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.SystemService;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
@@ -164,6 +165,7 @@
import com.android.systemui.SwipeHelper;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
+import com.android.systemui.UiOffloadThread;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.classifier.FalsingLog;
import com.android.systemui.classifier.FalsingManager;
@@ -184,6 +186,7 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.activity.UndockingTaskEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -545,6 +548,7 @@
private ViewMediatorCallback mKeyguardViewMediatorCallback;
protected ScrimController mScrimController;
protected DozeScrimController mDozeScrimController;
+ private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
private final Runnable mAutohide = new Runnable() {
@Override
@@ -716,7 +720,7 @@
private NetworkController mNetworkController;
private KeyguardMonitorImpl mKeyguardMonitor;
private BatteryController mBatteryController;
- private boolean mPanelExpanded;
+ protected boolean mPanelExpanded;
private boolean mKeyguardRequested;
private boolean mIsKeyguard;
private LogMaker mStatusBarStateLog;
@@ -792,8 +796,6 @@
mAccessibilityManager = (AccessibilityManager)
mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE));
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
@@ -1019,12 +1021,6 @@
new IconManager((ViewGroup) mKeyguardStatusBar.findViewById(R.id.statusIcons)));
mIconController = Dependency.get(StatusBarIconController.class);
- if (!ActivityManager.isHighEndGfx()) {
- mStatusBarWindow.setBackground(null);
- mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
- R.color.notification_panel_solid_background)));
- }
-
mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
mHeadsUpManager.setBar(this);
mHeadsUpManager.addListener(this);
@@ -1550,13 +1546,7 @@
}
void awakenDreams() {
- if (mDreamManager != null) {
- try {
- mDreamManager.awaken();
- } catch (RemoteException e) {
- // fine, stay asleep then
- }
- }
+ SystemServicesProxy.getInstance(mContext).awakenDreamsAsync();
}
public UserHandle getCurrentUserHandle() {
@@ -4407,7 +4397,7 @@
checkBarModes();
updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
- mStatusBarKeyguardViewManager.isSecure(),
+ mUnlockMethodCache.isMethodSecure(),
mStatusBarKeyguardViewManager.isOccluded());
Trace.endSection();
}
@@ -5243,7 +5233,6 @@
protected boolean mDisableNotificationAlerts = false;
protected DevicePolicyManager mDevicePolicyManager;
- protected IDreamManager mDreamManager;
protected PowerManager mPowerManager;
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -6909,12 +6898,8 @@
return false;
}
- boolean inUse = mPowerManager.isScreenOn();
- try {
- inUse = inUse && !mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.d(TAG, "failed to query dream manager", e);
- }
+ boolean inUse = mPowerManager.isScreenOn()
+ && !SystemServicesProxy.getInstance(mContext).isDreaming();
if (!inUse && !isDozing()) {
if (DEBUG) {
@@ -6991,11 +6976,13 @@
@Override
public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
- try {
- mBarService.onNotificationExpansionChanged(key, userAction, expanded);
- } catch (RemoteException e) {
- // Ignore.
- }
+ mUiOffloadThread.submit(() -> {
+ try {
+ mBarService.onNotificationExpansionChanged(key, userAction, expanded);
+ } catch (RemoteException e) {
+ // Ignore.
+ }
+ });
}
public boolean isKeyguardSecure() {
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 5f7ac5d..70f2260 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -257,6 +257,12 @@
mEntryPool.release(remove);
}
+ public void removeAllHeadsUpEntries() {
+ for (String key : mHeadsUpEntries.keySet()) {
+ removeHeadsUpEntry(mHeadsUpEntries.get(key).entry);
+ }
+ }
+
private void updatePinnedMode() {
boolean hasPinnedNotification = hasPinnedNotificationInternal();
if (hasPinnedNotification == mHasPinnedNotification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
index d6c080a..7bce33a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java
@@ -124,13 +124,11 @@
mKeyguardFadingAway = true;
mKeyguardFadingAwayDelay = delay;
mKeyguardFadingAwayDuration = fadeoutDuration;
- notifyKeyguardChanged();
}
public void notifyKeyguardDoneFading() {
mKeyguardFadingAway = false;
mKeyguardGoingAway = false;
- notifyKeyguardChanged();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 53671a1..e1acc9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -872,7 +872,14 @@
private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() {
@Override
public void onKeyguardShowingChanged() {
- notifyAdapters();
+
+ // When Keyguard is going away, we don't need to update our items immediately which
+ // helps making the transition faster.
+ if (!mKeyguardMonitor.isShowing()) {
+ mHandler.post(UserSwitcherController.this::notifyAdapters);
+ } else {
+ notifyAdapters();
+ }
}
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index aadae0f..0aac1c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -21,15 +21,21 @@
import android.os.MessageQueue;
import android.support.test.InstrumentationRegistry;
import android.testing.LeakCheck;
+import android.util.Log;
import org.junit.Before;
import org.junit.Rule;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
/**
* Base class that does System UI specific setup.
*/
public abstract class SysuiTestCase {
+ private static final String TAG = "SysuiTestCase";
+
private Handler mHandler;
@Rule
public SysuiTestableContext mContext = new SysuiTestableContext(
@@ -57,6 +63,15 @@
waitForIdleSync(mHandler);
}
+ protected void waitForUiOffloadThread() {
+ Future<?> future = Dependency.get(UiOffloadThread.class).submit(() -> {});
+ try {
+ future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(TAG, "Failed to wait for ui offload thread.", e);
+ }
+ }
+
public static void waitForIdleSync(Handler h) {
validateThread(h.getLooper());
Idler idler = new Idler(null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index ee0fe7b..56c07f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -27,6 +27,7 @@
boolean pulseAborted;
boolean pulseExtended;
boolean animateWakeup;
+ boolean dozing;
@Override
public void addCallback(@NonNull Callback callback) {
@@ -40,7 +41,7 @@
@Override
public void startDozing() {
- throw new RuntimeException("not implemented");
+ dozing = true;
}
@Override
@@ -50,7 +51,7 @@
@Override
public void stopDozing() {
- throw new RuntimeException("not implemented");
+ dozing = false;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
new file mode 100644
index 0000000..9188122
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
+import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
+import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.util.wakelock.WakeLockFake;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DozeUiTest {
+
+ private Context mContext;
+ private AlarmManager mAlarmManager;
+ private DozeMachine mMachine;
+ private WakeLockFake mWakeLock;
+ private DozeHostFake mHost;
+ private Handler mHandler;
+ private HandlerThread mHandlerThread;
+ private DozeUi mDozeUi;
+
+ @Before
+ public void setUp() throws Exception {
+ mHandlerThread = new HandlerThread("DozeUiTest");
+ mHandlerThread.start();
+ mContext = InstrumentationRegistry.getContext();
+ mAlarmManager = mock(AlarmManager.class);
+ mMachine = mock(DozeMachine.class);
+ mWakeLock = new WakeLockFake();
+ mHost = new DozeHostFake();
+ mHandler = mHandlerThread.getThreadHandler();
+
+ mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mHandlerThread.quit();
+ mHandler = null;
+ mHandlerThread = null;
+ }
+
+ @Test
+ public void pausingAndUnpausingAod_registersTimeTickAfterUnpausing() throws Exception {
+ mDozeUi.transitionTo(UNINITIALIZED, INITIALIZED);
+ mDozeUi.transitionTo(INITIALIZED, DOZE_AOD);
+ mDozeUi.transitionTo(DOZE_AOD, DOZE_AOD_PAUSED);
+
+ clearInvocations(mAlarmManager);
+
+ mDozeUi.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD);
+
+ verify(mAlarmManager).setExact(anyInt(), anyLong(), eq("doze_time_tick"), any(), any());
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
index 131a70b..308670d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/DismissCallbackRegistryTest.java
@@ -23,6 +23,8 @@
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.UiOffloadThread;
import org.junit.Before;
import org.junit.Test;
@@ -35,7 +37,7 @@
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class DismissCallbackRegistryTest {
+public class DismissCallbackRegistryTest extends SysuiTestCase {
private final DismissCallbackRegistry mDismissCallbackRegistry = new DismissCallbackRegistry();
private @Mock IKeyguardDismissCallback mMockCallback;
@@ -50,6 +52,7 @@
public void testCancelled() throws Exception {
mDismissCallbackRegistry.addCallback(mMockCallback);
mDismissCallbackRegistry.notifyDismissCancelled();
+ waitForUiOffloadThread();
verify(mMockCallback).onDismissCancelled();
}
@@ -58,6 +61,7 @@
mDismissCallbackRegistry.addCallback(mMockCallback);
mDismissCallbackRegistry.addCallback(mMockCallback2);
mDismissCallbackRegistry.notifyDismissCancelled();
+ waitForUiOffloadThread();
verify(mMockCallback).onDismissCancelled();
verify(mMockCallback2).onDismissCancelled();
}
@@ -66,6 +70,7 @@
public void testSucceeded() throws Exception {
mDismissCallbackRegistry.addCallback(mMockCallback);
mDismissCallbackRegistry.notifyDismissSucceeded();
+ waitForUiOffloadThread();
verify(mMockCallback).onDismissSucceeded();
}
@@ -74,6 +79,7 @@
mDismissCallbackRegistry.addCallback(mMockCallback);
mDismissCallbackRegistry.addCallback(mMockCallback2);
mDismissCallbackRegistry.notifyDismissSucceeded();
+ waitForUiOffloadThread();
verify(mMockCallback).onDismissSucceeded();
verify(mMockCallback2).onDismissSucceeded();
}
@@ -83,6 +89,7 @@
mDismissCallbackRegistry.addCallback(mMockCallback);
mDismissCallbackRegistry.notifyDismissSucceeded();
mDismissCallbackRegistry.notifyDismissSucceeded();
+ waitForUiOffloadThread();
verify(mMockCallback, times(1)).onDismissSucceeded();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
index 4d632af..f57b6b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
@@ -62,6 +62,7 @@
when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
.thenReturn(mThumbnailData);
mLoader.setVisible(true);
+ mLoader.setTaskLoadQueueIdle(true);
}
@Test
@@ -75,6 +76,11 @@
assertFalse(mLoader.isLoading());
mLoader.setFlingingFast(false);
assertTrue(mLoader.isLoading());
+ mLoader.setFlingingFast(false);
+ mLoader.setTaskLoadQueueIdle(false);
+ assertFalse(mLoader.isLoading());
+ mLoader.setTaskLoadQueueIdle(true);
+ assertTrue(mLoader.isLoading());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 0118a80..c7d5e68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -74,6 +74,7 @@
@UiThreadTest
public class NotificationInfoTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "test_package";
+ private static final int TEST_UID = 1;
private static final String TEST_CHANNEL = "test_channel";
private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME";
@@ -96,13 +97,13 @@
packageInfo.packageName = TEST_PACKAGE_NAME;
when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(packageInfo);
final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = 1; // non-zero
+ applicationInfo.uid = TEST_UID; // non-zero
when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(
applicationInfo);
// Package has one channel by default.
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(1);
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1);
// Some test channels.
mNotificationChannel = new NotificationChannel(
@@ -185,7 +186,7 @@
final NotificationChannelGroup notificationChannelGroup =
new NotificationChannelGroup("test_group_id", "Test Group Name");
when(mMockINotificationManager.getNotificationChannelGroupForPackage(
- eq("test_group_id"), eq(TEST_PACKAGE_NAME), anyInt()))
+ eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
.thenReturn(notificationChannelGroup);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
@@ -224,7 +225,7 @@
public void testBindNotification_DefaultChannelUsesNameWhenMoreThanOneChannelExists()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
@@ -309,7 +310,7 @@
@Test
public void testBindNotification_SettingsTextWithMultipleChannels() throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn,
@@ -352,7 +353,7 @@
public void testBindNotification_NumChannelsTextDisplaysWhenMoreThanOneChannelExists()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null,
@@ -380,7 +381,7 @@
public void testBindNotification_NumChannelsTextScalesWithNumberOfChannels()
throws Exception {
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(2);
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel),
mNotificationChannel.getImportance(), mSbn, null, null, null,
@@ -511,7 +512,7 @@
mNotificationChannel.getImportance(), mSbn, null, null, null,
null, null);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -525,7 +526,7 @@
Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch);
enabledSwitch.setChecked(false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -538,7 +539,7 @@
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -552,7 +553,7 @@
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -612,7 +613,7 @@
null, Collections.singleton(TEST_PACKAGE_NAME));
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), anyInt(), any());
+ anyString(), eq(TEST_UID), any());
}
@Test
@@ -630,7 +631,7 @@
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), anyInt(), updated.capture());
+ anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& NotificationChannel.USER_LOCKED_IMPORTANCE) != 0);
}
@@ -647,7 +648,7 @@
enabledSwitch.setChecked(false);
mNotificationInfo.handleCloseControls(false, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
@@ -664,7 +665,7 @@
enabledSwitch.setChecked(false);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
@@ -682,7 +683,7 @@
enabledSwitch.setChecked(false);
mNotificationInfo.handleCloseControls(true, false);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- eq(TEST_PACKAGE_NAME), anyInt(), eq(mNotificationChannel));
+ eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
}
@Test
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index b755dd6..f519db8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3974,6 +3974,16 @@
// OPEN: Settings > Battery > High Usage
DIALOG_HANDLE_ANOMALY = 988;
+ // ACTION: Camera lift gesture
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O
+ ACTION_CAMERA_LIFT_TRIGGER = 989;
+
+ // OPEN: Choose screen lock dialog in Settings
+ // CATEGORY: SETTINGS
+ // OS: O DR
+ SETTINGS_CHOOSE_LOCK_DIALOG = 990;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index 0e30fb2..de8a518 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -26,6 +26,7 @@
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
import com.android.internal.annotations.GuardedBy;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -96,7 +97,7 @@
mNodeFromOriginalWindow = info;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
- throw new RuntimeException("Callback with unexpected interactionId"); // Remove
+ return;
}
mSingleNodeCallbackHappened = true;
@@ -119,7 +120,7 @@
mNodesWithReplacementActions = infos;
} else {
Slog.e(LOG_TAG, "Callback with unexpected interactionId");
- throw new RuntimeException("Callback with unexpected interactionId"); // Remove
+ return;
}
callbackForSingleNode = mSingleNodeCallbackHappened;
callbackForMultipleNodes = mMultiNodeCallbackHappened;
@@ -147,7 +148,7 @@
if (DEBUG) {
Slog.e(LOG_TAG, "Extra callback");
}
- throw new RuntimeException("Extra callback"); // Replace with return before submit
+ return;
}
if (mNodeFromOriginalWindow != null) {
replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
@@ -172,7 +173,7 @@
if (DEBUG) {
Slog.e(LOG_TAG, "Extra callback");
}
- throw new RuntimeException("Extra callback"); // Replace with return before submit
+ return;
}
if (mNodesFromOriginalWindow != null) {
for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) {
@@ -180,7 +181,8 @@
}
}
recycleReplaceActionNodesLocked();
- nodesToReturn = mNodesFromOriginalWindow;
+ nodesToReturn = (mNodesFromOriginalWindow == null)
+ ? null : new ArrayList<>(mNodesFromOriginalWindow);
mDone = true;
}
try {
@@ -195,6 +197,12 @@
@GuardedBy("mLock")
private void replaceActionsOnInfoLocked(AccessibilityNodeInfo info) {
info.removeAllActions();
+ info.setClickable(false);
+ info.setFocusable(false);
+ info.setContextClickable(false);
+ info.setScrollable(false);
+ info.setLongClickable(false);
+ info.setDismissable(false);
// We currently only replace actions for the root node
if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID)
&& mNodesWithReplacementActions != null) {
@@ -213,6 +221,12 @@
info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
}
+ info.setClickable(nodeWithReplacementActions.isClickable());
+ info.setFocusable(nodeWithReplacementActions.isFocusable());
+ info.setContextClickable(nodeWithReplacementActions.isContextClickable());
+ info.setScrollable(nodeWithReplacementActions.isScrollable());
+ info.setLongClickable(nodeWithReplacementActions.isLongClickable());
+ info.setDismissable(nodeWithReplacementActions.isDismissable());
}
}
}
@@ -220,6 +234,7 @@
@GuardedBy("mLock")
private void recycleReplaceActionNodesLocked() {
+ if (mNodesWithReplacementActions == null) return;
for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) {
AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i);
nodeWithReplacementAction.recycle();
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 6e87f88..e380f2c 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -938,7 +938,12 @@
if (pointerIdBits == ALL_POINTER_ID_BITS) {
event = prototype;
} else {
- event = prototype.split(pointerIdBits);
+ try {
+ event = prototype.split(pointerIdBits);
+ } catch (IllegalArgumentException e) {
+ Slog.e(LOG_TAG, "sendMotionEvent: Failed to split motion event: " + e);
+ return;
+ }
}
if (action == MotionEvent.ACTION_DOWN) {
event.setDownTime(event.getEventTime());
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 41a78a7..93b5ed5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -172,7 +172,6 @@
startTrackingPackageChanges();
}
-
private void startTrackingPackageChanges() {
PackageMonitor monitor = new PackageMonitor() {
@Override
@@ -335,6 +334,7 @@
void listSessions(int userId, IResultReceiver receiver) {
Slog.i(TAG, "listSessions() for userId " + userId);
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
final Bundle resultData = new Bundle();
final ArrayList<String> sessions = new ArrayList<>();
@@ -364,6 +364,7 @@
void reset() {
Slog.i(TAG, "reset()");
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
final int size = mServicesCache.size();
for (int i = 0; i < size; i++) {
@@ -376,6 +377,8 @@
// Called by Shell command.
void setLogLevel(int level) {
Slog.i(TAG, "setLogLevel(): " + level);
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
boolean debug = false;
boolean verbose = false;
if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
@@ -391,6 +394,8 @@
// Called by Shell command.
int getLogLevel() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
@@ -400,6 +405,8 @@
// Called by Shell command.
public int getMaxPartitions() {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
synchronized (mLock) {
return sPartitionMaxCount;
}
@@ -407,6 +414,7 @@
// Called by Shell command.
public void setMaxPartitions(int max) {
+ mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
Slog.i(TAG, "setMaxPartitions(): " + max);
synchronized (mLock) {
sPartitionMaxCount = max;
@@ -550,18 +558,39 @@
}
@Override
- public void updateSession(int sessionId, AutofillId id, Rect bounds,
+ public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
AutofillValue value, int action, int flags, int userId) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
if (service != null) {
- service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value,
- action, flags);
+ service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
+ value, action, flags);
}
}
}
@Override
+ public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
+ AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
+ boolean hasCallback, int flags, String packageName, int sessionId, int action) {
+ boolean restart = false;
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId,
+ bounds, value, action, flags);
+ }
+ }
+ if (restart) {
+ return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
+ hasCallback, flags, packageName);
+ }
+
+ // Nothing changed...
+ return sessionId;
+ }
+
+ @Override
public void finishSession(int sessionId, int userId) {
synchronized (mLock) {
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 35371a7..2cb0bd5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.autofill;
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;
@@ -275,7 +276,7 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
- hasCallback, flags, packageName);
+ hasCallback, packageName);
if (newSession == null) {
return NO_SESSION;
}
@@ -359,8 +360,7 @@
}
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
- @NonNull IBinder appCallbackToken, boolean hasCallback, int flags,
- @NonNull String packageName) {
+ @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull String packageName) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -402,18 +402,29 @@
}
}
- void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
+ /**
+ * Updates a session and returns whether it should be restarted.
+ */
+ boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
AutofillValue value, int action, int flags) {
final Session session = mSessions.get(sessionId);
if (session == null || session.uid != uid) {
- if (sVerbose) {
- Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId + "(" + uid
- + ")");
+ if ((flags & FLAG_MANUAL_REQUEST) != 0) {
+ if (sDebug) {
+ Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
+ + autofillId);
+ }
+ return true;
}
- return;
+ if (sVerbose) {
+ Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
+ + "(" + uid + ")");
+ }
+ return false;
}
session.updateLocked(autofillId, virtualBounds, value, action, flags);
+ return false;
}
void removeSessionLocked(int sessionId) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 35f4fae..9aebf6d 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -404,10 +404,86 @@
}
private static abstract class PendingRequest implements Runnable {
- void cancel() {
+ protected final Object mLock = new Object();
+ private final WeakReference<RemoteFillService> mWeakService;
+ private final Runnable mTimeoutTrigger;
+ private final Handler mServiceHandler;
+
+ @GuardedBy("mLock")
+ private boolean mCancelled;
+
+ @GuardedBy("mLock")
+ private boolean mCompleted;
+
+ PendingRequest(RemoteFillService service) {
+ mWeakService = new WeakReference<>(service);
+ mServiceHandler = service.mHandler.getHandler();
+ mTimeoutTrigger = () -> {
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
+ }
+ mCompleted = true;
+ }
+
+ final RemoteFillService remoteService = mWeakService.get();
+ if (remoteService != null) {
+ fail(remoteService);
+ }
+ };
+ mServiceHandler.postAtTime(mTimeoutTrigger,
+ SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
}
+ protected RemoteFillService getService() {
+ return mWeakService.get();
+ }
+
+ /**
+ * Sub-classes must call this method when the remote service finishes, i.e., when it
+ * called {@code onFill...} or {@code onSave...}.
+ *
+ * @return {@code false} in the service is already finished, {@code true} otherwise.
+ */
+ protected final boolean finish() {
+ synchronized (mLock) {
+ if (mCompleted || mCancelled) {
+ return false;
+ }
+ mCompleted = true;
+ }
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ return true;
+ }
+
+ protected boolean isCancelledLocked() {
+ return mCancelled;
+ }
+
+ /**
+ * Cancels the service.
+ *
+ * @return {@code false} if service is already canceled, {@code true} otherwise.
+ */
+ boolean cancel() {
+ synchronized (mLock) {
+ if (mCancelled || mCompleted) {
+ return false;
+ }
+ mCancelled = true;
+ }
+
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ return true;
+ }
+
+ /**
+ * Called by the self-destructure timeout when the AutofilllService didn't reply to the
+ * request on time.
+ */
+ abstract void fail(RemoteFillService remoteService);
+
/**
* @return whether this request leads to a final state where no
* other requests can be made.
@@ -418,22 +494,14 @@
}
private static final class PendingFillRequest extends PendingRequest {
- private final Object mLock = new Object();
-
- private final WeakReference<RemoteFillService> mWeakService;
private final FillRequest mRequest;
private final IFillCallback mCallback;
private ICancellationSignal mCancellation;
- @GuardedBy("mLock")
- private boolean mCancelled;
-
- @GuardedBy("mLock")
- private boolean mCompleted;
-
public PendingFillRequest(FillRequest request, RemoteFillService service) {
+ super(service);
mRequest = request;
- mWeakService = new WeakReference<>(service);
+
mCallback = new IFillCallback.Stub() {
@Override
public void onCancellable(ICancellationSignal cancellation) {
@@ -441,7 +509,7 @@
final boolean cancelled;
synchronized (mLock) {
mCancellation = cancellation;
- cancelled = mCancelled;
+ cancelled = isCancelledLocked();
}
if (cancelled) {
try {
@@ -455,15 +523,10 @@
@Override
public void onSuccess(FillResponse response) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService remoteService = mWeakService.get();
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
- service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
getCallingUid(), request.getFlags(), response);
}
@@ -471,132 +534,100 @@
@Override
public void onFailure(CharSequence message) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService remoteService = mWeakService.get();
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
- service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
remoteService.dispatchOnFillRequestFailure(
PendingFillRequest.this, message);
}
}
};
- service.mHandler.getHandler().postAtTime(() -> {
- cancel();
- try {
- mCallback.onFailure(null);
- } catch (RemoteException e) {
- /* ignore */
- }
- }, PendingFillRequest.this,
- SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+ }
+
+ @Override
+ void fail(RemoteFillService remoteService) {
+ remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
@Override
public void run() {
- RemoteFillService remoteService = mWeakService.get();
+ final RemoteFillService remoteService = getService();
if (remoteService != null) {
try {
remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on fill request", e);
- cancel();
+
+ remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
}
}
@Override
- public void cancel() {
- final ICancellationSignal cancellation;
- synchronized (mLock) {
- if (mCancelled) {
- return;
+ public boolean cancel() {
+ if (!super.cancel()) return false;
+
+ final ICancellationSignal cancellation = mCancellation;
+ if (cancellation != null) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(LOG_TAG, "Error cancelling a fill request", e);
}
- mCancelled = true;
- cancellation = mCancellation;
}
- if (cancellation == null) {
- return;
- }
- try {
- cancellation.cancel();
- } catch (RemoteException e) {
- Slog.e(LOG_TAG, "Error cancelling a fill request", e);
- }
+ return true;
}
}
private static final class PendingSaveRequest extends PendingRequest {
- private final Object mLock = new Object();
-
- private final WeakReference<RemoteFillService> mWeakService;
private final SaveRequest mRequest;
private final ISaveCallback mCallback;
- @GuardedBy("mLock")
- private boolean mCompleted;
-
public PendingSaveRequest(@NonNull SaveRequest request,
@NonNull RemoteFillService service) {
+ super(service);
mRequest = request;
- mWeakService = new WeakReference<>(service);
+
mCallback = new ISaveCallback.Stub() {
@Override
public void onSuccess() {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- cancel();
- RemoteFillService service = mWeakService.get();
- if (service != null) {
- service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
- service.dispatchOnSaveRequestSuccess(
- PendingSaveRequest.this);
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
+ remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this);
}
}
@Override
public void onFailure(CharSequence message) {
- synchronized (mLock) {
- if (mCompleted) {
- return;
- }
- mCompleted = true;
- }
- RemoteFillService service = mWeakService.get();
- if (service != null) {
- service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
- service.dispatchOnSaveRequestFailure(
- PendingSaveRequest.this, message);
+ if (!finish()) return;
+
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
+ remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this,
+ message);
}
}
};
- service.mHandler.getHandler().postAtTime(() -> {
- cancel();
- try {
- mCallback.onFailure(null);
- } catch (RemoteException e) {
- /* ignore */
- }
- }, PendingSaveRequest.this,
- SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+ }
+
+ @Override
+ void fail(RemoteFillService remoteService) {
+ remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
}
@Override
public void run() {
- final RemoteFillService service = mWeakService.get();
- if (service != null) {
+ final RemoteFillService remoteService = getService();
+ if (remoteService != null) {
try {
- service.mAutoFillService.onSaveRequest(mRequest, mCallback);
+ remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Error calling on save request", e);
+
+ remoteService.dispatchOnFillRequestFailure(PendingSaveRequest.this, null);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6d58e72..0122301 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -818,6 +818,7 @@
}
}
if (atLeastOneChanged) {
+ if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
mService.setSaveShown();
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
this);
@@ -887,7 +888,7 @@
if (sVerbose) {
Slog.v(TAG, "Dumping structure of " + context + " before calling service.save()");
- context.getStructure().dump();
+ context.getStructure().dump(false);
}
}
@@ -1401,7 +1402,7 @@
pw.println(context.getStructure() + " (look at logcat)");
// TODO: add method on AssistStructure to dump on pw
- context.getStructure().dump();
+ context.getStructure().dump(false);
}
}
} else {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4f69f64..c3d55054 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -16,6 +16,7 @@
package com.android.server.autofill.ui;
import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -108,6 +109,8 @@
* Displays an error message to the user.
*/
public void showError(@Nullable CharSequence message, @NonNull AutoFillUiCallback callback) {
+ Slog.w(TAG, "showError(): " + message);
+
mHandler.post(() -> {
if (mCallback != callback) {
return;
@@ -237,6 +240,7 @@
*/
public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@NonNull String packageName, @NonNull AutoFillUiCallback callback) {
+ if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
int numIds = 0;
numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 7a1a5f2..38db8de 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -792,6 +792,11 @@
return false;
}
+ // 4. it is an "instant" app
+ if (app.isInstantApp()) {
+ return false;
+ }
+
// Everything else checks out; the only remaining roadblock would be if the
// package were disabled
return !appIsDisabled(app, pm);
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index ff92340..b3e20dc 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -17,15 +17,18 @@
package com.android.server.backup.utils;
import static com.android.server.backup.RefactoredBackupManagerService.BACKUP_MANIFEST_VERSION;
+import static com.android.server.backup.RefactoredBackupManagerService.TAG;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.util.Slog;
import android.util.StringBuilderPrinter;
import java.io.DataInputStream;
+import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -55,6 +58,10 @@
while (chunkTotal > 0) {
int toRead = (chunkTotal > buffer.length) ? buffer.length : chunkTotal;
int nRead = in.read(buffer, 0, toRead);
+ if (nRead < 0) {
+ Slog.e(TAG, "Unexpectedly reached end of file while reading data");
+ throw new EOFException();
+ }
out.write(buffer, 0, nRead);
chunkTotal -= nRead;
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 20a699b..4d080e9 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -31,6 +31,7 @@
android.hardware.weaver-V1.0-java-static \
android.hardware.biometrics.fingerprint-V2.1-java-static \
android.hardware.oemlock-V1.0-java-static \
+ android.hardware.tetheroffload.control-V1.0-java-static \
android.hardware.vibrator-V1.0-java-constants \
ifneq ($(INCREMENTAL_BUILDS),)
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b65f54e..61057dd 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1697,7 +1697,7 @@
mHandler.removeMessages(MESSAGE_USER_SWITCHED);
/* disable and enable BT when detect a user switch */
- if (mEnable && mBluetooth != null) {
+ if (mBluetooth != null && isEnabled()) {
try {
mBluetoothLock.readLock().lock();
if (mBluetooth != null) {
@@ -1766,6 +1766,8 @@
mState = BluetoothAdapter.STATE_OFF;
// enable
addActiveLog(REASON_USER_SWITCH, true);
+ // mEnable flag could have been reset on disableBLE. Reenable it.
+ mEnable = true;
handleEnable(mQuietEnable);
} else if (mBinding || mBluetooth != null) {
Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 54b02a8..b4f27f5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -139,6 +139,7 @@
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.Tethering;
+import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -177,6 +178,9 @@
implements PendingIntent.OnFinished {
private static final String TAG = ConnectivityService.class.getSimpleName();
+ public static final String DIAG_ARG = "--diag";
+ public static final String SHORT_ARG = "--short";
+
private static final boolean DBG = true;
private static final boolean VDBG = false;
@@ -471,7 +475,7 @@
new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
- synchronized(mValidationLogs) {
+ synchronized (mValidationLogs) {
while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
mValidationLogs.removeLast();
}
@@ -789,8 +793,7 @@
mTestMode = mSystemProperties.get("cm.test.mode").equals("true")
&& mSystemProperties.get("ro.build.type").equals("eng");
- mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager,
- IoThread.get().getLooper(), new MockableSystemProperties());
+ mTethering = makeTethering();
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -840,6 +843,14 @@
mMultinetworkPolicyTracker.start();
}
+ private Tethering makeTethering() {
+ // TODO: Move other elements into @Overridden getters.
+ final TetheringDependencies deps = new TetheringDependencies();
+ return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
+ IoThread.get().getLooper(), new MockableSystemProperties(),
+ deps);
+ }
+
private NetworkRequest createInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities();
@@ -1577,7 +1588,7 @@
}
private void sendStickyBroadcast(Intent intent) {
- synchronized(this) {
+ synchronized (this) {
if (!mSystemReady) {
mInitialBroadcast = new Intent(intent);
}
@@ -1618,7 +1629,7 @@
void systemReady() {
loadGlobalProxy();
- synchronized(this) {
+ synchronized (this) {
mSystemReady = true;
if (mInitialBroadcast != null) {
mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL);
@@ -1852,7 +1863,7 @@
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- if (argsContain(args, "--diag")) {
+ if (argsContain(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
}
@@ -1917,7 +1928,7 @@
pw.println();
dumpAvoidBadWifiSettings(pw);
- if (argsContain(args, "--short") == false) {
+ if (argsContain(args, SHORT_ARG) == false) {
pw.println();
synchronized (mValidationLogs) {
pw.println("mValidationLogs (most recent first):");
@@ -3381,7 +3392,7 @@
enforceCrossUserPermission(userId);
throwIfLockdownEnabled();
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn != null) {
return vpn.prepare(oldPackage, newPackage);
@@ -3408,7 +3419,7 @@
public void setVpnPackageAuthorization(String packageName, int userId, boolean authorized) {
enforceCrossUserPermission(userId);
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn != null) {
vpn.setPackageAuthorization(packageName, authorized);
@@ -3427,7 +3438,7 @@
public ParcelFileDescriptor establishVpn(VpnConfig config) {
throwIfLockdownEnabled();
int user = UserHandle.getUserId(Binder.getCallingUid());
- synchronized(mVpns) {
+ synchronized (mVpns) {
return mVpns.get(user).establish(config);
}
}
@@ -3444,7 +3455,7 @@
throw new IllegalStateException("Missing active network connection");
}
int user = UserHandle.getUserId(Binder.getCallingUid());
- synchronized(mVpns) {
+ synchronized (mVpns) {
mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
}
}
@@ -3458,7 +3469,7 @@
public LegacyVpnInfo getLegacyVpnInfo(int userId) {
enforceCrossUserPermission(userId);
- synchronized(mVpns) {
+ synchronized (mVpns) {
return mVpns.get(userId).getLegacyVpnInfo();
}
}
@@ -3474,7 +3485,7 @@
return new VpnInfo[0];
}
- synchronized(mVpns) {
+ synchronized (mVpns) {
List<VpnInfo> infoList = new ArrayList<>();
for (int i = 0; i < mVpns.size(); i++) {
VpnInfo info = createVpnInfo(mVpns.valueAt(i));
@@ -3522,7 +3533,7 @@
@Override
public VpnConfig getVpnConfig(int userId) {
enforceCrossUserPermission(userId);
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn != null) {
return vpn.getVpnConfig();
@@ -3556,7 +3567,7 @@
return true;
}
int user = UserHandle.getUserId(Binder.getCallingUid());
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn vpn = mVpns.get(user);
if (vpn == null) {
Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
@@ -3791,7 +3802,7 @@
}
private void onUserStart(int userId) {
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
loge("Starting user already has a VPN");
@@ -3806,7 +3817,7 @@
}
private void onUserStop(int userId) {
- synchronized(mVpns) {
+ synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn == null) {
loge("Stopped user has no VPN");
@@ -3818,7 +3829,7 @@
}
private void onUserAdded(int userId) {
- synchronized(mVpns) {
+ synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
@@ -3828,7 +3839,7 @@
}
private void onUserRemoved(int userId) {
- synchronized(mVpns) {
+ synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 2e2ddba..0453a9e 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -71,14 +72,20 @@
/** The listener that receives the gesture event. */
private final GestureEventListener mGestureListener = new GestureEventListener();
+ private final CameraLiftTriggerEventListener mCameraLiftTriggerListener =
+ new CameraLiftTriggerEventListener();
private Sensor mCameraLaunchSensor;
+ private Sensor mCameraLiftTriggerSensor;
private Context mContext;
private final MetricsLogger mMetricsLogger;
+ private PowerManager mPowerManager;
+ private KeyguardManager mKeyguardManager;
/** The wake lock held when a gesture is detected. */
private WakeLock mWakeLock;
- private boolean mRegistered;
+ private boolean mCameraLaunchRegistered;
+ private boolean mCameraLiftRegistered;
private int mUserId;
// Below are fields used for event logging only.
@@ -141,9 +148,11 @@
return;
}
- PowerManager powerManager = (PowerManager) mContext.getSystemService(
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(
+ Context.KEYGUARD_SERVICE);
+ mPowerManager = (PowerManager) mContext.getSystemService(
Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"GestureLauncherService");
updateCameraRegistered();
updateCameraDoubleTapPowerEnabled();
@@ -161,6 +170,9 @@
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
false, mSettingObserver, mUserId);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED),
+ false, mSettingObserver, mUserId);
}
private void updateCameraRegistered() {
@@ -170,6 +182,12 @@
} else {
unregisterCameraLaunchGesture();
}
+
+ if (isCameraLiftTriggerSettingEnabled(mContext, mUserId)) {
+ registerCameraLiftTrigger(resources);
+ } else {
+ unregisterCameraLiftTrigger();
+ }
}
@VisibleForTesting
@@ -181,8 +199,8 @@
}
private void unregisterCameraLaunchGesture() {
- if (mRegistered) {
- mRegistered = false;
+ if (mCameraLaunchRegistered) {
+ mCameraLaunchRegistered = false;
mCameraGestureOnTimeMs = 0L;
mCameraGestureLastEventTime = 0L;
mCameraGestureSensor1LastOnTimeMs = 0;
@@ -199,7 +217,7 @@
* Registers for the camera launch gesture.
*/
private void registerCameraLaunchGesture(Resources resources) {
- if (mRegistered) {
+ if (mCameraLaunchRegistered) {
return;
}
mCameraGestureOnTimeMs = SystemClock.elapsedRealtime();
@@ -209,7 +227,7 @@
int cameraLaunchGestureId = resources.getInteger(
com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
if (cameraLaunchGestureId != -1) {
- mRegistered = false;
+ mCameraLaunchRegistered = false;
String sensorName = resources.getString(
com.android.internal.R.string.config_cameraLaunchGestureSensorStringType);
mCameraLaunchSensor = sensorManager.getDefaultSensor(
@@ -221,7 +239,7 @@
// makes the code more robust.
if (mCameraLaunchSensor != null) {
if (sensorName.equals(mCameraLaunchSensor.getStringType())) {
- mRegistered = sensorManager.registerListener(mGestureListener,
+ mCameraLaunchRegistered = sensorManager.registerListener(mGestureListener,
mCameraLaunchSensor, 0);
} else {
String message = String.format("Wrong configuration. Sensor type and sensor "
@@ -230,12 +248,61 @@
throw new RuntimeException(message);
}
}
- if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mRegistered);
+ if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mCameraLaunchRegistered);
} else {
if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
}
}
+ private void unregisterCameraLiftTrigger() {
+ if (mCameraLiftRegistered) {
+ mCameraLiftRegistered = false;
+
+ SensorManager sensorManager = (SensorManager) mContext.getSystemService(
+ Context.SENSOR_SERVICE);
+ sensorManager.unregisterListener(mCameraLiftTriggerListener);
+ }
+ }
+
+ /**
+ * Registers for the camera lift trigger.
+ */
+ private void registerCameraLiftTrigger(Resources resources) {
+ if (mCameraLiftRegistered) {
+ return;
+ }
+ SensorManager sensorManager = (SensorManager) mContext.getSystemService(
+ Context.SENSOR_SERVICE);
+ int cameraLiftTriggerId = resources.getInteger(
+ com.android.internal.R.integer.config_cameraLiftTriggerSensorType);
+ if (cameraLiftTriggerId != -1) {
+ mCameraLiftRegistered = false;
+ String sensorName = resources.getString(
+ com.android.internal.R.string.config_cameraLiftTriggerSensorStringType);
+ mCameraLiftTriggerSensor = sensorManager.getDefaultSensor(
+ cameraLiftTriggerId,
+ false /*wakeUp*/);
+
+ // Compare the camera lift trigger string type to that in the resource file to make
+ // sure we are registering the correct sensor. This is redundant check, it
+ // makes the code more robust.
+ if (mCameraLiftTriggerSensor != null) {
+ if (sensorName.equals(mCameraLiftTriggerSensor.getStringType())) {
+ mCameraLiftRegistered = sensorManager.registerListener(mCameraLiftTriggerListener,
+ mCameraLiftTriggerSensor, 0);
+ } else {
+ String message = String.format("Wrong configuration. Sensor type and sensor "
+ + "string type don't match: %s in resources, %s in the sensor.",
+ sensorName, mCameraLiftTriggerSensor.getStringType());
+ throw new RuntimeException(message);
+ }
+ }
+ if (DBG) Slog.d(TAG, "Camera lift trigger sensor registered: " + mCameraLiftRegistered);
+ } else {
+ if (DBG) Slog.d(TAG, "Camera lift trigger sensor is not specified.");
+ }
+ }
+
public static boolean isCameraLaunchSettingEnabled(Context context, int userId) {
return isCameraLaunchEnabled(context.getResources())
&& (Settings.Secure.getIntForUser(context.getContentResolver(),
@@ -248,6 +315,12 @@
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
}
+ public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) {
+ return isCameraLiftTriggerEnabled(context.getResources())
+ && (Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, 0, userId) != 0);
+ }
+
/**
* Whether to enable the camera launch gesture.
*/
@@ -263,11 +336,18 @@
com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
}
+ public static boolean isCameraLiftTriggerEnabled(Resources resources) {
+ boolean configSet = resources.getInteger(
+ com.android.internal.R.integer.config_cameraLiftTriggerSensorType) != -1;
+ return configSet;
+ }
+
/**
* Whether GestureLauncherService should be enabled according to system properties.
*/
public static boolean isGestureLauncherEnabled(Resources resources) {
- return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources);
+ return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources) ||
+ isCameraLiftTriggerEnabled(resources);
}
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
@@ -296,7 +376,7 @@
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+ powerTapInterval + "ms");
- launched = handleCameraLaunchGesture(false /* useWakelock */,
+ launched = handleCameraGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
@@ -313,17 +393,17 @@
* @return true if camera was launched, false otherwise.
*/
@VisibleForTesting
- boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
+ boolean handleCameraGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (!userSetupComplete) {
if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, ignoring camera launch gesture.",
+ "userSetupComplete = %s, ignoring camera gesture.",
userSetupComplete));
return false;
}
if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, performing camera launch gesture.",
+ "userSetupComplete = %s, performing camera gesture.",
userSetupComplete));
if (useWakelock) {
@@ -361,7 +441,7 @@
private final class GestureEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
- if (!mRegistered) {
+ if (!mCameraLaunchRegistered) {
if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered.");
return;
}
@@ -371,7 +451,7 @@
Slog.d(TAG, String.format("Received a camera launch event: " +
"values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
}
- if (handleCameraLaunchGesture(true /* useWakelock */,
+ if (handleCameraGesture(true /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
@@ -430,4 +510,35 @@
mCameraLaunchLastEventExtra = extra;
}
}
+
+ private final class CameraLiftTriggerEventListener implements SensorEventListener {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (!mCameraLiftRegistered) {
+ if (DBG) Slog.d(TAG, "Ignoring camera lift event because it's unregistered.");
+ return;
+ }
+ if (event.sensor == mCameraLiftTriggerSensor) {
+ if (DBG) {
+ float[] values = event.values;
+ Slog.d(TAG, String.format("Received a camera lift trigger event: " +
+ "values=[%.4f].", values[0]));
+ }
+ if (mKeyguardManager.isKeyguardLocked() || !mPowerManager.isInteractive()) {
+ if (handleCameraGesture(true /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER);
+ }
+ } else if (DBG) {
+ Slog.d(TAG, "Ignoring lift event because device is awake");
+ }
+ return;
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Ignored.
+ }
+ }
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index ebcda44..1ad1404 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -26,6 +26,8 @@
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -74,6 +76,7 @@
private long mNitzTimeSetTime = NOT_SET;
// TODO: Have a way to look up the timezone we are in
private long mNitzZoneSetTime = NOT_SET;
+ private Network mDefaultNetwork = null;
private Context mContext;
private TrustedTime mTime;
@@ -83,6 +86,8 @@
private AlarmManager mAlarmManager;
private PendingIntent mPendingPollIntent;
private SettingsObserver mSettingsObserver;
+ private ConnectivityManager mCM;
+ private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
// The last time that we successfully fetched the NTP time.
private long mLastNtpFetchTime = NOT_SET;
private final PowerManager.WakeLock mWakeLock;
@@ -104,6 +109,7 @@
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -124,13 +130,12 @@
public void systemRunning() {
registerForTelephonyIntents();
registerForAlarms();
- registerForConnectivityIntents();
HandlerThread thread = new HandlerThread(TAG);
thread.start();
mHandler = new MyHandler(thread.getLooper());
- // Check the network time on the new thread
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+ mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+ mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
mSettingsObserver.observe(mContext);
@@ -153,15 +158,10 @@
}, new IntentFilter(ACTION_POLL));
}
- private void registerForConnectivityIntents() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiver(mConnectivityReceiver, intentFilter);
- }
-
private void onPollNetworkTime(int event) {
- // If Automatic time is not set, don't bother.
- if (!isAutomaticTimeRequested()) return;
+ // If Automatic time is not set, don't bother. Similarly, if we don't
+ // have any default network, don't bother.
+ if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
mWakeLock.acquire();
try {
onPollNetworkTimeUnderWakeLock(event);
@@ -263,22 +263,6 @@
}
};
- /** Receiver for ConnectivityManager events */
- private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
- if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION ");
- // Don't bother checking if we have connectivity, NtpTrustedTime does that for us.
- Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED);
- // Send with a short delay to make sure the network is ready for use
- mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS);
- }
- }
- };
-
/** Handler to do the network accesses on */
private class MyHandler extends Handler {
@@ -298,6 +282,21 @@
}
}
+ private class NetworkTimeUpdateCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ Log.d(TAG, String.format("New default network %s; checking time.", network));
+ mDefaultNetwork = network;
+ // Running on mHandler so invoke directly.
+ onPollNetworkTime(EVENT_NETWORK_CHANGED);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+ }
+ }
+
/** Observer to watch for changes to the AUTO_TIME setting */
private static class SettingsObserver extends ContentObserver {
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index a94bf79..e3ebf4d 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -244,20 +244,22 @@
// get the path to the odex or oat file
String baseCodePath = cameraInfo.getBaseCodePath();
- String odex = null;
+ String[] files = null;
try {
- odex = DexFile.getDexFileOutputPath(baseCodePath, arch);
+ files = DexFile.getDexFileOutputPaths(baseCodePath, arch);
} catch (IOException ioe) {}
- if (odex == null) {
+ if (files == null) {
return true;
}
//not pinning the oat/odex is not a fatal error
- pf = pinFile(odex, 0, 0, MAX_CAMERA_PIN_SIZE);
- if (pf != null) {
- mPinnedCameraFiles.add(pf);
- if (DEBUG) {
- Slog.i(TAG, "Pinned " + pf.mFilename);
+ for (String file : files) {
+ pf = pinFile(file, 0, 0, MAX_CAMERA_PIN_SIZE);
+ if (pf != null) {
+ mPinnedCameraFiles.add(pf);
+ if (DEBUG) {
+ Slog.i(TAG, "Pinned " + pf.mFilename);
+ }
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 452fe1d..cffb158 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3009,6 +3009,18 @@
}
}
+ @Override
+ public void secdiscard(String path) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+ waitForReady();
+
+ try {
+ mCryptConnector.execute("cryptfs", "secdiscard", escapeNull(path));
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
class AppFuseMountScope extends AppFuseBridge.MountScope {
boolean opened = false;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 04421cc..6b5366a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -640,7 +640,7 @@
int result = ActivityManager.getService().startActivityWithConfig(
null, null, homeIntent, null, null, null, 0, 0,
mConfiguration, null, UserHandle.USER_CURRENT);
- if (result >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
Slog.e(TAG, "Could not start dock app: " + homeIntent
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2bd55e2..36c3f7d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5922,6 +5922,13 @@
return;
}
+ int visibility =
+ resolveAccountVisibility(account, packageName, getUserAccounts(userId));
+ if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) {
+ Slog.w(TAG, "requestAccountAccess: account is hidden");
+ return;
+ }
+
if (AccountManagerService.this.hasAccountAccess(account, packageName,
new UserHandle(userId))) {
Bundle result = new Bundle();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5e03508..2680b425 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -780,7 +780,8 @@
smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
if (nextUpdateTime < Long.MAX_VALUE) {
Message msg = smap.obtainMessage();
- smap.sendMessageAtTime(msg, nextUpdateTime);
+ smap.sendMessageAtTime(msg, nextUpdateTime
+ + SystemClock.uptimeMillis() - SystemClock.elapsedRealtime());
}
}
if (!smap.mActiveForegroundAppsChanged) {
@@ -811,30 +812,35 @@
Intent intent;
String title;
String msg;
+ String[] pkgs;
if (active.size() == 1) {
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", active.get(0).mPackageName, null));
title = context.getString(
R.string.foreground_service_app_in_background, active.get(0).mLabel);
msg = context.getString(R.string.foreground_service_tap_for_details);
+ pkgs = new String[] { active.get(0).mPackageName };
} else {
intent = new Intent(Settings.ACTION_FOREGROUND_SERVICES_SETTINGS);
- String[] pkgs = new String[active.size()];
+ pkgs = new String[active.size()];
for (int i = 0; i < active.size(); i++) {
pkgs[i] = active.get(i).mPackageName;
}
intent.putExtra("packages", pkgs);
title = context.getString(
R.string.foreground_service_apps_in_background, active.size());
- msg = active.get(0).mLabel.toString();
+ msg = active.get(0).mLabel.toString();
for (int i = 1; i < active.size(); i++) {
msg = context.getString(R.string.foreground_service_multiple_separator,
msg, active.get(i).mLabel);
}
}
+ Bundle notificationBundle = new Bundle();
+ notificationBundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, pkgs);
Notification.Builder n =
new Notification.Builder(context,
SystemNotificationChannels.FOREGROUND_SERVICE)
+ .addExtras(notificationBundle)
.setSmallIcon(R.drawable.ic_check_circle_24px)
.setOngoing(true)
.setShowWhen(false)
@@ -854,10 +860,11 @@
}
}
- private void requestUpdateActiveForegroundAppsLocked(ServiceMap smap, long time) {
+ private void requestUpdateActiveForegroundAppsLocked(ServiceMap smap, long timeElapsed) {
Message msg = smap.obtainMessage(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
- if (time != 0) {
- smap.sendMessageAtTime(msg, time);
+ if (timeElapsed != 0) {
+ smap.sendMessageAtTime(msg,
+ timeElapsed + SystemClock.uptimeMillis() - SystemClock.elapsedRealtime());
} else {
smap.mActiveForegroundAppsChanged = true;
smap.sendMessage(msg);
@@ -909,6 +916,9 @@
if (changed) {
requestUpdateActiveForegroundAppsLocked(smap,
nowElapsed + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+ } else if (smap.mActiveForegroundApps.size() > 0) {
+ // Just being paranoid.
+ requestUpdateActiveForegroundAppsLocked(smap, 0);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 8ed95ee..ff5efde 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -65,6 +65,7 @@
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
+ static final boolean DEBUG_OOM_ADJ_REASON = DEBUG_ALL || false;
static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8398eee..3b27c7c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -118,6 +118,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
@@ -5370,8 +5371,9 @@
boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
- Slog.i(TAG, "Process " + app.processName + " (pid " + pid
- + ") has died");
+ Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+ + ProcessList.makeOomAdjString(app.setAdj)
+ + ProcessList.makeProcStateString(app.setProcState));
mAllowLowerMemLevel = true;
} else {
// Note that we always want to do oom adj to update our state with the
@@ -5379,7 +5381,8 @@
mAllowLowerMemLevel = false;
doLowMem = false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
+ app.setAdj, app.setProcState);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
handleAppDiedLocked(app, false, true);
@@ -5429,7 +5432,35 @@
return null;
}
- dumpStackTraces(tracesPath, firstPids, processCpuTracker, lastPids, nativePids);
+ ArrayList<Integer> extraPids = null;
+
+ // Lastly, measure CPU usage.
+ if (processCpuTracker != null) {
+ processCpuTracker.init();
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException ignored) {
+ }
+
+ processCpuTracker.update();
+
+ // We'll take the stack crawls of just the top apps using CPU.
+ final int N = processCpuTracker.countWorkingStats();
+ extraPids = new ArrayList<>();
+ for (int i = 0; i < N && extraPids.size() < 5; i++) {
+ ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
+ if (lastPids.indexOfKey(stats.pid) >= 0) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
+
+ extraPids.add(stats.pid);
+ } else if (DEBUG_ANR) {
+ Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+ + stats.pid);
+ }
+ }
+ }
+
+ dumpStackTraces(tracesPath, firstPids, nativePids, extraPids);
return tracesFile;
}
@@ -5491,8 +5522,7 @@
}
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
- ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
- ArrayList<Integer> nativePids) {
+ ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {
// Use a FileObserver to detect when traces finish writing.
// The order of traces is considered important to maintain for legibility.
DumpStackFileObserver observer = new DumpStackFileObserver(tracesPath);
@@ -5548,43 +5578,21 @@
}
}
- // Lastly, measure CPU usage.
- if (processCpuTracker != null) {
- processCpuTracker.init();
- System.gc();
- processCpuTracker.update();
- try {
- synchronized (processCpuTracker) {
- processCpuTracker.wait(500); // measure over 1/2 second.
- }
- } catch (InterruptedException e) {
- }
- processCpuTracker.update();
+ // Lastly, dump stacks for all extra PIDs from the CPU tracker.
+ if (extraPids != null) {
+ for (int pid : extraPids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);
- // We'll take the stack crawls of just the top apps using CPU.
- final int N = processCpuTracker.countWorkingStats();
- int numProcs = 0;
- for (int i=0; i<N && numProcs<5; i++) {
- ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
- if (lastPids.indexOfKey(stats.pid) >= 0) {
- numProcs++;
-
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
-
- final long timeTaken = observer.dumpWithTimeout(stats.pid, remainingTime);
- remainingTime -= timeTaken;
- if (remainingTime <= 0) {
- Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + stats.pid +
+ final long timeTaken = observer.dumpWithTimeout(pid, remainingTime);
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
"); deadline exceeded.");
- return;
- }
+ return;
+ }
- if (DEBUG_ANR) {
- Slog.d(TAG, "Done with extra pid " + stats.pid + " in " + timeTaken + "ms");
- }
- } else if (DEBUG_ANR) {
- Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
- + stats.pid);
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");
}
}
}
@@ -5636,7 +5644,7 @@
if (app != null) {
ArrayList<Integer> firstPids = new ArrayList<Integer>();
firstPids.add(app.pid);
- dumpStackTraces(tracesPath, firstPids, null, null, null);
+ dumpStackTraces(tracesPath, firstPids, null, null);
}
File lastTracesFile = null;
@@ -7891,12 +7899,6 @@
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
// Adjust the source bounds by the insets for the transition down
final Rect sourceBounds = new Rect(r.pictureInPictureArgs.getSourceRectHint());
- final Rect insets = r.pictureInPictureArgs.getSourceRectHintInsets();
- if (insets != null) {
- sourceBounds.offsetTo(Math.max(0, sourceBounds.left - insets.left),
- Math.max(0, sourceBounds.top - insets.top));
- }
-
mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, aspectRatio,
true /* moveHomeStackToFront */, "enterPictureInPictureMode");
final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
@@ -20629,6 +20631,7 @@
if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
// The max adjustment doesn't allow this app to be anything
// below foreground, so it is not worth doing work for it.
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making fixed: " + app);
app.adjType = "fixed";
app.adjSeq = mAdjSeq;
app.curRawAdj = app.maxAdj;
@@ -20680,12 +20683,14 @@
app.adjType = "top-activity";
foregroundActivities = true;
procState = PROCESS_STATE_CUR_TOP;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making top: " + app);
} else if (app.instr != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making instrumentation: " + app);
} else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
@@ -20696,6 +20701,7 @@
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making broadcast: " + app);
} else if (app.executingServices.size() > 0) {
// An app that is currently executing a service callback also
// counts as being in the foreground.
@@ -20704,6 +20710,7 @@
ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "exec-service";
procState = ActivityManager.PROCESS_STATE_SERVICE;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making exec-service: " + app);
//Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
} else {
// As far as we know the process is empty. We may change our mind later.
@@ -20715,6 +20722,7 @@
app.cached = true;
app.empty = true;
app.adjType = "cch-empty";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making empty: " + app);
}
// Examine all activities if not already foreground.
@@ -20736,10 +20744,13 @@
// App has a visible activity; only upgrade adjustment.
if (adj > ProcessList.VISIBLE_APP_ADJ) {
adj = ProcessList.VISIBLE_APP_ADJ;
- app.adjType = "visible";
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
+ app.adjType = "vis-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
@@ -20756,10 +20767,13 @@
} else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "pausing";
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
if (procState > PROCESS_STATE_CUR_TOP) {
procState = PROCESS_STATE_CUR_TOP;
+ app.adjType = "pause-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
@@ -20768,7 +20782,8 @@
} else if (r.state == ActivityState.STOPPING) {
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
- app.adjType = "stopping";
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to stop-activity: " + app);
}
// For the process state, we will at this point consider the
// process to be cached. It will be cached either as an activity
@@ -20780,6 +20795,8 @@
if (!r.finishing) {
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "stop-activity";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to stop-activity: " + app);
}
}
app.cached = false;
@@ -20789,6 +20806,7 @@
if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
app.adjType = "cch-act";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to cached activity: " + app);
}
}
}
@@ -20806,6 +20824,7 @@
app.cached = false;
app.adjType = "fg-service";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to fg service: " + app);
} else if (app.hasOverlayUi) {
// The process is display an overlay UI.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -20813,6 +20832,7 @@
app.cached = false;
app.adjType = "has-overlay-ui";
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to overlay ui: " + app);
}
}
@@ -20828,6 +20848,7 @@
app.adjType = "force-imp";
app.adjSource = app.forcingToImportant;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to force imp: " + app);
}
}
@@ -20838,9 +20859,12 @@
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "heavy";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to heavy: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
procState = ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+ app.adjType = "heavy";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to heavy: " + app);
}
}
@@ -20852,9 +20876,12 @@
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "home";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to home: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_HOME) {
procState = ActivityManager.PROCESS_STATE_HOME;
+ app.adjType = "home";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to home: " + app);
}
}
@@ -20867,9 +20894,12 @@
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
app.adjType = "previous";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to prev: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "previous";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to prev: " + app);
}
}
@@ -20893,14 +20923,20 @@
procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
}
app.adjType = "backup";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to backup: " + app);
app.cached = false;
}
if (procState > ActivityManager.PROCESS_STATE_BACKUP) {
procState = ActivityManager.PROCESS_STATE_BACKUP;
+ app.adjType = "backup";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to backup: " + app);
}
}
boolean mayBeTop = false;
+ String mayBeTopType = null;
+ Object mayBeTopSource = null;
+ Object mayBeTopTarget = null;
for (int is = app.services.size()-1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
@@ -20912,6 +20948,8 @@
app.hasStartedServices = true;
if (procState > ActivityManager.PROCESS_STATE_SERVICE) {
procState = ActivityManager.PROCESS_STATE_SERVICE;
+ app.adjType = "started-services";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to started service: " + app);
}
if (app.hasShownUi && app != mHomeProcess) {
// If this process has shown some UI, let it immediately
@@ -20929,6 +20967,7 @@
if (adj > ProcessList.SERVICE_ADJ) {
adj = ProcessList.SERVICE_ADJ;
app.adjType = "started-services";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to started service: " + app);
app.cached = false;
}
}
@@ -21010,27 +21049,35 @@
// memory.
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adjType = "cch-bound-ui-services";
+ if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ adjType = "cch-bound-ui-services";
+ }
} else {
+ int newAdj;
if ((cr.flags&(Context.BIND_ABOVE_CLIENT
|Context.BIND_IMPORTANT)) != 0) {
- adj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
+ newAdj = clientAdj >= ProcessList.PERSISTENT_SERVICE_ADJ
? clientAdj : ProcessList.PERSISTENT_SERVICE_ADJ;
} else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
&& clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
&& adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+ newAdj = ProcessList.PERCEPTIBLE_APP_ADJ;
} else if (clientAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
- adj = clientAdj;
+ newAdj = clientAdj;
} else {
if (adj > ProcessList.VISIBLE_APP_ADJ) {
- adj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
+ newAdj = Math.max(clientAdj, ProcessList.VISIBLE_APP_ADJ);
+ } else {
+ newAdj = adj;
}
}
if (!client.cached) {
app.cached = false;
}
- adjType = "service";
+ if (adj > newAdj) {
+ adj = newAdj;
+ adjType = "service";
+ }
}
}
if ((cr.flags & (Context.BIND_NOT_FOREGROUND
@@ -21057,6 +21104,9 @@
// is more important to continue considering it to be
// in the background state.
mayBeTop = true;
+ mayBeTopType = "service";
+ mayBeTopSource = cr.binding.client;
+ mayBeTopTarget = s.name;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
} else {
// Special handling for above-top states (persistent
@@ -21093,6 +21143,9 @@
}
if (procState > clientProcState) {
procState = clientProcState;
+ if (adjType == null) {
+ adjType = "service";
+ }
}
if (procState < ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
&& (cr.flags&Context.BIND_SHOWING_UI) != 0) {
@@ -21105,6 +21158,9 @@
app.adjSource = cr.binding.client;
app.adjSourceProcState = clientProcState;
app.adjTarget = s.name;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to " + adjType
+ + ": " + app + ", due to " + cr.binding.client
+ + " adj=" + adj + " procState=" + procState);
}
}
if ((cr.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
@@ -21130,6 +21186,8 @@
app.adjSource = a;
app.adjSourceProcState = procState;
app.adjTarget = s.name;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to service w/activity: "
+ + app);
}
}
}
@@ -21160,21 +21218,17 @@
// we are going to consider it empty.
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
}
+ String adjType = null;
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
- app.adjType = "cch-ui-provider";
+ adjType = "cch-ui-provider";
} else {
adj = clientAdj > ProcessList.FOREGROUND_APP_ADJ
? clientAdj : ProcessList.FOREGROUND_APP_ADJ;
- app.adjType = "provider";
+ adjType = "provider";
}
app.cached &= client.cached;
- app.adjTypeCode = ActivityManager.RunningAppProcessInfo
- .REASON_PROVIDER_IN_USE;
- app.adjSource = client;
- app.adjSourceProcState = clientProcState;
- app.adjTarget = cpr.name;
}
if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
if (clientProcState == ActivityManager.PROCESS_STATE_TOP) {
@@ -21189,6 +21243,9 @@
// in the background state.
mayBeTop = true;
clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+ mayBeTopType = adjType = "provider-top";
+ mayBeTopSource = client;
+ mayBeTopTarget = cpr.name;
} else {
// Special handling for above-top states (persistent
// processes). These should not bring the current process
@@ -21196,6 +21253,9 @@
// give them the best state after that.
clientProcState =
ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ if (adjType == null) {
+ adjType = "provider";
+ }
}
}
if (procState > clientProcState) {
@@ -21204,6 +21264,17 @@
if (client.curSchedGroup > schedGroup) {
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
}
+ if (adjType != null) {
+ app.adjType = adjType;
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE;
+ app.adjSource = client;
+ app.adjSourceProcState = clientProcState;
+ app.adjTarget = cpr.name;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to " + adjType
+ + ": " + app + ", due to " + client
+ + " adj=" + adj + " procState=" + procState);
+ }
}
// If the provider has external (non-framework) process
// dependencies, ensure that its adjustment is at least
@@ -21213,8 +21284,9 @@
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.cached = false;
- app.adjType = "provider";
+ app.adjType = "ext-provider";
app.adjTarget = cpr.name;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to external provider: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
@@ -21228,10 +21300,13 @@
adj = ProcessList.PREVIOUS_APP_ADJ;
schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
app.cached = false;
- app.adjType = "provider";
+ app.adjType = "recent-provider";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to recent provider: " + app);
}
if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+ app.adjType = "recent-provider";
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to recent provider: " + app);
}
}
@@ -21243,6 +21318,9 @@
// is top (states that tend to be longer-term) and otherwise allow it to go
// to the top state.
switch (procState) {
+ case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+ // Something else is keeping it at this level, just leave it.
+ break;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
@@ -21250,10 +21328,22 @@
// These all are longer-term states, so pull them up to the top
// of the background states, but not all the way to the top state.
procState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ app.adjType = mayBeTopType;
+ app.adjSource = mayBeTopSource;
+ app.adjTarget = mayBeTopTarget;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "May be top raise to " + mayBeTopType
+ + ": " + app + ", due to " + mayBeTopSource
+ + " adj=" + adj + " procState=" + procState);
break;
default:
// Otherwise, top is a better choice, so take it.
procState = ActivityManager.PROCESS_STATE_TOP;
+ app.adjType = mayBeTopType;
+ app.adjSource = mayBeTopSource;
+ app.adjTarget = mayBeTopTarget;
+ if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "May be top raise to " + mayBeTopType
+ + ": " + app + ", due to " + mayBeTopSource
+ + " adj=" + adj + " procState=" + procState);
break;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4e00f2d..55ec3b0 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -149,6 +149,7 @@
import android.util.Slog;
import android.util.TimeUtils;
import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.WindowManager.LayoutParams;
@@ -1437,7 +1438,13 @@
case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
- if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
+ final IAppTransitionAnimationSpecsFuture specsFuture =
+ pendingOptions.getSpecsFuture();
+ if (specsFuture != null) {
+ service.mWindowManager.overridePendingAppTransitionMultiThumbFuture(
+ specsFuture, pendingOptions.getOnAnimationStartListener(),
+ animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
+ } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
&& specs != null) {
service.mWindowManager.overridePendingAppTransitionMultiThumb(
specs, pendingOptions.getOnAnimationStartListener(),
@@ -2165,7 +2172,8 @@
final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
- allowTaskSnapshot());
+ allowTaskSnapshot(),
+ state.ordinal() >= RESUMED.ordinal() && state.ordinal() <= STOPPED.ordinal());
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b2f655c..9fcd593 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2998,7 +2998,8 @@
stack.animateResizePinnedStack(sourceHintBounds, destBounds, -1 /* animationDuration */,
true /* schedulePipModeChangedOnAnimationEnd */);
- mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName);
+ mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName,
+ r.getTask().taskId);
}
/** Move activity with its stack to front and make the stack focused. */
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6d4eb5b..960351b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -533,18 +533,19 @@
auxiliaryResponse, originalIntent, resolvedType, callingPackage,
verificationBundle, userId);
}
- return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent,
- auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
- resolvedType, userId, auxiliaryResponse.packageName,
- auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
- auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
+ return InstantAppResolver.buildEphemeralInstallerIntent(
+ Intent.ACTION_INSTALL_INSTANT_APP_PACKAGE, originalIntent,
+ auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
+ resolvedType, userId, auxiliaryResponse.packageName, auxiliaryResponse.splitName,
+ auxiliaryResponse.versionCode, auxiliaryResponse.token,
+ auxiliaryResponse.needsPhaseTwo);
}
void postStartActivityProcessing(
ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
ActivityStack targetStack) {
- if (result < START_SUCCESS) {
+ if (ActivityManager.isStartResultFatalError(result)) {
return;
}
@@ -956,7 +957,8 @@
// If we are not able to proceed, disassociate the activity from the task. Leaving an
// activity in an incomplete state can lead to issues, such as performing operations
// without a window container.
- if (result < START_SUCCESS && mStartActivity.getTask() != null) {
+ if (ActivityManager.isStartResultFatalError(result)
+ && mStartActivity.getTask() != null) {
mStartActivity.getTask().removeActivity(mStartActivity);
}
mService.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5d8cb12..11fc40b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -183,7 +183,6 @@
}
private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
- private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
@@ -215,28 +214,6 @@
}
}
- @Override
- public String getSubsystemLowPowerStats() {
- Slog.d(TAG, "begin getSubsystemLowPowerStats");
- try {
- mUtf8BufferStat.clear();
- mUtf16BufferStat.clear();
- mDecoderStat.reset();
- int bytesWritten = getSubsystemLowPowerStats(mUtf8BufferStat);
- if (bytesWritten < 0) {
- return null;
- } else if (bytesWritten == 0) {
- return "Empty";
- }
- mUtf8BufferStat.limit(bytesWritten);
- mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
- mUtf16BufferStat.flip();
- return mUtf16BufferStat.toString();
- } finally {
- Slog.d(TAG, "end getSubsystemLowPowerStats");
- }
- }
-
BatteryStatsService(File systemDir, Handler handler) {
// Our handler here will be accessing the disk, use a different thread than
// what the ActivityManagerService gave us (no I/O on that one!).
@@ -989,10 +966,10 @@
}
@Override
- public void noteBleScanResult(WorkSource ws) {
+ public void noteBleScanResults(WorkSource ws, int numNewResults) {
enforceCallingPermission();
synchronized (mStats) {
- mStats.noteBluetoothScanResultFromSourceLocked(ws);
+ mStats.noteBluetoothScanResultsFromSourceLocked(ws, numNewResults);
}
}
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 372ab6b..b2d3137 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -34,7 +34,7 @@
# Application process bound to work
30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
# Application process died
-30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3)
+30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
# The Activity Manager failed to pause the given activity.
30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
# Attempting to pause the current activity
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 80e7c75..7810c5e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -356,7 +356,7 @@
procState = "PERU";
break;
case ActivityManager.PROCESS_STATE_TOP:
- procState = "TOP";
+ procState = "TOP ";
break;
case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
procState = "BFGS";
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index f5d7b68..ea9ff59 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -96,7 +96,7 @@
};
private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
- l.onActivityPinned((String) m.obj);
+ l.onActivityPinned((String) m.obj, m.arg1);
};
private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
@@ -279,10 +279,10 @@
}
/** Notifies all listeners when an Activity is pinned. */
- void notifyActivityPinned(String packageName) {
+ void notifyActivityPinned(String packageName, int taskId) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
- packageName);
+ taskId, 0, packageName);
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index dcd58e7..702cbbe 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -67,6 +67,10 @@
.createIfNeeded()
.build();
+ // like a PLAY_CREATE_IF_NEEDED operation but with a skip to the end of the ramp
+ private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
+ new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
+
private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
// a public client is one that needs an anonymized version of the playback configurations, we
// keep track of whether there is at least one to know when we need to create the list of
@@ -487,17 +491,19 @@
private static final class DuckingManager {
private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
- void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+ synchronized void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+ if (DEBUG) { Log.v(TAG, "DuckingManager: duckUid() uid:"+ uid); }
if (!mDuckers.containsKey(uid)) {
mDuckers.put(uid, new DuckedApp(uid));
}
final DuckedApp da = mDuckers.get(uid);
for (AudioPlaybackConfiguration apc : apcsToDuck) {
- da.addDuck(apc);
+ da.addDuck(apc, false /*skipRamp*/);
}
}
- void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+ synchronized void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+ if (DEBUG) { Log.v(TAG, "DuckingManager: unduckUid() uid:"+ uid); }
final DuckedApp da = mDuckers.remove(uid);
if (da == null) {
return;
@@ -506,25 +512,27 @@
}
// pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
- void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
+ synchronized void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
+ if (DEBUG) { Log.v(TAG, "DuckingManager: checkDuck() player piid:"
+ + apc.getPlayerInterfaceId()+ " uid:"+ apc.getClientUid()); }
final DuckedApp da = mDuckers.get(apc.getClientUid());
if (da == null) {
return;
}
- // FIXME here the player needs to be put in a state that is the same as if it
- // had been ducked as it starts. At the moment, this works already for linked
- // players, as is the case in gapless playback.
- da.addDuck(apc);
+ da.addDuck(apc, true /*skipRamp*/);
}
- void dump(PrintWriter pw) {
+ synchronized void dump(PrintWriter pw) {
for (DuckedApp da : mDuckers.values()) {
da.dump(pw);
}
}
- void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
- final DuckedApp da = mDuckers.get(apc.getClientUid());
+ synchronized void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+ final int uid = apc.getClientUid();
+ if (DEBUG) { Log.v(TAG, "DuckingManager: removedReleased() player piid: "
+ + apc.getPlayerInterfaceId() + " uid:" + uid); }
+ final DuckedApp da = mDuckers.get(uid);
if (da == null) {
return;
}
@@ -550,20 +558,21 @@
// pre-conditions:
// * apc != null
// * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
- void addDuck(@NonNull AudioPlaybackConfiguration apc) {
+ void addDuck(@NonNull AudioPlaybackConfiguration apc, boolean skipRamp) {
final int piid = new Integer(apc.getPlayerInterfaceId());
if (mDuckedPlayers.contains(piid)) {
- if (DEBUG) { Log.v(TAG, "player " + piid + " already ducked"); }
+ if (DEBUG) { Log.v(TAG, "player piid:" + piid + " already ducked"); }
return;
}
try {
- Log.v(TAG, "ducking player " + apc.getPlayerInterfaceId() + " uid:" + mUid);
+ Log.v(TAG, "ducking (skipRamp=" + skipRamp + ") player piid:"
+ + apc.getPlayerInterfaceId() + " uid:" + mUid);
apc.getPlayerProxy().applyVolumeShaper(
DUCK_VSHAPE,
- PLAY_CREATE_IF_NEEDED);
+ skipRamp ? PLAY_SKIP_RAMP : PLAY_CREATE_IF_NEEDED);
mDuckedPlayers.add(piid);
} catch (Exception e) {
- Log.e(TAG, "Error ducking player " + piid + " uid:" + mUid, e);
+ Log.e(TAG, "Error ducking player piid:" + piid + " uid:" + mUid, e);
}
}
@@ -577,13 +586,13 @@
DUCK_ID,
VolumeShaper.Operation.REVERSE);
} catch (Exception e) {
- Log.e(TAG, "Error unducking player " + piid + " uid:" + mUid, e);
+ Log.e(TAG, "Error unducking player piid:" + piid + " uid:" + mUid, e);
}
} else {
// this piid was in the list of ducked players, but wasn't found
if (DEBUG) {
- Log.v(TAG, "Error unducking player " + piid + ", player not found for"
- + " uid " + mUid);
+ Log.v(TAG, "Error unducking player piid:" + piid
+ + ", player not found for uid " + mUid);
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 3677905..0ee2a41 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -971,14 +971,18 @@
return result;
}
}
- // Otherwise wait until https probe completes and use its result.
+ // Otherwise wait until http and https probes completes and use their results.
try {
+ httpProbe.join();
+ if (httpProbe.result().isPortal()) {
+ return httpProbe.result();
+ }
httpsProbe.join();
+ return httpsProbe.result();
} catch (InterruptedException e) {
- validationLog("Error: https probe wait interrupted!");
+ validationLog("Error: http or https probe wait interrupted!");
return CaptivePortalProbeResult.FAILED;
}
- return httpsProbe.result();
}
private URL makeURL(String url) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 925dfb5..c1ce7b5 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -20,6 +20,7 @@
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
+import static com.android.server.ConnectivityService.SHORT_ARG;
import android.app.Notification;
import android.app.NotificationManager;
@@ -47,6 +48,7 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.util.SharedLog;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Bundle;
@@ -62,7 +64,6 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
@@ -84,6 +85,7 @@
import com.android.server.connectivity.tethering.SimChangeListener;
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringConfiguration;
+import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
import com.android.server.net.BaseNetworkObserver;
@@ -148,9 +150,7 @@
}
}
- private final static int MAX_LOG_RECORDS = 500;
-
- private final LocalLog mLocalLog = new LocalLog(MAX_LOG_RECORDS);
+ private final SharedLog mLog = new SharedLog(TAG);
// used to synchronize public access to members
private final Object mPublicSync;
@@ -181,8 +181,9 @@
public Tethering(Context context, INetworkManagementService nmService,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
- Looper looper, MockableSystemProperties systemProperties) {
- mLocalLog.log("CONSTRUCTED");
+ Looper looper, MockableSystemProperties systemProperties,
+ TetheringDependencies deps) {
+ mLog.mark("constructed");
mContext = context;
mNMService = nmService;
mStatsService = statsService;
@@ -197,9 +198,10 @@
mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper);
mTetherMasterSM.start();
- mOffloadController = new OffloadController(mTetherMasterSM.getHandler());
+ mOffloadController = new OffloadController(mTetherMasterSM.getHandler(),
+ deps.getOffloadHardwareInterface(), mLog);
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
- mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+ mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK, mLog);
mForwardedDownstreams = new HashSet<>();
mSimChange = new SimChangeListener(
mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
@@ -1145,7 +1147,7 @@
addState(mSetDnsForwardersErrorState);
mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList);
+ mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
setInitialState(mInitialState);
}
@@ -1192,7 +1194,7 @@
try {
mNMService.setIpForwardingEnabled(true);
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mSetIpForwardingEnabledErrorState);
return false;
}
@@ -1205,12 +1207,12 @@
mNMService.stopTethering();
mNMService.startTethering(cfg.dhcpRanges);
} catch (Exception ee) {
- mLocalLog.log("ERROR " + ee);
+ mLog.e(ee);
transitionTo(mStartTetheringErrorState);
return false;
}
}
- mLocalLog.log("SET master tether settings: ON");
+ mLog.log("SET master tether settings: ON");
return true;
}
@@ -1218,19 +1220,19 @@
try {
mNMService.stopTethering();
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mStopTetheringErrorState);
return false;
}
try {
mNMService.setIpForwardingEnabled(false);
} catch (Exception e) {
- mLocalLog.log("ERROR " + e);
+ mLog.e(e);
transitionTo(mSetIpForwardingDisabledErrorState);
return false;
}
transitionTo(mInitialState);
- mLocalLog.log("SET master tether settings: OFF");
+ mLog.log("SET master tether settings: OFF");
return true;
}
@@ -1356,13 +1358,13 @@
}
try {
mNMService.setDnsForwarders(network, dnsServers);
- mLocalLog.log(String.format(
- "SET DNS forwarders: network=%s dnsServers=[%s]",
+ mLog.log(String.format(
+ "SET DNS forwarders: network=%s dnsServers=%s",
network, Arrays.toString(dnsServers)));
} catch (Exception e) {
// TODO: Investigate how this can fail and what exactly
// happens if/when such failures occur.
- mLocalLog.log("ERROR setting DNS forwarders failed, " + e);
+ mLog.e("setting DNS forwarders failed, " + e);
transitionTo(mSetDnsForwardersErrorState);
}
}
@@ -1491,7 +1493,8 @@
handleInterfaceServingStateInactive(who);
if (mNotifyList.isEmpty()) {
- // transitions appropriately
+ // This transitions us out of TetherModeAliveState,
+ // either to InitialState or an error state.
turnOffMasterTetherSettings();
break;
}
@@ -1717,12 +1720,23 @@
pw.println("Log:");
pw.increaseIndent();
- mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
+ if (argsContain(args, SHORT_ARG)) {
+ pw.println("<log removed for brevity>");
+ } else {
+ mLog.dump(fd, pw, args);
+ }
pw.decreaseIndent();
pw.decreaseIndent();
}
+ private static boolean argsContain(String[] args, String target) {
+ for (String arg : args) {
+ if (arg.equals(target)) return true;
+ }
+ return false;
+ }
+
@Override
public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
int state, int error) {
@@ -1736,8 +1750,7 @@
}
}
- mLocalLog.log(String.format("OBSERVED iface=%s state=%s error=%s",
- iface, state, error));
+ mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
try {
// Notify that we're tethering (or not) this interface.
@@ -1775,8 +1788,8 @@
private void trackNewTetherableInterface(String iface, int interfaceType) {
TetherState tetherState;
tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
- interfaceType, mNMService, mStatsService, this,
- new IPv6TetheringInterfaceServices(iface, mNMService)));
+ interfaceType, mLog, mNMService, mStatsService, this,
+ new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
mTetherStates.put(iface, tetherState);
tetherState.stateMachine.start();
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 2485654..518f6c1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -25,6 +25,7 @@
import android.net.NetworkState;
import android.net.RouteInfo;
import android.net.util.NetworkConstants;
+import android.net.util.SharedLog;
import android.util.Log;
import java.net.Inet6Address;
@@ -64,6 +65,7 @@
}
private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
+ private final SharedLog mLog;
// NOTE: mActiveDownstreams is a list and not a hash data structure because
// we keep active downstreams in arrival order. This is done so /64s can
// be parceled out on a "first come, first served" basis and a /64 used by
@@ -74,8 +76,10 @@
private short mNextSubnetId;
private NetworkState mUpstreamNetworkState;
- public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) {
+ public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
+ SharedLog log) {
mNotifyList = notifyList;
+ mLog = log.forSubComponent(TAG);
mActiveDownstreams = new LinkedList<>();
mUniqueLocalPrefix = generateUniqueLocalPrefix();
mNextSubnetId = 0;
@@ -115,7 +119,7 @@
if (VDBG) {
Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
}
- if (!canTetherIPv6(ns)) {
+ if (!canTetherIPv6(ns, mLog)) {
stopIPv6TetheringOnAllInterfaces();
setUpstreamNetworkState(null);
return;
@@ -150,9 +154,7 @@
null);
}
- if (DBG) {
- Log.d(TAG, "setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
- }
+ mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
}
private void updateIPv6TetheringInterfaces() {
@@ -206,7 +208,7 @@
return null;
}
- private static boolean canTetherIPv6(NetworkState ns) {
+ private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
// Broadly speaking:
//
// [1] does the upstream have an IPv6 default route?
@@ -260,13 +262,11 @@
final boolean outcome = canTether && supportedConfiguration;
- if (VDBG) {
- if (ns == null) {
- Log.d(TAG, "No available upstream.");
- } else {
- Log.d(TAG, String.format("IPv6 tethering is %s for upstream: %s",
- (outcome ? "available" : "not available"), toDebugString(ns)));
- }
+ if (ns == null) {
+ sharedLog.log("No available upstream.");
+ } else {
+ sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
+ (outcome ? "available" : "not available"), toDebugString(ns)));
}
return outcome;
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
index c6a7925..adf4af8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java
@@ -28,10 +28,10 @@
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.NetdService;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.ServiceSpecificException;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
import java.net.Inet6Address;
@@ -54,6 +54,7 @@
private final String mIfName;
private final INetworkManagementService mNMService;
+ private final SharedLog mLog;
private NetworkInterface mNetworkInterface;
private byte[] mHwAddr;
@@ -61,9 +62,11 @@
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
- public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
+ public IPv6TetheringInterfaceServices(
+ String ifname, INetworkManagementService nms, SharedLog log) {
mIfName = ifname;
mNMService = nms;
+ mLog = log.forSubComponent(mIfName);
}
public boolean start() {
@@ -72,12 +75,12 @@
try {
mNetworkInterface = NetworkInterface.getByName(mIfName);
} catch (SocketException e) {
- Log.e(TAG, "Error looking up NetworkInterfaces for " + mIfName, e);
+ mLog.e("Error looking up NetworkInterfaces: " + e);
stop();
return false;
}
if (mNetworkInterface == null) {
- Log.e(TAG, "Failed to find NetworkInterface for " + mIfName);
+ mLog.e("Failed to find NetworkInterface");
stop();
return false;
}
@@ -85,7 +88,7 @@
try {
mHwAddr = mNetworkInterface.getHardwareAddress();
} catch (SocketException e) {
- Log.e(TAG, "Failed to find hardware address for " + mIfName, e);
+ mLog.e("Failed to find hardware address: " + e);
stop();
return false;
}
@@ -161,11 +164,11 @@
try {
final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
if (removalFailures > 0) {
- Log.e(TAG, String.format("Failed to remove %d IPv6 routes from local table.",
+ mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
removalFailures));
}
} catch (RemoteException e) {
- Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e);
+ mLog.e("Failed to remove IPv6 routes from local table: " + e);
}
}
@@ -195,7 +198,7 @@
// error (EEXIST is silently ignored).
mNMService.addInterfaceToLocalNetwork(mIfName, toBeAdded);
} catch (RemoteException e) {
- Log.e(TAG, "Failed to add IPv6 routes to local table: ", e);
+ mLog.e("Failed to add IPv6 routes to local table: " + e);
}
}
}
@@ -206,7 +209,7 @@
final INetd netd = NetdService.getInstance();
if (netd == null) {
if (newDnses != null) newDnses.clear();
- Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
+ mLog.e("No netd service instance available; not setting local IPv6 addresses");
return;
}
@@ -217,7 +220,7 @@
try {
netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
+ mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
}
}
}
@@ -234,7 +237,7 @@
try {
netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
+ mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
newDnses.remove(dns);
}
}
@@ -243,7 +246,7 @@
try {
netd.tetherApplyDnsInterfaces();
} catch (ServiceSpecificException | RemoteException e) {
- Log.e(TAG, "Failed to update local DNS caching server");
+ mLog.e("Failed to update local DNS caching server");
if (newDnses != null) newDnses.clear();
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 220e751..ec7ab5b 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -18,10 +18,11 @@
import android.net.LinkProperties;
import android.os.Handler;
-import android.util.Log;
+import android.net.util.SharedLog;
/**
- * A wrapper around hardware offload interface.
+ * A class to encapsulate the business logic of programming the tethering
+ * hardware offload interface.
*
* @hide
*/
@@ -29,25 +30,50 @@
private static final String TAG = OffloadController.class.getSimpleName();
private final Handler mHandler;
+ private final OffloadHardwareInterface mHwInterface;
+ private final SharedLog mLog;
+ private boolean mConfigInitialized;
+ private boolean mControlInitialized;
private LinkProperties mUpstreamLinkProperties;
- public OffloadController(Handler h) {
+ public OffloadController(Handler h, OffloadHardwareInterface hwi, SharedLog log) {
mHandler = h;
+ mHwInterface = hwi;
+ mLog = log.forSubComponent(TAG);
}
public void start() {
- // TODO: initOffload() and configure callbacks to be handled on our
- // preferred Handler.
- Log.d(TAG, "tethering offload not supported");
+ if (started()) return;
+
+ if (!mConfigInitialized) {
+ mConfigInitialized = mHwInterface.initOffloadConfig();
+ if (!mConfigInitialized) {
+ mLog.i("tethering offload config not supported");
+ return;
+ }
+ }
+
+ // TODO: Create and register ITetheringOffloadCallback.
+ mControlInitialized = mHwInterface.initOffloadControl();
}
public void stop() {
- // TODO: stopOffload().
mUpstreamLinkProperties = null;
+ mHwInterface.stopOffloadControl();
+ mControlInitialized = false;
+ mConfigInitialized = false;
}
public void setUpstreamLinkProperties(LinkProperties lp) {
+ if (!started()) return;
+
// TODO: setUpstreamParameters().
mUpstreamLinkProperties = lp;
}
+
+ // TODO: public void addDownStream(...)
+
+ private boolean started() {
+ return mConfigInitialized && mControlInitialized;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
new file mode 100644
index 0000000..87fc491
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
+import android.hardware.tetheroffload.control.V1_0.IOffloadControl.stopOffloadCallback;
+import android.os.RemoteException;
+import android.util.Log;
+
+
+/**
+ * Capture tethering dependencies, for injection.
+ *
+ * @hide
+ */
+public class OffloadHardwareInterface {
+ private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
+
+ private static native boolean configOffload();
+
+ private IOffloadControl mOffloadControl;
+
+ public OffloadHardwareInterface() {}
+
+ public boolean initOffloadConfig() {
+ return configOffload();
+ }
+
+ // TODO: Extend this to take a TetheringControlCallback for registration.
+ public boolean initOffloadControl() {
+ if (mOffloadControl == null) {
+ try {
+ mOffloadControl = IOffloadControl.getService();
+ } catch (RemoteException e) {
+ Log.d(TAG, "tethering offload control not supported: " + e);
+ return false;
+ }
+ }
+
+ // TODO: call mOffloadControl.initOffload(...callback...);
+
+ return true;
+ }
+
+ public void stopOffloadControl() {
+ if (mOffloadControl == null) return;
+
+ try {
+ final stopOffloadCallback cb = new stopOffloadCallback() {
+ @Override
+ public void onValues(boolean success, String errMsg) {
+ if (success) return;
+
+ Log.e(TAG, "stopOffload failed: " + errMsg);
+ }
+ };
+ mOffloadControl.stopOffload(cb);
+ } catch (RemoteException e) {
+ Log.d(TAG, "failed to stopOffload: " + e);
+ }
+ mOffloadControl = null;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index d3cfd87..4a1d405 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -22,6 +22,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
@@ -82,6 +83,7 @@
private final State mTetheredState;
private final State mUnavailableState;
+ private final SharedLog mLog;
private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
private final IControlsTethering mTetherController;
@@ -93,10 +95,12 @@
private int mLastError;
private String mMyUpstreamIfaceName; // may change over time
- public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
- INetworkManagementService nMService, INetworkStatsService statsService,
- IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
+ public TetherInterfaceStateMachine(
+ String ifaceName, Looper looper, int interfaceType, SharedLog log,
+ INetworkManagementService nMService, INetworkStatsService statsService,
+ IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
super(ifaceName, looper);
+ mLog = log.forSubComponent(ifaceName);
mNMService = nMService;
mStatsService = statsService;
mTetherController = tetherController;
@@ -162,7 +166,7 @@
mNMService.setInterfaceConfig(mIfaceName, ifcg);
}
} catch (Exception e) {
- Log.e(TAG, "Error configuring interface " + mIfaceName, e);
+ mLog.e("Error configuring interface " + e);
return false;
}
@@ -203,7 +207,7 @@
transitionTo(mTetheredState);
break;
default:
- Log.e(TAG, "Invalid tethering interface serving state specified.");
+ mLog.e("Invalid tethering interface serving state specified.");
}
break;
case CMD_INTERFACE_DOWN:
@@ -232,13 +236,13 @@
try {
mNMService.tetherInterface(mIfaceName);
} catch (Exception e) {
- Log.e(TAG, "Error Tethering: " + e.toString());
+ mLog.e("Error Tethering: " + e);
mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
if (!mIPv6TetherSvc.start()) {
- Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
+ mLog.e("Failed to start IPv6TetheringInterfaceServices");
// TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
return;
}
@@ -255,7 +259,7 @@
mNMService.untetherInterface(mIfaceName);
} catch (Exception e) {
mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
- Log.e(TAG, "Failed to untether interface: " + e.toString());
+ mLog.e("Failed to untether interface: " + e);
}
configureIfaceIp(false);
@@ -316,7 +320,7 @@
maybeLogMessage(this, message.what);
switch (message.what) {
case CMD_TETHER_REQUESTED:
- Log.e(TAG, "CMD_TETHER_REQUESTED while in local hotspot mode.");
+ mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
// Ignored in local hotspot state.
@@ -389,7 +393,7 @@
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
- Log.e(TAG, "CMD_TETHER_REQUESTED while already tethering.");
+ mLog.e("CMD_TETHER_REQUESTED while already tethering.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
String newUpstreamIfaceName = (String)(message.obj);
@@ -406,7 +410,7 @@
mNMService.startInterfaceForwarding(mIfaceName,
newUpstreamIfaceName);
} catch (Exception e) {
- Log.e(TAG, "Exception enabling Nat: " + e.toString());
+ mLog.e("Exception enabling NAT: " + e);
cleanupUpstreamInterface(newUpstreamIfaceName);
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index d38beb3..44c61f0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity.tethering;
+import static android.content.Context.TELEPHONY_SERVICE;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -47,9 +48,9 @@
public class TetheringConfiguration {
private static final String TAG = TetheringConfiguration.class.getSimpleName();
- private static final int DUN_NOT_REQUIRED = 0;
- private static final int DUN_REQUIRED = 1;
- private static final int DUN_UNSPECIFIED = 2;
+ public static final int DUN_NOT_REQUIRED = 0;
+ public static final int DUN_REQUIRED = 1;
+ public static final int DUN_UNSPECIFIED = 2;
// USB is 192.168.42.1 and 255.255.255.0
// Wifi is 192.168.43.1 and 255.255.255.0
@@ -81,8 +82,9 @@
tetherableBluetoothRegexs = ctx.getResources().getStringArray(
com.android.internal.R.array.config_tether_bluetooth_regexs);
- isDunRequired = checkDunRequired(ctx);
- preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, isDunRequired);
+ final int dunCheck = checkDunRequired(ctx);
+ preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
+ isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
dhcpRanges = getDhcpRanges(ctx);
defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
@@ -138,14 +140,12 @@
pw.println();
}
- private static boolean checkDunRequired(Context ctx) {
- final TelephonyManager tm = ctx.getSystemService(TelephonyManager.class);
- final int secureSetting =
- (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
- return (secureSetting == DUN_REQUIRED);
+ private static int checkDunRequired(Context ctx) {
+ final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
+ return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
}
- private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, boolean requiresDun) {
+ private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
final int ifaceTypes[] = ctx.getResources().getIntArray(
com.android.internal.R.array.config_tether_upstream_types);
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
@@ -153,10 +153,10 @@
switch (i) {
case TYPE_MOBILE:
case TYPE_MOBILE_HIPRI:
- if (requiresDun) continue;
+ if (dunCheck == DUN_REQUIRED) continue;
break;
case TYPE_MOBILE_DUN:
- if (!requiresDun) continue;
+ if (dunCheck == DUN_NOT_REQUIRED) continue;
break;
}
upstreamIfaceTypes.add(i);
@@ -166,7 +166,7 @@
// of the value of |requiresDun|, cell data of one form or another is
// *always* an upstream, regardless of the upstream interface types
// specified by configuration resources.
- if (requiresDun) {
+ if (dunCheck == DUN_REQUIRED) {
if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
new file mode 100644
index 0000000..be2cf08
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+
+/**
+ * Capture tethering dependencies, for injection.
+ *
+ * @hide
+ */
+public class TetheringDependencies {
+ public OffloadHardwareInterface getOffloadHardwareInterface() {
+ return new OffloadHardwareInterface();
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 97a2d5e..be71490 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -29,6 +29,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.util.SharedLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -73,6 +74,7 @@
private static final int CALLBACK_MOBILE_REQUEST = 3;
private final Context mContext;
+ private final SharedLog mLog;
private final StateMachine mTarget;
private final Handler mHandler;
private final int mWhat;
@@ -84,16 +86,18 @@
private boolean mDunRequired;
private Network mCurrentDefault;
- public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
+ public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what, SharedLog log) {
mContext = ctx;
mTarget = tgt;
mHandler = mTarget.getHandler();
mWhat = what;
+ mLog = log.forSubComponent(TAG);
}
@VisibleForTesting
- public UpstreamNetworkMonitor(StateMachine tgt, int what, ConnectivityManager cm) {
- this(null, tgt, what);
+ public UpstreamNetworkMonitor(
+ StateMachine tgt, int what, ConnectivityManager cm, SharedLog log) {
+ this(null, tgt, what, log);
mCM = cm;
}
@@ -136,7 +140,7 @@
public void registerMobileNetworkRequest() {
if (mMobileNetworkCallback != null) {
- Log.e(TAG, "registerMobileNetworkRequest() already registered");
+ mLog.e("registerMobileNetworkRequest() already registered");
return;
}
@@ -156,7 +160,7 @@
// TODO: Change the timeout from 0 (no onUnavailable callback) to some
// moderate callback timeout. This might be useful for updating some UI.
// Additionally, we log a message to aid in any subsequent debugging.
- Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
+ mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0ef0561..9dc317a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -71,6 +71,7 @@
final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
private static final String TAG = "DisplayPowerController";
private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
+ private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked";
private static final boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
@@ -90,6 +91,7 @@
private static final int MSG_UPDATE_POWER_STATE = 1;
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
private static final int MSG_SCREEN_ON_UNBLOCKED = 3;
+ private static final int MSG_SCREEN_OFF_UNBLOCKED = 4;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -105,6 +107,7 @@
private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0;
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1;
private static final int REPORTED_TO_POLICY_SCREEN_ON = 2;
+ private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;
private final Object mLock = new Object();
@@ -219,6 +222,7 @@
// The currently active screen on unblocker. This field is non-null whenever
// we are waiting for a callback to release it and unblock the screen.
private ScreenOnUnblocker mPendingScreenOnUnblocker;
+ private ScreenOffUnblocker mPendingScreenOffUnblocker;
// True if we were in the process of turning off the screen.
// This allows us to recover more gracefully from situations where we abort
@@ -230,6 +234,7 @@
// The elapsed real time when the screen on was blocked.
private long mScreenOnBlockStartRealTime;
+ private long mScreenOffBlockStartRealTime;
// Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_SCREEN_* fields.
private int mReportedScreenStateToPolicy;
@@ -810,9 +815,43 @@
}
}
+ private void blockScreenOff() {
+ if (mPendingScreenOffUnblocker == null) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0);
+ mPendingScreenOffUnblocker = new ScreenOffUnblocker();
+ mScreenOffBlockStartRealTime = SystemClock.elapsedRealtime();
+ Slog.i(TAG, "Blocking screen off");
+ }
+ }
+
+ private void unblockScreenOff() {
+ if (mPendingScreenOffUnblocker != null) {
+ mPendingScreenOffUnblocker = null;
+ long delay = SystemClock.elapsedRealtime() - mScreenOffBlockStartRealTime;
+ Slog.i(TAG, "Unblocked screen off after " + delay + " ms");
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0);
+ }
+ }
+
private boolean setScreenState(int state) {
+ final boolean isOff = (state == Display.STATE_OFF);
if (mPowerState.getScreenState() != state) {
- final boolean wasOn = (mPowerState.getScreenState() != Display.STATE_OFF);
+
+ // If we are trying to turn screen off, give policy a chance to do something before we
+ // actually turn the screen off.
+ if (isOff && !mScreenOffBecauseOfProximity) {
+ if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
+ mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_OFF;
+ blockScreenOff();
+ mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);
+ return false;
+ } else if (mPendingScreenOffUnblocker != null) {
+
+ // Abort doing the state change until screen off is unblocked.
+ return false;
+ }
+ }
+
mPowerState.setScreenState(state);
// Tell battery stats about the transition.
@@ -829,13 +868,21 @@
// This surface is essentially the final state of the color fade animation and
// it is only removed once the window manager tells us that the activity has
// finished drawing underneath.
- final boolean isOff = (state == Display.STATE_OFF);
if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF
&& !mScreenOffBecauseOfProximity) {
mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
unblockScreenOn();
mWindowManagerPolicy.screenTurnedOff();
- } else if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
+ } else if (!isOff
+ && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) {
+
+ // We told policy already that screen was turning off, but now we changed our minds.
+ // Complete the full state transition on -> turningOff -> off.
+ unblockScreenOff();
+ mWindowManagerPolicy.screenTurnedOff();
+ mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_OFF;
+ }
+ if (!isOff && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF) {
mReportedScreenStateToPolicy = REPORTED_TO_POLICY_SCREEN_TURNING_ON;
if (mPowerState.getColorFadeLevel() == 0.0f) {
blockScreenOn();
@@ -1282,6 +1329,12 @@
updatePowerState();
}
break;
+ case MSG_SCREEN_OFF_UNBLOCKED:
+ if (mPendingScreenOffUnblocker == msg.obj) {
+ unblockScreenOff();
+ updatePowerState();
+ }
+ break;
}
}
}
@@ -1311,4 +1364,14 @@
mHandler.sendMessage(msg);
}
}
+
+ private final class ScreenOffUnblocker implements WindowManagerPolicy.ScreenOffListener {
+
+ @Override
+ public void onScreenOff() {
+ Message msg = mHandler.obtainMessage(MSG_SCREEN_OFF_UNBLOCKED, this);
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index fe49813..4fc6ddd 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -34,8 +34,13 @@
public abstract class AuthenticationClient extends ClientMonitor {
private long mOpId;
- public abstract boolean handleFailedAttempt();
+ public abstract int handleFailedAttempt();
public abstract void resetFailedAttempts();
+
+ public static final int LOCKOUT_NONE = 0;
+ public static final int LOCKOUT_TIMED = 1;
+ public static final int LOCKOUT_PERMANENT = 2;
+
private boolean mAlreadyCancelled;
public AuthenticationClient(Context context, long halDeviceId, IBinder token,
@@ -79,19 +84,21 @@
FingerprintUtils.vibrateFingerprintError(getContext());
}
// allow system-defined limit of number of attempts before giving up
- boolean inLockoutMode = handleFailedAttempt();
- // send lockout event in case driver doesn't enforce it.
- if (inLockoutMode) {
+ int lockoutMode = handleFailedAttempt();
+ if (lockoutMode != LOCKOUT_NONE) {
try {
- Slog.w(TAG, "Forcing lockout (fp driver code should do this!)");
- stop(false); // cancel fingerprint authentication
- receiver.onError(getHalDeviceId(),
- FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */);
+ Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
+ lockoutMode + ")");
+ stop(false);
+ int errorCode = lockoutMode == LOCKOUT_TIMED ?
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify lockout:", e);
}
}
- result |= inLockoutMode;
+ result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
} else {
if (receiver != null) {
FingerprintUtils.vibrateFingerprintSuccess(getContext());
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6f5b028..6cc7071 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -108,6 +108,7 @@
int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
// acquisition in some cases (too fast, too slow, dirty sensor, etc.)
int lockout; // total number of lockouts
+ int permanentLockout; // total number of permanent lockouts
}
private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
@@ -118,13 +119,16 @@
Collections.synchronizedMap(new HashMap<>());
private final AppOpsManager mAppOps;
private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
- private static final int MAX_FAILED_ATTEMPTS = 5;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
+ private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
+
private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
private final String mKeyguardPackage;
private int mCurrentUserId = UserHandle.USER_NULL;
private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
private Context mContext;
private long mHalDeviceId;
+ private boolean mTimedLockoutCleared;
private int mFailedAttempts;
@GuardedBy("this")
private IBiometricsFingerprint mDaemon;
@@ -173,7 +177,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
- resetFailedAttempts();
+ resetFailedAttempts(false /* clearAttemptCounter */);
}
}
};
@@ -181,7 +185,7 @@
private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
@Override
public void run() {
- resetFailedAttempts();
+ resetFailedAttempts(true /* clearAttemptCounter */);
}
};
@@ -369,6 +373,7 @@
if (client != null && client.onError(error, vendorCode)) {
removeClient(client);
}
+
if (DEBUG) Slog.v(TAG, "handleError(client="
+ (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
// This is the magic code that starts the next client when the old client finishes.
@@ -438,7 +443,7 @@
if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
removeClient(client);
}
- if (mPerformanceStats != null && !inLockoutMode()
+ if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
&& client instanceof AuthenticationClient) {
// ignore enrollment acquisitions or acquisitions when we're locked out
mPerformanceStats.acquire++;
@@ -482,8 +487,14 @@
}
}
- private boolean inLockoutMode() {
- return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
+ private int getLockoutMode() {
+ if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
+ return AuthenticationClient.LOCKOUT_PERMANENT;
+ } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&
+ (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
+ return AuthenticationClient.LOCKOUT_TIMED;
+ }
+ return AuthenticationClient.LOCKOUT_NONE;
}
private void scheduleLockoutReset() {
@@ -801,22 +812,27 @@
AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
@Override
- public boolean handleFailedAttempt() {
+ public int handleFailedAttempt() {
mFailedAttempts++;
- if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
+ mTimedLockoutCleared = false;
+ final int lockoutMode = getLockoutMode();
+ if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+ mPerformanceStats.permanentLockout++;
+ } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
mPerformanceStats.lockout++;
}
- if (inLockoutMode()) {
- // Failing multiple times will continue to push out the lockout time.
+
+ // Failing multiple times will continue to push out the lockout time
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
scheduleLockoutReset();
- return true;
+ return lockoutMode;
}
- return false;
+ return AuthenticationClient.LOCKOUT_NONE;
}
@Override
public void resetFailedAttempts() {
- FingerprintService.this.resetFailedAttempts();
+ FingerprintService.this.resetFailedAttempts(true /* clearAttemptCounter */);
}
@Override
@@ -830,11 +846,15 @@
}
};
- if (inLockoutMode()) {
- Slog.v(TAG, "In lockout mode; disallowing authentication");
- // Don't bother starting the client. Just send the error message.
- if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */)) {
- Slog.w(TAG, "Cannot send timeout message to client");
+ int lockoutMode = getLockoutMode();
+ if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(TAG, "In lockout mode(" + lockoutMode +
+ ") ; disallowing authentication");
+ int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+ FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+ if (!client.onError(errorCode, 0 /* vendorCode */)) {
+ Slog.w(TAG, "Cannot send permanent lockout message to client");
}
return;
}
@@ -864,11 +884,16 @@
startClient(client, true /* initiatedByClient */);
}
- protected void resetFailedAttempts() {
- if (DEBUG && inLockoutMode()) {
- Slog.v(TAG, "Reset fingerprint lockout");
+ // attempt counter should only be cleared when Keyguard goes away or when
+ // a fingerprint is successfully authenticated
+ protected void resetFailedAttempts(boolean clearAttemptCounter) {
+ if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+ Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
}
- mFailedAttempts = 0;
+ if (clearAttemptCounter) {
+ mFailedAttempts = 0;
+ }
+ mTimedLockoutCleared = true;
// If we're asked to reset failed attempts externally (i.e. from Keyguard),
// the alarm might still be pending; remove it.
cancelLockoutReset();
@@ -1301,6 +1326,7 @@
set.put("reject", (stats != null) ? stats.reject : 0);
set.put("acquire", (stats != null) ? stats.acquire : 0);
set.put("lockout", (stats != null) ? stats.lockout : 0);
+ set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
// cryptoStats measures statistics about secure fingerprint transactions
// (e.g. to unlock password storage, make secure purchases, etc.)
set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
@@ -1336,6 +1362,7 @@
proto.write(FingerprintActionStatsProto.REJECT, normal.reject);
proto.write(FingerprintActionStatsProto.ACQUIRE, normal.acquire);
proto.write(FingerprintActionStatsProto.LOCKOUT, normal.lockout);
+ proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
proto.end(countsToken);
}
@@ -1348,6 +1375,7 @@
proto.write(FingerprintActionStatsProto.REJECT, crypto.reject);
proto.write(FingerprintActionStatsProto.ACQUIRE, crypto.acquire);
proto.write(FingerprintActionStatsProto.LOCKOUT, crypto.lockout);
+ proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
proto.end(countsToken);
}
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index 88a6bdd..8646107 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -85,7 +85,6 @@
IFingerprintServiceReceiver receiver = getReceiver();
try {
if (receiver != null) {
- // TODO: plumb remaining
receiver.onRemoved(getHalDeviceId(), fingerId, groupId, remaining);
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index e2c1274..b0d76e8 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -63,6 +63,7 @@
import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -218,6 +219,11 @@
private static final String KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
private static final String KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
private static final String KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
+ private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
+ = "max_standard_reschedule_count";
+ private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
+ private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
+ private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
private static final int DEFAULT_MIN_IDLE_COUNT = 1;
private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -233,6 +239,10 @@
private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
+ private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+ private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+ private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
/**
* Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -303,6 +313,24 @@
* memory state.
*/
int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
+ /**
+ * The maximum number of times we allow a job to have itself rescheduled before
+ * giving up on it, for standard jobs.
+ */
+ int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT;
+ /**
+ * The maximum number of times we allow a job to have itself rescheduled before
+ * giving up on it, for jobs that are executing work.
+ */
+ int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT;
+ /**
+ * The minimum backoff time to allow for linear backoff.
+ */
+ long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
+ /**
+ * The minimum backoff time to allow for exponential backoff.
+ */
+ long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -374,6 +402,14 @@
if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
}
+ MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
+ DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
+ MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
+ DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
+ MIN_LINEAR_BACKOFF_TIME = mParser.getLong(KEY_MIN_LINEAR_BACKOFF_TIME,
+ DEFAULT_MIN_LINEAR_BACKOFF_TIME);
+ MIN_EXP_BACKOFF_TIME = mParser.getLong(KEY_MIN_EXP_BACKOFF_TIME,
+ DEFAULT_MIN_EXP_BACKOFF_TIME);
}
}
@@ -421,11 +457,38 @@
pw.print(" "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("=");
pw.print(BG_CRITICAL_JOB_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("=");
+ pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("=");
+ pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println();
+
+ pw.print(" "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("=");
+ pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println();
+
+ pw.print(" "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("=");
+ pw.print(MIN_EXP_BACKOFF_TIME); pw.println();
}
}
final Constants mConstants;
+ static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
+ if (o1.enqueueTime < o2.enqueueTime) {
+ return -1;
+ }
+ return o1.enqueueTime > o2.enqueueTime ? 1 : 0;
+ };
+
+ static <T> void addOrderedItem(ArrayList<T> array, T newItem, Comparator<T> comparator) {
+ int where = Collections.binarySearch(array, newItem, comparator);
+ if (where < 0) {
+ where = ~where;
+ }
+ array.add(where, newItem);
+ }
+
/**
* Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
* still clean up. On reinstall the package will have a new uid.
@@ -647,7 +710,7 @@
// This is a new job, we can just immediately put it on the pending
// list and try to run it.
mJobPackageTracker.notePending(jobStatus);
- mPendingJobs.add(jobStatus);
+ addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
maybeRunPendingJobsLocked();
}
}
@@ -689,6 +752,13 @@
}
}
+ private void cancelJobsForNonExistentUsers() {
+ UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
+ synchronized (mLock) {
+ mJobs.removeJobsOfNonUsers(umi.getUserIds());
+ }
+ }
+
void cancelJobsForPackageAndUid(String pkgName, int uid) {
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
@@ -771,7 +841,7 @@
// except those using the idle exemption flag.
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJob();
+ final JobStatus executing = jsc.getRunningJobLocked();
if (executing != null
&& (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
@@ -798,7 +868,7 @@
if (mPendingJobs.size() <= 0) {
for (int i=0; i<mActiveServices.size(); i++) {
final JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus job = jsc.getRunningJob();
+ final JobStatus job = jsc.getRunningJobLocked();
if (job != null
&& (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
&& !job.dozeWhitelisted) {
@@ -879,6 +949,8 @@
} catch (RemoteException e) {
// ignored; both services live in system_server
}
+ // Remove any jobs that are not associated with any of the current users.
+ cancelJobsForNonExistentUsers();
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
// Let's go!
@@ -918,6 +990,7 @@
if (!jobStatus.isPreparedLocked()) {
Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
}
+ jobStatus.enqueueTime = SystemClock.elapsedRealtime();
final boolean update = mJobs.add(jobStatus);
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
@@ -953,7 +1026,7 @@
private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
- final JobStatus executing = jsc.getRunningJob();
+ final JobStatus executing = jsc.getRunningJobLocked();
if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
jsc.cancelExecutingJobLocked(reason);
return true;
@@ -970,11 +1043,7 @@
private boolean isCurrentlyActiveLocked(JobStatus job) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
- // The 'unsafe' direct-internal-reference running-job inspector is okay to
- // use here because we are already holding the necessary lock *and* we
- // immediately discard the returned object reference, if any; we return
- // only a boolean state indicator to the caller.
- final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
+ final JobStatus running = serviceContext.getRunningJobLocked();
if (running != null && running.matches(job.getUid(), job.getJobId())) {
return true;
}
@@ -1016,18 +1085,38 @@
final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
long delayMillis;
+ if (failureToReschedule.hasWorkLocked()) {
+ if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) {
+ Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+ + backoffAttempts + " > work limit "
+ + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+ return null;
+ }
+ } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) {
+ Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+ + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+ return null;
+ }
+
switch (job.getBackoffPolicy()) {
- case JobInfo.BACKOFF_POLICY_LINEAR:
- delayMillis = initialBackoffMillis * backoffAttempts;
- break;
+ case JobInfo.BACKOFF_POLICY_LINEAR: {
+ long backoff = initialBackoffMillis;
+ if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
+ backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
+ }
+ delayMillis = backoff * backoffAttempts;
+ } break;
default:
if (DEBUG) {
Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
}
- case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
- delayMillis =
- (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
- break;
+ case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
+ long backoff = initialBackoffMillis;
+ if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
+ backoff = mConstants.MIN_EXP_BACKOFF_TIME;
+ }
+ delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
+ } break;
}
delayMillis =
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
@@ -1163,7 +1252,7 @@
// state is such that all ready jobs should be run immediately.
if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
mJobPackageTracker.notePending(runNow);
- mPendingJobs.add(runNow);
+ addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
} else {
queueReadyJobsForExecutionLocked();
}
@@ -1191,6 +1280,17 @@
}
}
+ private void stopNonReadyActiveJobsLocked() {
+ for (int i=0; i<mActiveServices.size(); i++) {
+ JobServiceContext serviceContext = mActiveServices.get(i);
+ final JobStatus running = serviceContext.getRunningJobLocked();
+ if (running != null && !running.isReady()) {
+ serviceContext.cancelExecutingJobLocked(
+ JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
+ }
+ }
+ }
+
/**
* Run through list of jobs and execute all possible - at least one is expired so we do
* as many as we can.
@@ -1201,6 +1301,7 @@
}
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
+ stopNonReadyActiveJobsLocked();
mJobs.forEachJob(mReadyQueueFunctor);
mReadyQueueFunctor.postProcess();
@@ -1227,9 +1328,6 @@
newReadyJobs = new ArrayList<JobStatus>();
}
newReadyJobs.add(job);
- } else if (areJobConstraintsNotSatisfiedLocked(job)) {
- stopJobOnServiceContextLocked(job,
- JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
}
@@ -1237,6 +1335,9 @@
if (newReadyJobs != null) {
noteJobsPending(newReadyJobs);
mPendingJobs.addAll(newReadyJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
+ }
}
newReadyJobs = null;
}
@@ -1305,9 +1406,6 @@
runnableJobs = new ArrayList<>();
}
runnableJobs.add(job);
- } else if (areJobConstraintsNotSatisfiedLocked(job)) {
- stopJobOnServiceContextLocked(job,
- JobParameters.REASON_CONSTRAINTS_NOT_SATISFIED);
}
}
@@ -1326,6 +1424,9 @@
}
noteJobsPending(runnableJobs);
mPendingJobs.addAll(runnableJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
+ }
} else {
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Not running anything.");
@@ -1354,6 +1455,7 @@
noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
+ stopNonReadyActiveJobsLocked();
mJobs.forEachJob(mMaybeQueueFunctor);
mMaybeQueueFunctor.postProcess();
}
@@ -1431,15 +1533,6 @@
}
/**
- * Criteria for cancelling an active job:
- * - It's not ready
- * - It's running on a JSC.
- */
- private boolean areJobConstraintsNotSatisfiedLocked(JobStatus job) {
- return !job.isReady() && isCurrentlyActiveLocked(job);
- }
-
- /**
* Reconcile jobs in the pending queue against available execution contexts.
* A controller can force a job into the pending queue even if it's already running, but
* here is where we decide whether to actually execute it.
@@ -1515,7 +1608,7 @@
int numForeground = 0;
for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
final JobServiceContext js = mActiveServices.get(i);
- final JobStatus status = js.getRunningJob();
+ final JobStatus status = js.getRunningJobLocked();
if ((contextIdToJobMap[i] = status) != null) {
numActive++;
if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
@@ -1591,10 +1684,10 @@
for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
boolean preservePreferredUid = false;
if (act[i]) {
- JobStatus js = mActiveServices.get(i).getRunningJob();
+ JobStatus js = mActiveServices.get(i).getRunningJobLocked();
if (js != null) {
if (DEBUG) {
- Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob());
+ Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJobLocked());
}
// preferredUid will be set to uid of currently running job.
mActiveServices.get(i).preemptExecutingJobLocked();
@@ -2003,6 +2096,83 @@
}
}
+ int getJobState(PrintWriter pw, String pkgName, int userId, int jobId) {
+ try {
+ final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
+ userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM);
+ if (uid < 0) {
+ pw.print("unknown("); pw.print(pkgName); pw.println(")");
+ return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
+ }
+
+ synchronized (mLock) {
+ final JobStatus js = mJobs.getJobByUidAndJobId(uid, jobId);
+ if (DEBUG) Slog.d(TAG, "get-job-state " + uid + "/" + jobId + ": " + js);
+ if (js == null) {
+ pw.print("unknown("); UserHandle.formatUid(pw, uid);
+ pw.print("/jid"); pw.print(jobId); pw.println(")");
+ return JobSchedulerShellCommand.CMD_ERR_NO_JOB;
+ }
+
+ boolean printed = false;
+ if (mPendingJobs.contains(js)) {
+ pw.print("pending");
+ printed = true;
+ }
+ if (isCurrentlyActiveLocked(js)) {
+ if (printed) {
+ pw.print(" ");
+ }
+ printed = true;
+ pw.println("active");
+ }
+ if (!ArrayUtils.contains(mStartedUsers, js.getUserId())) {
+ if (printed) {
+ pw.print(" ");
+ }
+ printed = true;
+ pw.println("user-stopped");
+ }
+ if (mBackingUpUids.indexOfKey(js.getSourceUid()) >= 0) {
+ if (printed) {
+ pw.print(" ");
+ }
+ printed = true;
+ pw.println("backing-up");
+ }
+ boolean componentPresent = false;
+ try {
+ componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+ js.getServiceComponent(),
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ js.getUserId()) != null);
+ } catch (RemoteException e) {
+ }
+ if (!componentPresent) {
+ if (printed) {
+ pw.print(" ");
+ }
+ printed = true;
+ pw.println("no-component");
+ }
+ if (js.isReady()) {
+ if (printed) {
+ pw.print(" ");
+ }
+ printed = true;
+ pw.println("ready");
+ }
+ if (!printed) {
+ pw.print("waiting");
+ }
+ pw.println();
+ }
+ } catch (RemoteException e) {
+ // can't happen
+ }
+ return 0;
+ }
+
private String printContextIdToJobMap(JobStatus[] map, String initial) {
StringBuilder s = new StringBuilder(initial + ": ");
for (int i=0; i<map.length; i++) {
@@ -2067,7 +2237,8 @@
}
final int filterUidFinal = UserHandle.getAppId(filterUid);
- final long now = SystemClock.elapsedRealtime();
+ final long nowElapsed = SystemClock.elapsedRealtime();
+ final long nowUptime = SystemClock.uptimeMillis();
synchronized (mLock) {
mConstants.dump(pw);
pw.println();
@@ -2099,7 +2270,7 @@
continue;
}
- job.dump(pw, " ", true);
+ job.dump(pw, " ", true, nowElapsed);
pw.print(" Ready: ");
pw.print(isReadyToBeExecutedLocked(job));
pw.print(" (job=");
@@ -2169,39 +2340,40 @@
JobStatus job = mPendingJobs.get(i);
pw.print(" Pending #"); pw.print(i); pw.print(": ");
pw.println(job.toShortString());
- job.dump(pw, " ", false);
+ job.dump(pw, " ", false, nowElapsed);
int priority = evaluateJobPriorityLocked(job);
if (priority != JobInfo.PRIORITY_DEFAULT) {
pw.print(" Evaluated priority: "); pw.println(priority);
}
pw.print(" Tag: "); pw.println(job.getTag());
pw.print(" Enq: ");
- TimeUtils.formatDuration(now - job.madePending, pw);
- pw.println(" ago");
+ TimeUtils.formatDuration(job.madePending - nowUptime, pw);
+ pw.println();
}
pw.println();
pw.println("Active jobs:");
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext jsc = mActiveServices.get(i);
pw.print(" Slot #"); pw.print(i); pw.print(": ");
- final JobStatus job = jsc.getRunningJob();
+ final JobStatus job = jsc.getRunningJobLocked();
if (job == null) {
pw.println("inactive");
continue;
} else {
pw.println(job.toShortString());
pw.print(" Running for: ");
- TimeUtils.formatDuration(now - jsc.getExecutionStartTimeElapsed(), pw);
+ TimeUtils.formatDuration(nowElapsed - jsc.getExecutionStartTimeElapsed(), pw);
pw.print(", timeout at: ");
- TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
+ TimeUtils.formatDuration(jsc.getTimeoutElapsed() - nowElapsed, pw);
pw.println();
- job.dump(pw, " ", false);
- int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+ job.dump(pw, " ", false, nowElapsed);
+ int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
if (priority != JobInfo.PRIORITY_DEFAULT) {
pw.print(" Evaluated priority: "); pw.println(priority);
}
- pw.print(" Active at "); pw.println(job.madeActive);
- pw.print(" Pending for ");
+ pw.print(" Active at ");
+ TimeUtils.formatDuration(job.madeActive - nowUptime, pw);
+ pw.print(", pending for ");
TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
pw.println();
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index fdfb345..2d2f61f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -60,6 +60,8 @@
return getStorageSeq(pw);
case "get-storage-not-low":
return getStorageNotLow(pw);
+ case "get-job-state":
+ return getJobState(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -83,6 +85,43 @@
}
}
+ private boolean printError(int errCode, String pkgName, int userId, int jobId) {
+ PrintWriter pw;
+ switch (errCode) {
+ case CMD_ERR_NO_PACKAGE:
+ pw = getErrPrintWriter();
+ pw.print("Package not found: ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ return true;
+
+ case CMD_ERR_NO_JOB:
+ pw = getErrPrintWriter();
+ pw.print("Could not find job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.println(userId);
+ return true;
+
+ case CMD_ERR_CONSTRAINTS:
+ pw = getErrPrintWriter();
+ pw.print("Job ");
+ pw.print(jobId);
+ pw.print(" in package ");
+ pw.print(pkgName);
+ pw.print(" / user ");
+ pw.print(userId);
+ pw.println(" has functional constraints but --force not specified");
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
private int runJob(PrintWriter pw) throws Exception {
checkPermission("force scheduled jobs");
@@ -114,42 +153,17 @@
final long ident = Binder.clearCallingIdentity();
try {
int ret = mInternal.executeRunCommand(pkgName, userId, jobId, force);
- switch (ret) {
- case CMD_ERR_NO_PACKAGE:
- pw.print("Package not found: ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.println(userId);
- break;
-
- case CMD_ERR_NO_JOB:
- pw.print("Could not find job ");
- pw.print(jobId);
- pw.print(" in package ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.println(userId);
- break;
-
- case CMD_ERR_CONSTRAINTS:
- pw.print("Job ");
- pw.print(jobId);
- pw.print(" in package ");
- pw.print(pkgName);
- pw.print(" / user ");
- pw.print(userId);
- pw.println(" has functional constraints but --force not specified");
- break;
-
- default:
- // success!
- pw.print("Running job");
- if (force) {
- pw.print(" [FORCED]");
- }
- pw.println();
- break;
+ if (printError(ret, pkgName, userId, jobId)) {
+ return ret;
}
+
+ // success!
+ pw.print("Running job");
+ if (force) {
+ pw.print(" [FORCED]");
+ }
+ pw.println();
+
return ret;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -244,6 +258,43 @@
return 0;
}
+ private int getJobState(PrintWriter pw) throws Exception {
+ checkPermission("force timeout jobs");
+
+ int userId = UserHandle.USER_SYSTEM;
+
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-u":
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = ActivityManager.getCurrentUser();
+ }
+
+ final String pkgName = getNextArgRequired();
+ final String jobIdStr = getNextArgRequired();
+ final int jobId = Integer.parseInt(jobIdStr);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ int ret = mInternal.getJobState(pw, pkgName, userId, jobId);
+ printError(ret, pkgName, userId, jobId);
+ return ret;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
@@ -277,6 +328,18 @@
pw.println(" Return the last storage update sequence number that was received.");
pw.println(" get-storage-not-low");
pw.println(" Return whether storage is currently considered to not be low.");
+ pw.println(" get-job-state [-u | --user USER_ID] PACKAGE JOB_ID");
+ pw.println(" Return the current state of a job, may be any combination of:");
+ pw.println(" pending: currently on the pending list, waiting to be active");
+ pw.println(" active: job is actively running");
+ pw.println(" user-stopped: job can't run because its user is stopped");
+ pw.println(" backing-up: job can't run because app is currently backing up its data");
+ pw.println(" no-component: job can't run because its component is not available");
+ pw.println(" ready: job is ready to run (all constraints satisfied or bypassed)");
+ pw.println(" waiting: if nothing else above is printed, job not ready to run");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's job is to be run; the default is");
+ pw.println(" the primary or system user");
pw.println();
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index bdcf642..ff39baf 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -146,7 +146,7 @@
}
/**
- * Give a job to this context for execution. Callers must first check {@link #getRunningJob()}
+ * Give a job to this context for execution. Callers must first check {@link #getRunningJobLocked()}
* and ensure it is null to make sure this is a valid context.
* @param job The status of the job that we are going to run.
* @return True if the job is valid and is running. False if the job cannot be executed.
@@ -210,23 +210,8 @@
/**
* Used externally to query the running job. Will return null if there is no job running.
- * Be careful when using this function, at any moment it's possible that the job returned may
- * stop executing.
*/
- JobStatus getRunningJob() {
- final JobStatus job;
- synchronized (mLock) {
- job = mRunningJob;
- }
- return job == null ? null : new JobStatus(job);
- }
-
- /**
- * Internal non-cloning inspection of the currently running job, if any. The lock
- * must be held when calling this *and* for the entire lifetime of using its returned
- * JobStatus object!
- */
- JobStatus getRunningJobUnsafeLocked() {
+ JobStatus getRunningJobLocked() {
return mRunningJob;
}
@@ -256,7 +241,7 @@
}
boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
- final JobStatus executing = getRunningJob();
+ final JobStatus executing = getRunningJobLocked();
if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
&& (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
&& (!matchJobId || jobId == executing.getJobId())) {
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 57b1ccc..22eed3b 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -35,6 +35,7 @@
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.IoThread;
import com.android.server.job.controllers.JobStatus;
@@ -171,6 +172,14 @@
return removed;
}
+ /**
+ * Remove the jobs of users not specified in the whitelist.
+ * @param whitelist Array of User IDs whose jobs are not to be removed.
+ */
+ public void removeJobsOfNonUsers(int[] whitelist) {
+ mJobSet.removeJobsOfNonUsers(whitelist);
+ }
+
@VisibleForTesting
public void clear() {
mJobSet.clear();
@@ -454,10 +463,12 @@
synchronized (mLock) {
jobs = readJobMapImpl(fis);
if (jobs != null) {
+ long now = SystemClock.elapsedRealtime();
IActivityManager am = ActivityManager.getService();
for (int i=0; i<jobs.size(); i++) {
JobStatus js = jobs.get(i);
js.prepareLocked(am);
+ js.enqueueTime = now;
this.jobSet.add(js);
}
}
@@ -837,6 +848,17 @@
return didRemove;
}
+ // Remove the jobs all users not specified by the whitelist of user ids
+ public void removeJobsOfNonUsers(int[] whitelist) {
+ for (int jobIndex = mJobs.size() - 1; jobIndex >= 0; jobIndex--) {
+ int jobUserId = UserHandle.getUserId(mJobs.keyAt(jobIndex));
+ // check if job's user id is not in the whitelist
+ if (!ArrayUtils.contains(whitelist, jobUserId)) {
+ mJobs.removeAt(jobIndex);
+ }
+ }
+ }
+
public boolean contains(JobStatus job) {
final int uid = job.getUid();
ArraySet<JobStatus> jobs = mJobs.get(uid);
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index b1f8f6b..d275bd9 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -93,34 +93,31 @@
}
}
- private void maybeReportNewChargingState() {
+ private void maybeReportNewChargingStateLocked() {
final boolean stablePower = mChargeTracker.isOnStablePower();
final boolean batteryNotLow = mChargeTracker.isBatteryNotLow();
if (DEBUG) {
- Slog.d(TAG, "maybeReportNewChargingState: " + stablePower);
+ Slog.d(TAG, "maybeReportNewChargingStateLocked: " + stablePower);
}
boolean reportChange = false;
- synchronized (mLock) {
- for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
- final JobStatus ts = mTrackedTasks.valueAt(i);
- boolean previous = ts.setChargingConstraintSatisfied(stablePower);
- if (previous != stablePower) {
- reportChange = true;
- }
- previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
- if (previous != batteryNotLow) {
- reportChange = true;
- }
+ for (int i = mTrackedTasks.size() - 1; i >= 0; i--) {
+ final JobStatus ts = mTrackedTasks.valueAt(i);
+ boolean previous = ts.setChargingConstraintSatisfied(stablePower);
+ if (previous != stablePower) {
+ reportChange = true;
+ }
+ previous = ts.setBatteryNotLowConstraintSatisfied(batteryNotLow);
+ if (previous != batteryNotLow) {
+ reportChange = true;
}
}
- // Let the scheduler know that state has changed. This may or may not result in an
- // execution.
- if (reportChange) {
- mStateChangedListener.onControllerStateChanged();
- }
- // Also tell the scheduler that any ready jobs should be flushed.
if (stablePower || batteryNotLow) {
+ // If one of our conditions has been satisfied, always schedule any newly ready jobs.
mStateChangedListener.onRunJobNow(null);
+ } else if (reportChange) {
+ // Otherwise, just let the job scheduler know the state has changed and take care of it
+ // as it thinks is best.
+ mStateChangedListener.onControllerStateChanged();
}
}
@@ -201,38 +198,42 @@
@VisibleForTesting
public void onReceiveInternal(Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_BATTERY_LOW.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Battery life too low to do work. @ "
- + SystemClock.elapsedRealtime());
+ synchronized (mLock) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_BATTERY_LOW.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Battery life too low to do work. @ "
+ + SystemClock.elapsedRealtime());
+ }
+ // If we get this action, the battery is discharging => it isn't plugged in so
+ // there's no work to cancel. We track this variable for the case where it is
+ // charging, but hasn't been for long enough to be healthy.
+ mBatteryHealthy = false;
+ maybeReportNewChargingStateLocked();
+ } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Battery life healthy enough to do work. @ "
+ + SystemClock.elapsedRealtime());
+ }
+ mBatteryHealthy = true;
+ maybeReportNewChargingStateLocked();
+ } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Received charging intent, fired @ "
+ + SystemClock.elapsedRealtime());
+ }
+ mCharging = true;
+ maybeReportNewChargingStateLocked();
+ } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Disconnected from power.");
+ }
+ mCharging = false;
+ maybeReportNewChargingStateLocked();
}
- // If we get this action, the battery is discharging => it isn't plugged in so
- // there's no work to cancel. We track this variable for the case where it is
- // charging, but hasn't been for long enough to be healthy.
- mBatteryHealthy = false;
- } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Battery life healthy enough to do work. @ "
- + SystemClock.elapsedRealtime());
- }
- mBatteryHealthy = true;
- maybeReportNewChargingState();
- } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Received charging intent, fired @ "
- + SystemClock.elapsedRealtime());
- }
- mCharging = true;
- maybeReportNewChargingState();
- } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
- if (DEBUG) {
- Slog.d(TAG, "Disconnected from power.");
- }
- mCharging = false;
- maybeReportNewChargingState();
+ mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE,
+ mLastBatterySeq);
}
- mLastBatterySeq = intent.getIntExtra(BatteryManager.EXTRA_SEQUENCE, mLastBatterySeq);
}
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 4d507d6..53bf402 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -22,14 +22,10 @@
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.Intent;
import android.net.Uri;
-import android.os.Binder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -180,7 +176,10 @@
// Used by shell commands
public int overrideState = 0;
- // Metrics about queue latency
+ // When this job was enqueued, for ordering. (in elapsedRealtimeMillis)
+ public long enqueueTime;
+
+ // Metrics about queue latency. (in uptimeMillis)
public long madePending;
public long madeActive;
@@ -349,6 +348,10 @@
return null;
}
+ public boolean hasWorkLocked() {
+ return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
+ }
+
public boolean hasExecutingWorkLocked() {
return executingWork != null && executingWork.size() > 0;
}
@@ -744,10 +747,11 @@
sb.append(getSourceUid());
if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
|| latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
+ long now = SystemClock.elapsedRealtime();
sb.append(" TIME=");
- sb.append(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
- sb.append("-");
- sb.append(formatRunTime(latestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
+ formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
+ sb.append(":");
+ formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
}
if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
sb.append(" NET=");
@@ -789,17 +793,19 @@
return sb.toString();
}
- private String formatRunTime(long runtime, long defaultValue) {
+ private void formatRunTime(PrintWriter pw, long runtime, long defaultValue, long now) {
if (runtime == defaultValue) {
- return "none";
+ pw.print("none");
} else {
- long elapsedNow = SystemClock.elapsedRealtime();
- long nextRuntime = runtime - elapsedNow;
- if (nextRuntime > 0) {
- return DateUtils.formatElapsedTime(nextRuntime / 1000);
- } else {
- return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
- }
+ TimeUtils.formatDuration(runtime - now, pw);
+ }
+ }
+
+ private void formatRunTime(StringBuilder sb, long runtime, long defaultValue, long now) {
+ if (runtime == defaultValue) {
+ sb.append("none");
+ } else {
+ TimeUtils.formatDuration(runtime - now, sb);
}
}
@@ -881,7 +887,7 @@
}
// Dumpsys infrastructure
- public void dump(PrintWriter pw, String prefix, boolean full) {
+ public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
pw.print(prefix);
@@ -1020,10 +1026,14 @@
dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
}
}
- pw.print(prefix); pw.print("Earliest run time: ");
- pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
- pw.print(prefix); pw.print("Latest run time: ");
- pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
+ pw.print(prefix); pw.print("Enqueue time: ");
+ TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
+ pw.println();
+ pw.print(prefix); pw.print("Run time: earliest=");
+ formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
+ pw.print(", latest=");
+ formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
+ pw.println();
if (numFailures != 0) {
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 45971f5..4ada555 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -943,7 +943,7 @@
long time = mNtpTime.getCachedNtpTime();
long timeReference = mNtpTime.getCachedNtpTimeReference();
long certainty = mNtpTime.getCacheCertainty();
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
if (DEBUG) {
Log.d(TAG, "NTP server returned: "
@@ -1458,7 +1458,7 @@
// reset SV count to zero
updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
- mFixRequestTime = System.currentTimeMillis();
+ mFixRequestTime = SystemClock.elapsedRealtime();
if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
// and our fix interval is not short
@@ -1535,12 +1535,12 @@
mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
}
if (mTimeToFirstFix > 0) {
- int timeBetweenFixes = (int) (System.currentTimeMillis() - mLastFixTime);
+ int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
}
}
- mLastFixTime = System.currentTimeMillis();
+ mLastFixTime = SystemClock.elapsedRealtime();
// report time to first fix
if (mTimeToFirstFix == 0 && hasLatLong) {
mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
@@ -1665,7 +1665,7 @@
updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
- System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
+ SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
// send an intent to notify that the GPS is no longer receiving fixes.
Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6b8a74f..8753a3a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -135,6 +135,7 @@
private static final int PROFILE_KEY_IV_SIZE = 12;
private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
+ // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
private final Object mSeparateChallengeLock = new Object();
private final Injector mInjector;
@@ -149,12 +150,12 @@
private final NotificationManager mNotificationManager;
private final UserManager mUserManager;
private final IActivityManager mActivityManager;
+ private final SyntheticPasswordManager mSpManager;
private final KeyStore mKeyStore;
private boolean mFirstCallToVold;
protected IGateKeeperService mGateKeeperService;
- private SyntheticPasswordManager mSpManager;
/**
* The UIDs that are used for system credential storage in keystore.
@@ -2187,23 +2188,23 @@
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- synchronized (this) {
- pw.println("Current lock settings service state:");
- pw.println(String.format("SP Enabled = %b",
- mLockPatternUtils.isSyntheticPasswordEnabled()));
+ pw.println("Current lock settings service state:");
+ pw.println(String.format("SP Enabled = %b",
+ mLockPatternUtils.isSyntheticPasswordEnabled()));
- List<UserInfo> users = mUserManager.getUsers();
- for (int user = 0; user < users.size(); user++) {
- final int userId = users.get(user).id;
- pw.println(" User " + userId);
+ List<UserInfo> users = mUserManager.getUsers();
+ for (int user = 0; user < users.size(); user++) {
+ final int userId = users.get(user).id;
+ pw.println(" User " + userId);
+ synchronized (mSpManager) {
pw.println(String.format(" SP Handle = %x",
getSyntheticPasswordHandleLocked(userId)));
- try {
- pw.println(String.format(" SID = %x",
- getGateKeeperService().getSecureUserId(userId)));
- } catch (RemoteException e) {
- // ignore.
- }
+ }
+ try {
+ pw.println(String.format(" SID = %x",
+ getGateKeeperService().getSecureUserId(userId)));
+ } catch (RemoteException e) {
+ // ignore.
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 861209d..d621a68 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -26,6 +26,7 @@
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
@@ -339,8 +340,11 @@
synchronized (mFileWriteLock) {
RandomAccessFile raf = null;
try {
- // Write the hash to file
- raf = new RandomAccessFile(name, "rw");
+ // Write the hash to file, requiring each write to be synchronized to the
+ // underlying storage device immediately to avoid data loss in case of power loss.
+ // This also ensures future secdiscard operation on the file succeeds since the
+ // file would have been allocated on flash.
+ raf = new RandomAccessFile(name, "rws");
// Truncate the file if pattern is null, to clear the lock
if (hash == null || hash.length == 0) {
raf.setLength(0);
@@ -435,12 +439,17 @@
return readFile(getSynthenticPasswordStateFilePathForUser(userId, handle, name));
}
- public void deleteSyntheticPasswordState(int userId, long handle, String name, boolean secure) {
+ public void deleteSyntheticPasswordState(int userId, long handle, String name) {
String path = getSynthenticPasswordStateFilePathForUser(userId, handle, name);
File file = new File(path);
if (file.exists()) {
- //TODO: (b/34600579) invoke secdiscardable
- file.delete();
+ try {
+ mContext.getSystemService(StorageManager.class).secdiscard(file.getAbsolutePath());
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to secdiscard " + path, e);
+ } finally {
+ file.delete();
+ }
mCache.putFile(path, null);
}
}
@@ -546,7 +555,7 @@
void initialize(SQLiteDatabase db);
}
- class DatabaseHelper extends SQLiteOpenHelper {
+ static class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "LockSettingsDB";
private static final String DATABASE_NAME = "locksettings.db";
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index e2ec92b..2f8a1b4 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -452,7 +452,7 @@
// Nuke the SP handle (and as a result, its SID) for the given user.
public void clearSidForUser(int userId) {
- destroyState(SP_HANDLE_NAME, true, DEFAULT_HANDLE, userId);
+ destroyState(SP_HANDLE_NAME, DEFAULT_HANDLE, userId);
}
public boolean hasSidForUser(int userId) {
@@ -487,8 +487,8 @@
}
public void destroyEscrowData(int userId) {
- destroyState(SP_E0_NAME, true, DEFAULT_HANDLE, userId);
- destroyState(SP_P1_NAME, true, DEFAULT_HANDLE, userId);
+ destroyState(SP_E0_NAME, DEFAULT_HANDLE, userId);
+ destroyState(SP_P1_NAME, DEFAULT_HANDLE, userId);
}
private int loadWeaverSlot(long handle, int userId) {
@@ -523,7 +523,7 @@
Log.w(TAG, "Failed to destroy slot", e);
}
}
- destroyState(WEAVER_SLOT_NAME, true, handle, userId);
+ destroyState(WEAVER_SLOT_NAME, handle, userId);
}
private int getNextAvailableWeaverSlot() {
@@ -877,17 +877,17 @@
public void destroyTokenBasedSyntheticPassword(long handle, int userId) {
destroySyntheticPassword(handle, userId);
- destroyState(SECDISCARDABLE_NAME, true, handle, userId);
+ destroyState(SECDISCARDABLE_NAME, handle, userId);
}
public void destroyPasswordBasedSyntheticPassword(long handle, int userId) {
destroySyntheticPassword(handle, userId);
- destroyState(SECDISCARDABLE_NAME, true, handle, userId);
- destroyState(PASSWORD_DATA_NAME, true, handle, userId);
+ destroyState(SECDISCARDABLE_NAME, handle, userId);
+ destroyState(PASSWORD_DATA_NAME, handle, userId);
}
private void destroySyntheticPassword(long handle, int userId) {
- destroyState(SP_BLOB_NAME, true, handle, userId);
+ destroyState(SP_BLOB_NAME, handle, userId);
destroySPBlobKey(getHandleName(handle));
if (hasState(WEAVER_SLOT_NAME, handle, userId)) {
destroyWeaverSlot(handle, userId);
@@ -938,8 +938,8 @@
mStorage.writeSyntheticPasswordState(userId, handle, stateName, data);
}
- private void destroyState(String stateName, boolean secure, long handle, int userId) {
- mStorage.deleteSyntheticPasswordState(userId, handle, stateName, secure);
+ private void destroyState(String stateName, long handle, int userId) {
+ mStorage.deleteSyntheticPasswordState(userId, handle, stateName);
}
protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] applicationId) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 0db1b5d..e0017b5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -673,7 +673,7 @@
public void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession,
MediaSessionRecord newMediaButtonSession) {
if (DEBUG_KEY_EVENT) {
- Log.d(TAG, "Media button session will be changed to " + newMediaButtonSession);
+ Log.d(TAG, "Media button session is changed to " + newMediaButtonSession);
}
synchronized (mLock) {
if (oldMediaButtonSession != null) {
@@ -1505,7 +1505,8 @@
}
private boolean isVoiceKey(int keyCode) {
- return keyCode == KeyEvent.KEYCODE_HEADSETHOOK;
+ return keyCode == KeyEvent.KEYCODE_HEADSETHOOK
+ || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
}
private boolean isUserSetupComplete() {
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index cd0da79..f474769 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -124,9 +124,7 @@
// When the media button session is removed, nullify the media button session and do not
// search for the alternative media session within the app. It's because the alternative
// media session might be a dummy which isn't able to handle the media key events.
- mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
- mMediaButtonSession, null);
- mMediaButtonSession = null;
+ updateMediaButtonSession(null);
}
clearCache(record.getUserId());
}
@@ -163,9 +161,7 @@
MediaSessionRecord newMediaButtonSession =
findMediaButtonSession(mMediaButtonSession.getUid());
if (newMediaButtonSession != mMediaButtonSession) {
- mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
- mMediaButtonSession, newMediaButtonSession);
- mMediaButtonSession = newMediaButtonSession;
+ updateMediaButtonSession(newMediaButtonSession);
}
}
}
@@ -199,9 +195,7 @@
// Found the media button session.
mAudioPlaybackMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
if (mMediaButtonSession != mediaButtonSession) {
- mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
- mMediaButtonSession, mediaButtonSession);
- mMediaButtonSession = mediaButtonSession;
+ updateMediaButtonSession(mediaButtonSession);
}
return;
}
@@ -262,6 +256,13 @@
return mMediaButtonSession;
}
+ private void updateMediaButtonSession(MediaSessionRecord newMediaButtonSession) {
+ MediaSessionRecord oldMediaButtonSession = mMediaButtonSession;
+ mMediaButtonSession = newMediaButtonSession;
+ mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
+ oldMediaButtonSession, newMediaButtonSession);
+ }
+
public MediaSessionRecord getDefaultVolumeSession() {
if (mCachedVolumeDefault != null) {
return mCachedVolumeDefault;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 5a5e658..803b0dc 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -153,7 +153,7 @@
final ApplicationInfo applicationInfo =
mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
0, UserHandle.getUserId(sbn.getUid()));
- if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+ if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) {
return true;
}
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index e83d453..f00ef38 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -286,7 +286,7 @@
private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
final int userId = UserHandle.getUserId(r.uid);
final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
- if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
// O apps should not have the default channel.
return false;
}
@@ -1158,6 +1158,9 @@
public boolean badgingEnabled(UserHandle userHandle) {
int userId = userHandle.getIdentifier();
+ if (userId == UserHandle.USER_ALL) {
+ return false;
+ }
if (mBadgingEnabled.indexOfKey(userId) < 0) {
mBadgingEnabled.put(userId,
Secure.getIntForUser(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0e1f485..ef3e7bc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -20,6 +20,7 @@
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
@@ -46,6 +47,7 @@
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -243,11 +245,14 @@
packageFilter, null, null);
final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_ADDED);
userFilter.addAction(ACTION_USER_REMOVED);
getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
userFilter, null, null);
restoreSettings();
+
+ initIfNeeded();
onSwitchUser(UserHandle.USER_SYSTEM);
publishBinderService(Context.OVERLAY_SERVICE, mService);
@@ -269,14 +274,31 @@
}
}
+ private void initIfNeeded() {
+ final UserManager um = getContext().getSystemService(UserManager.class);
+ final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+ synchronized (mLock) {
+ final int userCount = users.size();
+ for (int i = 0; i < userCount; i++) {
+ final UserInfo userInfo = users.get(i);
+ if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
+ // Initialize any users that can't be switched to, as there state would
+ // never be setup in onSwitchUser(). We will switch to the system user right
+ // after this, and its state will be setup there.
+ final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
+ updateOverlayPaths(users.get(i).id, targets);
+ }
+ }
+ }
+ }
+
@Override
public void onSwitchUser(final int newUserId) {
// ensure overlays in the settings are up-to-date, and propagate
// any asset changes to the rest of the system
- final List<String> targets;
synchronized (mLock) {
- targets = mImpl.onSwitchUser(newUserId);
- updateAssetsLocked(newUserId, targets);
+ final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+ updateAssets(newUserId, targets);
}
schedulePersistSettings();
}
@@ -428,10 +450,19 @@
private final class UserReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
switch (intent.getAction()) {
+ case ACTION_USER_ADDED:
+ if (userId != UserHandle.USER_NULL) {
+ final ArrayList<String> targets;
+ synchronized (mLock) {
+ targets = mImpl.updateOverlaysForUser(userId);
+ }
+ updateOverlayPaths(userId, targets);
+ }
+ break;
+
case ACTION_USER_REMOVED:
- final int userId =
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (userId != UserHandle.USER_NULL) {
synchronized (mLock) {
mImpl.onUserRemoved(userId);
@@ -647,9 +678,7 @@
public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
schedulePersistSettings();
FgThread.getHandler().post(() -> {
- synchronized (mLock) {
- updateAssetsLocked(userId, targetPackageName);
- }
+ updateAssets(userId, targetPackageName);
final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
Uri.fromParts("package", targetPackageName, null));
@@ -670,13 +699,10 @@
}
}
- private void updateAssetsLocked(final int userId, final String targetPackageName) {
- final List<String> list = new ArrayList<>();
- list.add(targetPackageName);
- updateAssetsLocked(userId, list);
- }
-
- private void updateAssetsLocked(final int userId, List<String> targetPackageNames) {
+ /**
+ * Updates the target packages' set of enabled overlays in PackageManager.
+ */
+ private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
if (DEBUG) {
Slog.d(TAG, "Updating overlay assets");
}
@@ -706,12 +732,19 @@
}
if (!pm.setEnabledOverlayPackages(
- userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+ userId, targetPackageName, pendingChanges.get(targetPackageName))) {
Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
- targetPackageName, userId));
+ targetPackageName, userId));
}
}
+ }
+ private void updateAssets(final int userId, final String targetPackageName) {
+ updateAssets(userId, Collections.singletonList(targetPackageName));
+ }
+
+ private void updateAssets(final int userId, List<String> targetPackageNames) {
+ updateOverlayPaths(userId, targetPackageNames);
final IActivityManager am = ActivityManager.getService();
try {
am.scheduleApplicationInfoChanged(targetPackageNames, userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 5196c66..261bcc5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -68,15 +68,15 @@
mListener = listener;
}
- /*
- * Call this when switching to a new Android user. Will return a list of
- * target packages that must refresh their overlays. This list is the union
+ /**
+ * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
+ * Returns a list of target packages that must refresh their overlays. This list is the union
* of two sets: the set of targets with currently active overlays, and the
* set of targets that had, but no longer have, active overlays.
*/
- List<String> onSwitchUser(final int newUserId) {
+ ArrayList<String> updateOverlaysForUser(final int newUserId) {
if (DEBUG) {
- Slog.d(TAG, "onSwitchUser newUserId=" + newUserId);
+ Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
}
final Set<String> packagesToUpdateAssets = new ArraySet<>();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 2f83793..353b710 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -22,12 +22,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
+import android.os.UserHandle;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -266,32 +268,32 @@
return true;
}
- private static final String TAB1 = " ";
- private static final String TAB2 = TAB1 + TAB1;
- private static final String TAB3 = TAB2 + TAB1;
-
- void dump(@NonNull final PrintWriter pw) {
+ void dump(@NonNull final PrintWriter p) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(p, " ");
pw.println("Settings");
- pw.println(TAB1 + "Items");
+ pw.increaseIndent();
if (mItems.isEmpty()) {
- pw.println(TAB2 + "<none>");
+ pw.println("<none>");
return;
}
final int N = mItems.size();
for (int i = 0; i < N; i++) {
final SettingsItem item = mItems.get(i);
- final StringBuilder sb = new StringBuilder();
- sb.append(TAB2 + item.mPackageName + ":" + item.getUserId() + " {\n");
- sb.append(TAB3 + "mPackageName.......: " + item.mPackageName + "\n");
- sb.append(TAB3 + "mUserId............: " + item.getUserId() + "\n");
- sb.append(TAB3 + "mTargetPackageName.: " + item.getTargetPackageName() + "\n");
- sb.append(TAB3 + "mBaseCodePath......: " + item.getBaseCodePath() + "\n");
- sb.append(TAB3 + "mState.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
- sb.append(TAB3 + "mIsEnabled.........: " + item.isEnabled() + "\n");
- sb.append(TAB2 + "}");
- pw.println(sb.toString());
+ pw.println(item.mPackageName + ":" + item.getUserId() + " {");
+ pw.increaseIndent();
+
+ pw.print("mPackageName.......: "); pw.println(item.mPackageName);
+ pw.print("mUserId............: "); pw.println(item.getUserId());
+ pw.print("mTargetPackageName.: "); pw.println(item.getTargetPackageName());
+ pw.print("mBaseCodePath......: "); pw.println(item.getBaseCodePath());
+ pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
+ pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
+ pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+
+ pw.decreaseIndent();
+ pw.println("}");
}
}
@@ -527,12 +529,6 @@
.filter(item -> item.getTargetPackageName().equals(targetPackageName));
}
- private void assertNotNull(@Nullable final Object o) {
- if (o == null) {
- throw new AndroidRuntimeException("object must not be null");
- }
- }
-
static final class BadKeyException extends RuntimeException {
BadKeyException(@NonNull final String packageName, final int userId) {
super("Bad key mPackageName=" + packageName + " mUserId=" + userId);
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index aa780cc..562ab33 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.InstantAppResolveInfo;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -95,7 +96,7 @@
return mGetEphemeralResolveInfoCaller
.getEphemeralResolveInfoList(target, hashPrefix, token);
} catch (TimeoutException e) {
- throw new ConnectionException(ConnectionException.FAILURE_BIND);
+ throw new ConnectionException(ConnectionException.FAILURE_CALL);
} catch (RemoteException ignore) {
}
} finally {
@@ -140,7 +141,12 @@
if (mRemoteInstance != null) {
return mRemoteInstance;
}
- bindLocked(token);
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ bindLocked(token);
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
+ }
return mRemoteInstance;
}
}
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 85be4a2..34cc6e3 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -182,6 +182,7 @@
failureIntent = null;
}
final Intent installerIntent = buildEphemeralInstallerIntent(
+ Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE,
requestObj.origIntent,
failureIntent,
requestObj.callingPackage,
@@ -226,6 +227,7 @@
* Builds and returns an intent to launch the instant installer.
*/
public static Intent buildEphemeralInstallerIntent(
+ @NonNull String action,
@NonNull Intent origIntent,
@NonNull Intent failureIntent,
@NonNull String callingPackage,
@@ -239,7 +241,7 @@
boolean needsPhaseTwo) {
// Construct the intent that launches the instant installer
int flags = origIntent.getFlags();
- final Intent intent = new Intent();
+ final Intent intent = new Intent(action);
intent.setFlags(flags
| Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f79f6f4..29f9f7c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -546,12 +546,12 @@
try {
code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage,
userId, intents, startActivityOptions);
- if (code >= ActivityManager.START_SUCCESS) {
+ if (ActivityManager.isStartResultSuccessful(code)) {
return true; // Success
} else {
Log.e(TAG, "Couldn't start activity, code=" + code);
}
- return code >= ActivityManager.START_SUCCESS;
+ return false;
} catch (SecurityException e) {
if (DEBUG) {
Slog.d(TAG, "SecurityException while launching intent", e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 132ea2b..75e7a1e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1093,7 +1093,7 @@
PackageInfo packageInfo = null;
try {
packageInfo = AppGlobals.getPackageManager().getPackageInfo(
- basePackageName, 0, userId);
+ basePackageName, PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
} catch (RemoteException ignored) {
}
if (packageInfo == null || packageInfo.applicationInfo == null) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 8fcfc8f..4540d2d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -207,7 +207,8 @@
public boolean handleMessage(Message msg) {
// Cache package manager data without the lock held
final PackageInfo pkgInfo = mPm.getPackageInfo(
- params.appPackageName, PackageManager.GET_SIGNATURES /*flags*/, userId);
+ params.appPackageName, PackageManager.GET_SIGNATURES
+ | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
final ApplicationInfo appInfo = mPm.getApplicationInfo(
params.appPackageName, 0, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f97e20d..bf30d7a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2027,15 +2027,17 @@
EventLog.writeEvent(EventLogTags.UNKNOWN_SOURCES_ENABLED,
getUnknownSourcesSettings());
- // Force a gc to clear up things
- Runtime.getRuntime().gc();
-
// Remove the replaced package's older resources safely now
// We delete after a gc for applications on sdcard.
if (res.removedInfo != null && res.removedInfo.args != null) {
+ Runtime.getRuntime().gc();
synchronized (mInstallLock) {
res.removedInfo.args.doPostDeleteLI(true);
}
+ } else {
+ // Force a gc to clear up things. Ask for a background one, it's fine to go on
+ // and not block here.
+ VMRuntime.getRuntime().requestConcurrentGC();
}
// Notify DexManager that the package was installed for new users.
@@ -3186,6 +3188,17 @@
return null;
}
+ @Override
+ public @Nullable ComponentName getInstantAppResolverComponent() {
+ synchronized (mPackages) {
+ final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
+ if (instantAppResolver == null) {
+ return null;
+ }
+ return instantAppResolver.first;
+ }
+ }
+
private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
@@ -3470,28 +3483,49 @@
return cur;
}
+ /**
+ * Returns whether or not a full application can see an instant application.
+ * <p>
+ * Currently, there are three cases in which this can occur:
+ * <ol>
+ * <li>The calling application is a "special" process. The special
+ * processes are {@link Process#SYSTEM_UID}, {@link Process#SHELL_UID}
+ * and {@code 0}</li>
+ * <li>The calling application has the permission
+ * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}</li>
+ * <li>[TODO] The calling application is the default launcher on the
+ * system partition.</li>
+ * </ol>
+ */
+ private boolean canAccessInstantApps(int callingUid) {
+ final boolean isSpecialProcess =
+ callingUid == Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID
+ || callingUid == 0;
+ final boolean allowMatchInstant =
+ isSpecialProcess
+ || mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
+ return allowMatchInstant;
+ }
private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
if (ps == null) {
return null;
}
- final PackageParser.Package p = ps.pkg;
+ PackageParser.Package p = ps.pkg;
if (p == null) {
return null;
}
+ final int callingUid = Binder.getCallingUid();
// Filter out ephemeral app metadata:
// * The system/shell/root can see metadata for any app
// * An installed app can see metadata for 1) other installed apps
// and 2) ephemeral apps that have explicitly interacted with it
// * Ephemeral apps can only see their own data and exposed installed apps
// * Holding a signature permission allows seeing instant apps
- final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
- if (callingAppId != Process.SYSTEM_UID
- && callingAppId != Process.SHELL_UID
- && callingAppId != Process.ROOT_UID
- && checkUidPermission(Manifest.permission.ACCESS_INSTANT_APPS,
- Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) {
- final String instantAppPackageName = getInstantAppPackageName(Binder.getCallingUid());
+ if (!canAccessInstantApps(callingUid)) {
+ final String instantAppPackageName = getInstantAppPackageName(callingUid);
if (instantAppPackageName != null) {
// ephemeral apps can only get information on themselves or
// installed apps that are exposed.
@@ -3502,6 +3536,7 @@
} else {
if (ps.getInstantApp(userId)) {
// only get access to the ephemeral app if we've been granted access
+ final int callingAppId = UserHandle.getAppId(callingUid);
if (!mInstantAppRegistry.isInstantAccessGranted(
userId, callingAppId, ps.appId)) {
return null;
@@ -3600,15 +3635,15 @@
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
- // TODO: We will change version code to long, so in the new API it is long
- (int) versionedPackage.getVersionCode(), flags, userId);
+ versionedPackage.getVersionCode(), flags, userId);
}
private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ final int callingUid = Binder.getCallingUid();
flags = updateFlagsForPackage(flags, userId, packageName);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
@@ -3620,7 +3655,10 @@
if (matchFactoryOnly) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
+ if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
+ return null;
+ }
+ if (filterAppAccessLPr(ps, callingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -3634,15 +3672,22 @@
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
- if (filterSharedLibPackageLPr((PackageSetting) p.mExtras,
- Binder.getCallingUid(), userId, flags)) {
+ final PackageSetting ps = (PackageSetting) p.mExtras;
+ if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
+ return null;
+ }
+ if (ps != null && filterAppAccessLPr(ps, callingUid, userId)) {
return null;
}
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
+ if (ps == null) return null;
+ if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
+ return null;
+ }
+ if (filterAppAccessLPr(ps, callingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
@@ -3651,6 +3696,57 @@
return null;
}
+ /**
+ * Returns whether or not access to the application should be filtered.
+ * <p>
+ * Access may be limited based upon whether the calling or target applications
+ * are instant applications.
+ *
+ * @see #canAccessInstantApps(int)
+ */
+ private boolean filterAppAccessLPr(@NonNull PackageSetting ps, int callingUid,
+ @Nullable ComponentName component, boolean componentVisibleToInstantApp, int userId) {
+ // if we're in an isolated process, get the real calling UID
+ if (Process.isIsolated(callingUid)) {
+ callingUid = mIsolatedOwners.get(callingUid);
+ }
+ // if the target and caller are the same application, don't filter
+ if (isCallerSameApp(ps.name, callingUid)) {
+ return false;
+ }
+ final String instantAppPkgName = getInstantAppPackageName(callingUid);
+ final boolean callerIsInstantApp = instantAppPkgName != null;
+ if (callerIsInstantApp) {
+ // request for a specific component; if it hasn't been explicitly exposed, filter
+ if (component != null) {
+ return !componentVisibleToInstantApp;
+ }
+ // request for application; if no components have been explicitly exposed, filter
+ return !ps.pkg.visibleToInstantApps;
+ }
+ if (ps.getInstantApp(userId)) {
+ // caller can see all components of all instant applications, don't filter
+ if (canAccessInstantApps(callingUid)) {
+ return false;
+ }
+ // request for a specific instant application component, filter
+ if (component != null) {
+ return true;
+ }
+ // request for an instant application; if the caller hasn't been granted access, filter
+ return !mInstantAppRegistry.isInstantAccessGranted(
+ userId, UserHandle.getAppId(callingUid), ps.appId);
+ }
+ return false;
+ }
+
+ /**
+ * @see #filterAppAccessLPr(PackageSetting, int, ComponentName, boolean, int)
+ */
+ private boolean filterAppAccessLPr(@NonNull PackageSetting ps, int callingUid, int userId) {
+ return filterAppAccessLPr(ps, callingUid, null, false, userId);
+ }
+
private boolean filterSharedLibPackageLPr(@Nullable PackageSetting ps, int uid, int userId,
int flags) {
// Callers can access only the libs they depend on, otherwise they need to explicitly
@@ -3859,6 +3955,9 @@
if (filterSharedLibPackageLPr(ps, uid, userId, flags)) {
return null;
}
+ if (filterAppAccessLPr(ps, uid, userId)) {
+ return null;
+ }
if (ps.pkg == null) {
final PackageInfo pInfo = generatePackageInfo(ps, flags, userId);
if (pInfo != null) {
@@ -3900,6 +3999,9 @@
if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) {
return null;
}
+ if (filterAppAccessLPr(ps, Binder.getCallingUid(), userId)) {
+ return null;
+ }
// Note: isEnabledLP() does not apply here - always return info
ApplicationInfo ai = PackageParser.generateApplicationInfo(
p, flags, ps.readUserState(userId), userId);
@@ -4199,15 +4301,15 @@
*/
int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid) {
return updateFlagsForResolve(flags, userId, intent, callingUid,
- false /*includeInstantApps*/, false /*onlyExposedExplicitly*/);
+ false /*wantInstantApps*/, false /*onlyExposedExplicitly*/);
}
int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid,
- boolean includeInstantApps) {
+ boolean wantInstantApps) {
return updateFlagsForResolve(flags, userId, intent, callingUid,
- includeInstantApps, false /*onlyExposedExplicitly*/);
+ wantInstantApps, false /*onlyExposedExplicitly*/);
}
int updateFlagsForResolve(int flags, int userId, Intent intent, int callingUid,
- boolean includeInstantApps, boolean onlyExposedExplicitly) {
+ boolean wantInstantApps, boolean onlyExposedExplicitly) {
// Safe mode means we shouldn't match any third-party components
if (mSafeMode) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
@@ -4220,18 +4322,11 @@
flags |= PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY;
flags |= PackageManager.MATCH_INSTANT;
} else {
- // Otherwise, prevent leaking ephemeral components
- final boolean isSpecialProcess =
- callingUid == Process.SYSTEM_UID
- || callingUid == Process.SHELL_UID
- || callingUid == 0;
final boolean allowMatchInstant =
- (includeInstantApps
+ (wantInstantApps
&& Intent.ACTION_VIEW.equals(intent.getAction())
&& hasWebURI(intent))
- || isSpecialProcess
- || mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
+ || canAccessInstantApps(callingUid);
flags &= ~(PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY
| PackageManager.MATCH_EXPLICITLY_VISIBLE_ONLY);
if (!allowMatchInstant) {
@@ -4262,8 +4357,9 @@
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -4272,6 +4368,11 @@
if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
+ final boolean visibleToInstantApp =
+ (a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ return null;
+ }
return generateActivityInfo(a, flags, ps.readUserState(userId), userId);
}
if (mResolveComponentName.equals(component)) {
@@ -4324,7 +4425,8 @@
}
@Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(int flags, int userId) {
+ public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
+ int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
Preconditions.checkArgumentNonnegative(userId, "userId must be >= 0");
@@ -4335,8 +4437,9 @@
== PERMISSION_GRANTED
|| mContext.checkCallingOrSelfPermission(DELETE_PACKAGES)
== PERMISSION_GRANTED
- || mContext.checkCallingOrSelfPermission(REQUEST_INSTALL_PACKAGES)
- == PERMISSION_GRANTED
+ || canRequestPackageInstallsInternal(packageName,
+ PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId,
+ false /* throwIfPermNotDeclared*/)
|| mContext.checkCallingOrSelfPermission(REQUEST_DELETE_PACKAGES)
== PERMISSION_GRANTED;
@@ -4359,7 +4462,8 @@
final long identity = Binder.clearCallingIdentity();
try {
PackageInfo packageInfo = getPackageInfoVersioned(
- libInfo.getDeclaringPackage(), flags, userId);
+ libInfo.getDeclaringPackage(), flags
+ | PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
if (packageInfo == null) {
continue;
}
@@ -4433,8 +4537,9 @@
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
@@ -4443,6 +4548,11 @@
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
+ final boolean visibleToInstantApp =
+ (s.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ return null;
+ }
ServiceInfo si = PackageParser.generateServiceInfo(s, flags,
ps.readUserState(userId), userId);
if (si != null) {
@@ -4457,8 +4567,9 @@
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ final int callingUid = Binder.getCallingUid();
flags = updateFlagsForComponent(flags, userId, component);
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProviders.mProviders.get(component);
@@ -4467,6 +4578,11 @@
if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
+ final boolean visibleToInstantApp =
+ (p.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+ if (filterAppAccessLPr(ps, callingUid, component, visibleToInstantApp, userId)) {
+ return null;
+ }
ProviderInfo pi = PackageParser.generateProviderInfo(p, flags,
ps.readUserState(userId), userId);
if (pi != null) {
@@ -6479,18 +6595,22 @@
}
} else {
final PackageParser.Package pkg = mPackages.get(pkgName);
+ result = null;
if (pkg != null) {
- return applyPostResolutionFilter(filterIfNotSystemUser(
+ result = filterIfNotSystemUser(
mActivities.queryIntentForPackage(
intent, resolvedType, flags, pkg.activities, userId),
- userId), instantAppPkgName);
- } else {
+ userId);
+ }
+ if (result == null || result.size() == 0) {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
addEphemeral = !ephemeralDisabled
&& isInstantAppAllowed(
intent, null /*result*/, userId, true /*skipPackageCheck*/);
- result = new ArrayList<ResolveInfo>();
+ if (result == null) {
+ result = new ArrayList<>();
+ }
}
}
}
@@ -9311,6 +9431,9 @@
}
if (p != null) {
usesLibraryFiles.addAll(p.getAllCodePaths());
+ if (p.usesLibraryFiles != null) {
+ Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
+ }
}
}
@@ -17457,17 +17580,24 @@
}
}
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
- // Do not run PackageDexOptimizer through the local performDexOpt
- // method because `pkg` may not be in `mPackages` yet.
- //
- // Also, don't fail application installs if the dexopt step fails.
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
- null /* instructionSets */, false /* checkProfiles */,
- getCompilerFilterForReason(REASON_INSTALL),
- getOrCreateCompilerPackageStats(pkg),
- mDexManager.isUsedByOtherApps(pkg.packageName));
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ // dexopt can take some time to complete, so, for instant apps, we skip this
+ // step during installation. Instead, we'll take extra time the first time the
+ // instant app starts. It's preferred to do it this way to provide continuous
+ // progress to the user instead of mysteriously blocking somewhere in the
+ // middle of running an instant app.
+ if (!instantApp) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+ // Do not run PackageDexOptimizer through the local performDexOpt
+ // method because `pkg` may not be in `mPackages` yet.
+ //
+ // Also, don't fail application installs if the dexopt step fails.
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ null /* instructionSets */, false /* checkProfiles */,
+ getCompilerFilterForReason(REASON_INSTALL),
+ getOrCreateCompilerPackageStats(pkg),
+ mDexManager.isUsedByOtherApps(pkg.packageName));
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
// Notify BackgroundDexOptService that the package has been changed.
// If this is an update of a package which used to fail to compile,
@@ -17757,14 +17887,12 @@
Integer.MAX_VALUE, "versionCode must be >= -1");
final String packageName = versionedPackage.getPackageName();
- // TODO: We will change version code to long, so in the new API it is long
- final int versionCode = (int) versionedPackage.getVersionCode();
+ final int versionCode = versionedPackage.getVersionCode();
final String internalPackageName;
synchronized (mPackages) {
// Normalize package name to handle renamed packages and static libs
internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(),
- // TODO: We will change version code to long, so in the new API it is long
- (int) versionedPackage.getVersionCode());
+ versionedPackage.getVersionCode());
}
final int uid = Binder.getCallingUid();
@@ -17906,8 +18034,7 @@
libEntry.info.getVersion()) < 0) {
continue;
}
- // TODO: We will change version code to long, so in the new API it is long
- final int libVersionCode = (int) libEntry.info.getDeclaringPackage().getVersionCode();
+ final int libVersionCode = libEntry.info.getDeclaringPackage().getVersionCode();
if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (libVersionCode == versionCode) {
return libEntry.apk;
@@ -18060,22 +18187,30 @@
// Static shared libs can be declared by any package, so let us not
// allow removing a package if it provides a lib others depend on.
pkg = mPackages.get(packageName);
+
+ allUsers = sUserManager.getUserIds();
+
if (pkg != null && pkg.staticSharedLibName != null) {
SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(pkg.staticSharedLibName,
pkg.staticSharedLibVersion);
if (libEntry != null) {
- List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
- libEntry.info, 0, userId);
- if (!ArrayUtils.isEmpty(libClientPackages)) {
- Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
- + " hosting lib " + libEntry.info.getName() + " version "
- + libEntry.info.getVersion() + " used by " + libClientPackages);
- return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
+ for (int currUserId : allUsers) {
+ if (userId != UserHandle.USER_ALL && userId != currUserId) {
+ continue;
+ }
+ List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
+ libEntry.info, 0, currUserId);
+ if (!ArrayUtils.isEmpty(libClientPackages)) {
+ Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+ + " hosting lib " + libEntry.info.getName() + " version "
+ + libEntry.info.getVersion() + " used by " + libClientPackages
+ + " for user " + currUserId);
+ return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
+ }
}
}
}
- allUsers = sUserManager.getUserIds();
info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
}
@@ -23877,6 +24012,11 @@
return getUidTargetSdkVersionLockedLPr(uid);
}
}
+
+ @Override
+ public boolean canAccessInstantApps(int callingUid) {
+ return PackageManagerService.this.canAccessInstantApps(callingUid);
+ }
}
@Override
@@ -23983,6 +24123,12 @@
@Override
public boolean canRequestPackageInstalls(String packageName, int userId) {
+ return canRequestPackageInstallsInternal(packageName, 0, userId,
+ true /* throwIfPermNotDeclared*/);
+ }
+
+ private boolean canRequestPackageInstallsInternal(String packageName, int flags, int userId,
+ boolean throwIfPermNotDeclared) {
int callingUid = Binder.getCallingUid();
int uid = getPackageUid(packageName, 0, userId);
if (callingUid != uid && callingUid != Process.ROOT_UID
@@ -23990,18 +24136,23 @@
throw new SecurityException(
"Caller uid " + callingUid + " does not own package " + packageName);
}
- ApplicationInfo info = getApplicationInfo(packageName, 0, userId);
+ ApplicationInfo info = getApplicationInfo(packageName, flags, userId);
if (info == null) {
return false;
}
if (info.targetSdkVersion < Build.VERSION_CODES.O) {
- throw new UnsupportedOperationException(
- "Operation only supported on apps targeting Android O or higher");
+ return false;
}
String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
- throw new SecurityException("Need to declare " + appOpPermission + " to call this api");
+ if (throwIfPermNotDeclared) {
+ throw new SecurityException("Need to declare " + appOpPermission
+ + " to call this api");
+ } else {
+ Slog.e(TAG, "Need to declare " + appOpPermission + " to call this api");
+ return false;
+ }
}
if (sUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userId)) {
return false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3e920d4..184129e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -148,6 +148,8 @@
return runSetHomeActivity();
case "get-privapp-permissions":
return runGetPrivappPermissions();
+ case "get-instantapp-resolver":
+ return runGetInstantAppResolver();
case "has-feature":
return runHasFeature();
default:
@@ -890,7 +892,8 @@
userId = UserHandle.USER_SYSTEM;
flags |= PackageManager.DELETE_ALL_USERS;
} else {
- final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId);
+ final PackageInfo info = mInterface.getPackageInfo(packageName,
+ PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
if (info == null) {
pw.println("Failure [not installed for " + userId + "]");
return 1;
@@ -1272,6 +1275,21 @@
return 0;
}
+ private int runGetInstantAppResolver() {
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ final ComponentName instantAppsResolver = mInterface.getInstantAppResolverComponent();
+ if (instantAppsResolver == null) {
+ return 1;
+ }
+ pw.println(instantAppsResolver.flattenToString());
+ return 0;
+ } catch (Exception e) {
+ pw.println(e.toString());
+ return 1;
+ }
+ }
+
private int runHasFeature() {
final PrintWriter err = getErrPrintWriter();
final String featureName = getNextArg();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ac4b828..6d48a05 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Canvas;
import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
@@ -1356,7 +1357,7 @@
if (icon == null) {
return; // has no icon
}
-
+ int maxIconDimension = mMaxIconDimension;
Bitmap bitmap;
try {
switch (icon.getType()) {
@@ -1368,8 +1369,11 @@
return;
}
case Icon.TYPE_BITMAP:
+ bitmap = icon.getBitmap(); // Don't recycle in this case.
+ break;
case Icon.TYPE_ADAPTIVE_BITMAP: {
bitmap = icon.getBitmap(); // Don't recycle in this case.
+ maxIconDimension *= (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
break;
}
default:
@@ -1378,7 +1382,7 @@
throw ShortcutInfo.getInvalidIconException();
}
mShortcutBitmapSaver.saveBitmapLocked(shortcut,
- mMaxIconDimension, mIconPersistFormat, mIconPersistQuality);
+ maxIconDimension, mIconPersistFormat, mIconPersistQuality);
} finally {
// Once saved, we won't use the original icon information, so null it out.
shortcut.clearIcon();
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 30c4009..b115422 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3684,6 +3684,11 @@
}
@Override
+ public int[] getUserIds() {
+ return UserManagerService.this.getUserIds();
+ }
+
+ @Override
public boolean isUserUnlockingOrUnlocked(int userId) {
synchronized (mUserStates) {
int state = mUserStates.get(userId, -1);
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index a71bc4c..14fabc5 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -228,6 +228,7 @@
R.string.global_actions_airplane_mode_on_status,
R.string.global_actions_airplane_mode_off_status) {
+ @Override
void onToggle(boolean on) {
if (mHasTelephony && Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
@@ -254,10 +255,12 @@
}
}
+ @Override
public boolean showDuringKeyguard() {
return true;
}
+ @Override
public boolean showBeforeProvisioning() {
return false;
}
@@ -457,6 +460,7 @@
return false;
}
+ @Override
public boolean showDuringKeyguard() {
return true;
}
@@ -616,6 +620,7 @@
com.android.internal.R.drawable.ic_menu_cc, icon,
(user.name != null ? user.name : "Primary")
+ (isCurrentUser ? " \u2714" : "")) {
+ @Override
public void onPress() {
try {
ActivityManager.getService().switchUser(user.id);
@@ -624,10 +629,12 @@
}
}
+ @Override
public boolean showDuringKeyguard() {
return true;
}
+ @Override
public boolean showBeforeProvisioning() {
return false;
}
@@ -659,6 +666,7 @@
}
/** {@inheritDoc} */
+ @Override
public void onDismiss(DialogInterface dialog) {
if (mOnDismiss != null) {
mOnDismiss.run();
@@ -674,6 +682,7 @@
}
/** {@inheritDoc} */
+ @Override
public void onClick(DialogInterface dialog, int which) {
if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
dialog.dismiss();
@@ -689,6 +698,7 @@
*/
private class MyAdapter extends BaseAdapter {
+ @Override
public int getCount() {
int count = 0;
@@ -716,6 +726,7 @@
return false;
}
+ @Override
public Action getItem(int position) {
int filteredPos = 0;
@@ -740,11 +751,12 @@
+ ", provisioned=" + mDeviceProvisioned);
}
-
+ @Override
public long getItemId(int position) {
return position;
}
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
@@ -817,6 +829,7 @@
mIcon = icon;
}
+ @Override
public boolean isEnabled() {
return true;
}
@@ -825,8 +838,10 @@
return null;
}
+ @Override
abstract public void onPress();
+ @Override
public CharSequence getLabelForAccessibility(Context context) {
if (mMessage != null) {
return mMessage;
@@ -835,6 +850,7 @@
}
}
+ @Override
public View create(
Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_item, parent, false);
@@ -929,6 +945,7 @@
return context.getString(mMessageResId);
}
+ @Override
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
willCreate();
@@ -963,6 +980,7 @@
return v;
}
+ @Override
public final void onPress() {
if (mState.inTransition()) {
Log.w(TAG, "shouldn't be able to toggle when in transition");
@@ -974,6 +992,7 @@
changeStateFromPress(nowOn);
}
+ @Override
public boolean isEnabled() {
return !mState.inTransition();
}
@@ -1004,6 +1023,7 @@
R.string.global_action_silent_mode_off_status);
}
+ @Override
void onToggle(boolean on) {
if (on) {
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
@@ -1012,10 +1032,12 @@
}
}
+ @Override
public boolean showDuringKeyguard() {
return true;
}
+ @Override
public boolean showBeforeProvisioning() {
return false;
}
@@ -1050,6 +1072,7 @@
return null;
}
+ @Override
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
@@ -1065,17 +1088,21 @@
return v;
}
+ @Override
public void onPress() {
}
+ @Override
public boolean showDuringKeyguard() {
return true;
}
+ @Override
public boolean showBeforeProvisioning() {
return false;
}
+ @Override
public boolean isEnabled() {
return true;
}
@@ -1083,6 +1110,7 @@
void willCreate() {
}
+ @Override
public void onClick(View v) {
if (!(v.getTag() instanceof Integer)) return;
@@ -1093,6 +1121,7 @@
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
@@ -1146,6 +1175,7 @@
private static final int DIALOG_DISMISS_DELAY = 300; // ms
private Handler mHandler = new Handler() {
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_DISMISS:
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6f5c070c..d939345 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6667,6 +6667,11 @@
reportScreenStateToVrManager(true);
}
+ @Override
+ public void screenTurningOff(ScreenOffListener screenOffListener) {
+ mWindowManagerFuncs.screenTurningOff(screenOffListener);
+ }
+
private void reportScreenStateToVrManager(boolean isScreenOn) {
if (mVrManagerInternal == null) {
return;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a8d19e9..cf5bfc9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1397,13 +1397,16 @@
try {
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
- Slog.i(TAG, "Waking up from sleep (uid " + reasonUid +")...");
+ Slog.i(TAG, "Waking up from sleep (uid=" + reasonUid + " reason=" + reason
+ + ")...");
break;
case WAKEFULNESS_DREAMING:
- Slog.i(TAG, "Waking up from dream (uid " + reasonUid +")...");
+ Slog.i(TAG, "Waking up from dream (uid=" + reasonUid + " reason=" + reason
+ + ")...");
break;
case WAKEFULNESS_DOZING:
- Slog.i(TAG, "Waking up from dozing (uid " + reasonUid +")...");
+ Slog.i(TAG, "Waking up from dozing (uid=" + reasonUid + " reason=" + reason
+ + ")...");
break;
}
diff --git a/services/core/java/com/android/server/radio/RadioService.java b/services/core/java/com/android/server/radio/RadioService.java
index 4a2dd03..34bbffd 100644
--- a/services/core/java/com/android/server/radio/RadioService.java
+++ b/services/core/java/com/android/server/radio/RadioService.java
@@ -36,6 +36,8 @@
*/
private final long mNativeContext = nativeInit();
+ private final Object mLock = new Object();
+
public RadioService(Context context) {
super(context);
}
@@ -61,11 +63,13 @@
@Override
public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig,
boolean withAudio, ITunerCallback callback) {
- // TODO(b/36863239): add death monitoring for binder
if (callback == null) {
throw new IllegalArgumentException("Callback must not be empty");
}
- return nativeOpenTuner(mNativeContext, moduleId, bandConfig, withAudio, callback);
+ synchronized (mLock) {
+ // TODO(b/36863239): add death monitoring for binder
+ return nativeOpenTuner(mNativeContext, moduleId, bandConfig, withAudio, callback);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/radio/Tuner.java b/services/core/java/com/android/server/radio/Tuner.java
index 5d87aa5..9915c34 100644
--- a/services/core/java/com/android/server/radio/Tuner.java
+++ b/services/core/java/com/android/server/radio/Tuner.java
@@ -22,6 +22,8 @@
import android.hardware.radio.RadioManager;
import android.util.Slog;
+import java.util.List;
+
class Tuner extends ITuner.Stub {
// TODO(b/36863239): rename to RadioService.Tuner when native service goes away
private static final String TAG = "RadioServiceJava.Tuner";
@@ -31,15 +33,18 @@
*/
private final long mNativeContext;
+ @NonNull private final TunerCallback mTunerCallback;
private final Object mLock = new Object();
+ private boolean mIsClosed = false;
private boolean mIsMuted = false;
private int mRegion; // TODO(b/36863239): find better solution to manage regions
private final boolean mWithAudio;
Tuner(@NonNull ITunerCallback clientCallback, int halRev, int region, boolean withAudio) {
+ mTunerCallback = new TunerCallback(this, clientCallback, halRev);
mRegion = region;
mWithAudio = withAudio;
- mNativeContext = nativeInit(clientCallback, halRev);
+ mNativeContext = nativeInit(halRev);
}
@Override
@@ -48,7 +53,7 @@
super.finalize();
}
- private native long nativeInit(@NonNull ITunerCallback clientCallback, int halRev);
+ private native long nativeInit(int halRev);
private native void nativeFinalize(long nativeContext);
private native void nativeClose(long nativeContext);
@@ -62,11 +67,28 @@
private native void nativeCancel(long nativeContext);
private native RadioManager.ProgramInfo nativeGetProgramInformation(long nativeContext);
+ private native boolean nativeStartBackgroundScan(long nativeContext);
+ private native List<RadioManager.ProgramInfo> nativeGetProgramList(long nativeContext,
+ String filter);
+
+ private native boolean nativeIsAnalogForced(long nativeContext);
+ private native void nativeSetAnalogForced(long nativeContext, boolean isForced);
+
+ private native boolean nativeIsAntennaConnected(long nativeContext);
@Override
public void close() {
synchronized (mLock) {
+ if (mIsClosed) return;
+ mTunerCallback.detach();
nativeClose(mNativeContext);
+ mIsClosed = true;
+ }
+ }
+
+ private void checkNotClosedLocked() {
+ if (mIsClosed) {
+ throw new IllegalStateException("Tuner is closed, no further operations are allowed");
}
}
@@ -76,6 +98,7 @@
throw new IllegalArgumentException("The argument must not be a null pointer");
}
synchronized (mLock) {
+ checkNotClosedLocked();
nativeSetConfiguration(mNativeContext, config);
mRegion = config.getRegion();
}
@@ -84,6 +107,7 @@
@Override
public RadioManager.BandConfig getConfiguration() {
synchronized (mLock) {
+ checkNotClosedLocked();
return nativeGetConfiguration(mNativeContext, mRegion);
}
}
@@ -94,6 +118,7 @@
throw new IllegalStateException("Can't operate on mute - no audio requested");
}
synchronized (mLock) {
+ checkNotClosedLocked();
if (mIsMuted == mute) return;
mIsMuted = mute;
@@ -109,6 +134,7 @@
return true;
}
synchronized (mLock) {
+ checkNotClosedLocked();
return mIsMuted;
}
}
@@ -116,6 +142,7 @@
@Override
public void step(boolean directionDown, boolean skipSubChannel) {
synchronized (mLock) {
+ checkNotClosedLocked();
nativeStep(mNativeContext, directionDown, skipSubChannel);
}
}
@@ -123,6 +150,7 @@
@Override
public void scan(boolean directionDown, boolean skipSubChannel) {
synchronized (mLock) {
+ checkNotClosedLocked();
nativeScan(mNativeContext, directionDown, skipSubChannel);
}
}
@@ -130,6 +158,7 @@
@Override
public void tune(int channel, int subChannel) {
synchronized (mLock) {
+ checkNotClosedLocked();
nativeTune(mNativeContext, channel, subChannel);
}
}
@@ -137,6 +166,7 @@
@Override
public void cancel() {
synchronized (mLock) {
+ checkNotClosedLocked();
nativeCancel(mNativeContext);
}
}
@@ -144,7 +174,52 @@
@Override
public RadioManager.ProgramInfo getProgramInformation() {
synchronized (mLock) {
+ checkNotClosedLocked();
return nativeGetProgramInformation(mNativeContext);
}
}
+
+ @Override
+ public boolean startBackgroundScan() {
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ return nativeStartBackgroundScan(mNativeContext);
+ }
+ }
+
+ @Override
+ public List<RadioManager.ProgramInfo> getProgramList(String filter) {
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ List<RadioManager.ProgramInfo> list = nativeGetProgramList(mNativeContext, filter);
+ if (list == null) {
+ throw new IllegalStateException("Program list is not ready");
+ }
+ return list;
+ }
+ }
+
+ @Override
+ public boolean isAnalogForced() {
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ return nativeIsAnalogForced(mNativeContext);
+ }
+ }
+
+ @Override
+ public void setAnalogForced(boolean isForced) {
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ nativeSetAnalogForced(mNativeContext, isForced);
+ }
+ }
+
+ @Override
+ public boolean isAntennaConnected() {
+ synchronized (mLock) {
+ checkNotClosedLocked();
+ return nativeIsAntennaConnected(mNativeContext);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/radio/TunerCallback.java b/services/core/java/com/android/server/radio/TunerCallback.java
new file mode 100644
index 0000000..fcc874b
--- /dev/null
+++ b/services/core/java/com/android/server/radio/TunerCallback.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.radio;
+
+import android.annotation.NonNull;
+import android.hardware.radio.ITuner;
+import android.hardware.radio.ITunerCallback;
+import android.hardware.radio.RadioManager;
+import android.hardware.radio.RadioTuner;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+class TunerCallback implements ITunerCallback {
+ // TODO(b/36863239): rename to RadioService.TunerCallback when native service goes away
+ private static final String TAG = "RadioServiceJava.TunerCallback";
+
+ /**
+ * This field is used by native code, do not access or modify.
+ */
+ private final long mNativeContext;
+
+ @NonNull private final Tuner mTuner;
+ @NonNull private final ITunerCallback mClientCallback;
+
+ TunerCallback(@NonNull Tuner tuner, @NonNull ITunerCallback clientCallback, int halRev) {
+ mTuner = tuner;
+ mClientCallback = clientCallback;
+ mNativeContext = nativeInit(tuner, halRev);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ nativeFinalize(mNativeContext);
+ super.finalize();
+ }
+
+ private native long nativeInit(@NonNull Tuner tuner, int halRev);
+ private native void nativeFinalize(long nativeContext);
+ private native void nativeDetach(long nativeContext);
+
+ public void detach() {
+ nativeDetach(mNativeContext);
+ }
+
+ // called from native side
+ private void handleHwFailure() {
+ onError(RadioTuner.ERROR_HARDWARE_FAILURE);
+ mTuner.close();
+ }
+
+ @Override
+ public void onError(int status) {
+ try {
+ mClientCallback.onError(status);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "client died", e);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(RadioManager.BandConfig config) {
+ try {
+ mClientCallback.onConfigurationChanged(config);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "client died", e);
+ }
+ }
+
+ @Override
+ public void onProgramInfoChanged(RadioManager.ProgramInfo info) {
+ try {
+ mClientCallback.onProgramInfoChanged(info);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "client died", e);
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ throw new RuntimeException("Not a binder");
+ }
+}
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index 82dd9ac..7a35bf7 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -177,7 +177,7 @@
UserInfo info = users.get(i);
List<UsageStats> stats =
mUsageStats.queryUsageStatsForUser(info.id, UsageStatsManager.INTERVAL_BEST,
- oneYearAgo, timeNow);
+ oneYearAgo, timeNow, /*obfuscateInstantApps=*/ false);
if (stats == null) {
continue;
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 5bd485c..6801230 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -830,6 +830,10 @@
// coalesce refresh messages.
mHandler.removeMessages(MSG_KEYGUARD_SHOWING_CHANGED);
mHandler.sendEmptyMessage(MSG_KEYGUARD_SHOWING_CHANGED);
+
+ // Make sure handler processes the message before returning, such that isDeviceLocked
+ // after this call will retrieve the correct value.
+ mHandler.runWithScissors(() -> {}, 0);
}
@Override
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index fb7ccc7..4044fdb 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -368,7 +368,7 @@
// There is an active service, update it if needed
updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
- mCurrentVrService.getUserId(), null);
+ mCurrentVrService.getUserId(), mCurrentVrModeComponent);
}
}
@@ -675,7 +675,7 @@
* @param enabled new state for VR mode.
* @param component new component to be bound as a VR listener.
* @param userId user owning the component to be bound.
- * @param calling the component currently using VR mode, or null to leave unchanged.
+ * @param calling the component currently using VR mode.
*
* @return {@code true} if the component/user combination specified is valid.
*/
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index 37479c8..203bbf6 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -68,7 +68,7 @@
// The WebView package currently in use (or the one we are preparing).
private PackageInfo mCurrentWebViewPackage = null;
- private Object mLock = new Object();
+ private final Object mLock = new Object();
WebViewUpdater(Context context, SystemInterface systemInterface) {
mContext = context;
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 7ed3eac..50b1520 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -16,15 +16,14 @@
package com.android.server.wm;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;
+import static com.android.internal.notification.SystemNotificationChannels.ALERT_WINDOW;
import android.app.Notification;
-import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
@@ -41,7 +40,7 @@
/** Displays an ongoing notification for a process displaying an alert window */
class AlertWindowNotification {
- private static final String CHANNEL_PREFIX = "com.android.server.wm.AlertWindowNotification - ";
+ private static final String TAG_PREFIX = "com.android.server.wm.AlertWindowNotification: ";
private static final int NOTIFICATION_ID = 0;
private static int sNextRequestCode = 0;
@@ -58,7 +57,7 @@
mPackageName = packageName;
mNotificationManager =
(NotificationManager) mService.mContext.getSystemService(NOTIFICATION_SERVICE);
- mNotificationTag = CHANNEL_PREFIX + mPackageName;
+ mNotificationTag = TAG_PREFIX + mPackageName;
mRequestCode = sNextRequestCode++;
mIconUtilities = new IconUtilities(mService.mContext);
}
@@ -100,11 +99,9 @@
final String appName = (aInfo != null)
? pm.getApplicationLabel(aInfo).toString() : mPackageName;
- createNotificationChannelIfNeeded(context, appName);
-
final String message = context.getString(R.string.alert_windows_notification_message,
appName);
- final Notification.Builder builder = new Notification.Builder(context, mNotificationTag)
+ final Notification.Builder builder = new Notification.Builder(context, ALERT_WINDOW)
.setOngoing(true)
.setContentTitle(
context.getString(R.string.alert_windows_notification_title, appName))
@@ -134,20 +131,6 @@
return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT);
}
- private void createNotificationChannelIfNeeded(Context context, String appName) {
- if (mNotificationManager.getNotificationChannel(mNotificationTag) != null) {
- return;
- }
- final String nameChannel =
- context.getString(R.string.alert_windows_notification_channel_name, appName);
- final NotificationChannel channel =
- new NotificationChannel(mNotificationTag, nameChannel, IMPORTANCE_MIN);
- channel.enableLights(false);
- channel.enableVibration(false);
- mNotificationManager.createNotificationChannel(channel);
- }
-
-
private ApplicationInfo getApplicationInfo(PackageManager pm, String packageName) {
try {
return pm.getApplicationInfo(packageName, 0);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 16edd35..65e3ec0 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -411,7 +411,9 @@
}
if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
- + ": reportedVisible=" + mAppToken.reportedVisible);
+ + ": reportedVisible=" + mAppToken.reportedVisible
+ + " okToDisplay=" + mService.okToDisplay()
+ + " startingDisplayed=" + mAppToken.startingDisplayed);
transformation.clear();
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index b5e194b..c982f08 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -19,6 +19,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -98,18 +99,27 @@
private final Runnable mRemoveStartingWindow = () -> {
StartingSurface surface = null;
synchronized (mWindowMap) {
+ if (mContainer == null) {
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
+ + " remove starting window");
+ return;
+ }
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
+ ": startingWindow=" + mContainer.startingWindow
+ " startingView=" + mContainer.startingSurface);
- if (mContainer == null) {
- return;
- }
if (mContainer.startingWindow != null) {
surface = mContainer.startingSurface;
mContainer.startingData = null;
mContainer.startingSurface = null;
mContainer.startingWindow = null;
mContainer.startingDisplayed = false;
+ if (surface == null && DEBUG_STARTING_WINDOW) {
+ Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
+ + "remove");
+ }
+ } else if (DEBUG_STARTING_WINDOW) {
+ Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
+ + mContainer);
}
}
if (surface != null) {
@@ -127,6 +137,8 @@
synchronized (mWindowMap) {
if (mContainer == null) {
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
+ + " add starting window");
return;
}
startingData = mContainer.startingData;
@@ -135,6 +147,8 @@
if (startingData == null) {
// Animation has been canceled... do nothing.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
+ + " mAddStartingWindow: " + mContainer);
return;
}
@@ -174,6 +188,8 @@
if (abort) {
surface.remove();
}
+ } else if (DEBUG_STARTING_WINDOW) {
+ Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
}
};
@@ -447,10 +463,12 @@
public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot) {
+ boolean allowTaskSnapshot, boolean activityCreated) {
synchronized(mWindowMap) {
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
- + " pkg=" + pkg + " transferFrom=" + transferFrom);
+ + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
+ + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
+ + " allowTaskSnapshot=" + allowTaskSnapshot);
if (mContainer == null) {
Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
@@ -475,7 +493,7 @@
}
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
- allowTaskSnapshot);
+ allowTaskSnapshot, activityCreated);
if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
return createSnapshot();
@@ -536,7 +554,7 @@
return false;
}
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
mContainer.getMergedOverrideConfiguration());
@@ -546,8 +564,9 @@
}
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
- boolean allowTaskSnapshot) {
- if (newTask || !processRunning) {
+ boolean allowTaskSnapshot, boolean activityCreated) {
+ if (newTask || !processRunning
+ || (taskSwitch && !activityCreated)) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
@@ -573,6 +592,7 @@
return false;
}
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
mContainer.startingData = new SnapshotStartingData(mService, snapshot);
scheduleAddStartingWindow();
return true;
@@ -582,6 +602,8 @@
synchronized (mWindowMap) {
if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
// Already scheduled.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Trying to remove starting window but "
+ + "already scheduled");
return;
}
@@ -596,8 +618,7 @@
return;
}
- if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
- + ": Schedule remove starting " + mContainer
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
+ " startingWindow=" + mContainer.startingWindow);
mHandler.post(mRemoveStartingWindow);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 96ea5e5..17db253 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -38,6 +38,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -53,7 +54,6 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
-import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
import android.os.SystemClock;
@@ -155,6 +155,9 @@
StartingSurface startingSurface;
boolean startingDisplayed;
boolean startingMoved;
+ // True if the hidden state of this token was forced to false due to a transferred starting
+ // window.
+ private boolean mHiddenSetFromTransferredStartingWindow;
boolean firstWindowDrawn;
private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
new WindowState.UpdateReportedVisibilityResults();
@@ -185,7 +188,7 @@
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
- private boolean mDisbalePreviewScreenshots;
+ private boolean mDisablePreviewScreenshots;
Task mLastParent;
@@ -560,6 +563,9 @@
// with it will be removed as soon as their animations are complete
mAppAnimator.clearAnimation();
mAppAnimator.animating = false;
+ if (stack != null) {
+ stack.mExitingAppTokens.remove(this);
+ }
removeIfPossible();
}
@@ -787,14 +793,22 @@
if (getController() != null) {
getController().removeStartingWindow();
}
- } else if (mChildren.size() == 0 && startingData != null) {
+ } else if (mChildren.size() == 0) {
// If this is the last window and we had requested a starting transition window,
// well there is no point now.
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
startingData = null;
+ if (mHiddenSetFromTransferredStartingWindow) {
+ // We set the hidden state to false for the token from a transferred starting window.
+ // We now reset it back to true since the starting window was the last window in the
+ // token.
+ hidden = true;
+ }
} else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
// If this is the last window except for a starting transition window,
// we need to get rid of the starting transition.
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
+ + win);
if (getController() != null) {
getController().removeStartingWindow();
}
@@ -1168,6 +1182,7 @@
"Removing starting " + tStartingWindow + " from " + fromToken);
fromToken.removeChild(tStartingWindow);
fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
+ fromToken.mHiddenSetFromTransferredStartingWindow = false;
addWindow(tStartingWindow);
// Propagate other interesting state between the tokens. If the old token is displayed,
@@ -1183,6 +1198,7 @@
if (!fromToken.hidden) {
hidden = false;
hiddenRequested = false;
+ mHiddenSetFromTransferredStartingWindow = true;
}
setClientHidden(fromToken.mClientHidden);
fromToken.mAppAnimator.transferCurrentAnimation(
@@ -1359,7 +1375,7 @@
* windows in this app token where not considered drawn as of the last pass.
*/
boolean updateDrawnWindowStates(WindowState w) {
- if (DEBUG_STARTING_WINDOW && w == startingWindow) {
+ if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
+ " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
}
@@ -1541,7 +1557,7 @@
* See {@link Activity#setDisablePreviewScreenshots}.
*/
void setDisablePreviewScreenshots(boolean disable) {
- mDisbalePreviewScreenshots = disable;
+ mDisablePreviewScreenshots = disable;
}
/**
@@ -1553,7 +1569,7 @@
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
- return mDisbalePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
+ return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
true /* topToBottom */);
}
@@ -1601,11 +1617,13 @@
pw.print(" mIsExiting="); pw.println(mIsExiting);
}
if (startingWindow != null || startingSurface != null
- || startingDisplayed || startingMoved) {
+ || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
pw.print(" startingSurface="); pw.print(startingSurface);
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
- pw.print(" startingMoved="); pw.println(startingMoved);
+ pw.print(" startingMoved="); pw.print(startingMoved);
+ pw.println(" mHiddenSetFromTransferredStartingWindow="
+ + mHiddenSetFromTransferredStartingWindow);
}
if (!mFrozenBounds.isEmpty()) {
pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 257f285..221e795 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -520,9 +520,16 @@
}
w.mLayoutNeeded = false;
w.prelayout();
+ final boolean firstLayout = !w.isLaidOut();
mService.mPolicy.layoutWindowLw(w, null);
w.mLayoutSeq = mService.mLayoutSeq;
+ // If this is the first layout, we need to initialize the last inset values as
+ // otherwise we'd immediately cause an unnecessary resize.
+ if (firstLayout) {
+ w.updateLastInsetValues();
+ }
+
// Window frames may have changed. Update dim layer with the new bounds.
final Task task = w.getTask();
if (task != null) {
@@ -1892,6 +1899,11 @@
return true;
}
+ /** @return 'true' if removal of this display content is deferred due to active animation. */
+ boolean isRemovalDeferred() {
+ return mDeferredRemoval;
+ }
+
boolean animateForIme(float interpolatedValue, float animationTarget,
float dividerAnimationTarget) {
boolean updated = false;
@@ -2891,6 +2903,11 @@
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
synchronized(mService.mWindowMap) {
+ if (!mService.mPolicy.isScreenOn()) {
+ if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Attempted to take screenshot while display"
+ + " was off.");
+ return null;
+ }
// Figure out the part of the screen that is actually the app.
mScreenshotApplicationState.appWin = null;
forAllWindows(w -> {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index be3558b..233e75b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -181,7 +181,12 @@
final int size = mChildren.size();
for (int i = 0; i < size; ++i) {
- displaysInFocusOrder.put(i, mChildren.get(i).getDisplayId());
+ final DisplayContent displayContent = mChildren.get(i);
+ if (displayContent.isRemovalDeferred()) {
+ // Don't report displays that are going to be removed soon.
+ continue;
+ }
+ displaysInFocusOrder.put(i, displayContent.getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 6a7123c..091e1cb 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -159,6 +159,7 @@
}
}
+ @Override
public void binderDied() {
// Note: it is safe to call in to the input method manager
// here because we are not holding our lock.
@@ -205,6 +206,7 @@
outContentInsets, outStableInsets, null /* outOutsets */, null);
}
+ @Override
public void remove(IWindow window) {
mService.removeWindow(this, window);
}
@@ -214,6 +216,7 @@
mService.setWillReplaceWindows(appToken, childrenOnly);
}
+ @Override
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags,
int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
@@ -230,42 +233,50 @@
return res;
}
+ @Override
public boolean outOfMemory(IWindow window) {
return mService.outOfMemoryWindow(this, window);
}
+ @Override
public void setTransparentRegion(IWindow window, Region region) {
mService.setTransparentRegionWindow(this, window, region);
}
+ @Override
public void setInsets(IWindow window, int touchableInsets,
Rect contentInsets, Rect visibleInsets, Region touchableArea) {
mService.setInsetsWindow(this, window, touchableInsets, contentInsets,
visibleInsets, touchableArea);
}
+ @Override
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
mService.getWindowDisplayFrame(this, window, outDisplayFrame);
}
+ @Override
public void finishDrawing(IWindow window) {
if (WindowManagerService.localLOGV) Slog.v(
TAG_WM, "IWindow finishDrawing called for " + window);
mService.finishDrawingWindow(this, window);
}
+ @Override
public void setInTouchMode(boolean mode) {
synchronized(mService.mWindowMap) {
mService.mInTouchMode = mode;
}
}
+ @Override
public boolean getInTouchMode() {
synchronized(mService.mWindowMap) {
return mService.mInTouchMode;
}
}
+ @Override
public boolean performHapticFeedback(IWindow window, int effectId,
boolean always) {
synchronized(mService.mWindowMap) {
@@ -281,12 +292,14 @@
}
/* Drag/drop */
+ @Override
public IBinder prepareDrag(IWindow window, int flags,
int width, int height, Surface outSurface) {
return mService.prepareDragSurface(window, mSurfaceSession, flags,
width, height, outSurface);
}
+ @Override
public boolean performDrag(IWindow window, IBinder dragToken,
int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data) {
@@ -370,6 +383,7 @@
return true; // success!
}
+ @Override
public boolean startMovingTask(IWindow window, float startX, float startY) {
if (DEBUG_TASK_POSITIONING) Slog.d(
TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
@@ -382,6 +396,7 @@
}
}
+ @Override
public void reportDropResult(IWindow window, boolean consumed) {
IBinder token = window.asBinder();
if (DEBUG_DRAG) {
@@ -422,6 +437,7 @@
}
}
+ @Override
public void cancelDragAndDrop(IBinder dragToken) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "cancelDragAndDrop");
@@ -450,18 +466,21 @@
}
}
+ @Override
public void dragRecipientEntered(IWindow window) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "Drag into new candidate view @ " + window.asBinder());
}
}
+ @Override
public void dragRecipientExited(IWindow window) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "Drag from old candidate view @ " + window.asBinder());
}
}
+ @Override
public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
synchronized(mService.mWindowMap) {
long ident = Binder.clearCallingIdentity();
@@ -475,12 +494,14 @@
}
}
+ @Override
public void wallpaperOffsetsComplete(IBinder window) {
synchronized (mService.mWindowMap) {
mService.mRoot.mWallpaperController.wallpaperOffsetsComplete(window);
}
}
+ @Override
public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
synchronized(mService.mWindowMap) {
long ident = Binder.clearCallingIdentity();
@@ -493,6 +514,7 @@
}
}
+ @Override
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized(mService.mWindowMap) {
@@ -507,12 +529,14 @@
}
}
+ @Override
public void wallpaperCommandComplete(IBinder window, Bundle result) {
synchronized (mService.mWindowMap) {
mService.mRoot.mWallpaperController.wallpaperCommandComplete(window);
}
}
+ @Override
public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
synchronized(mService.mWindowMap) {
final long identity = Binder.clearCallingIdentity();
@@ -524,6 +548,7 @@
}
}
+ @Override
public IWindowId getWindowId(IBinder window) {
return mService.getWindowId(window);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0a999e6..818df01 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.util.function.Consumer;
class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
@@ -92,6 +93,12 @@
private TaskDescription mTaskDescription;
+ // If set to true, the task will report that it is not in the floating
+ // state regardless of it's stack affilation. As the floating state drives
+ // production of content insets this can be used to preserve them across
+ // stack moves and we in fact do so when moving from full screen to pinned.
+ private boolean mPreserveNonFloatingState = false;
+
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
boolean homeTask, TaskDescription taskDescription,
@@ -194,6 +201,16 @@
EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
final DisplayContent prevDisplayContent = getDisplayContent();
+ // If we are moving from the fullscreen stack to the pinned stack
+ // then we want to preserve our insets so that there will not
+ // be a jump in the area covered by system decorations. We rely
+ // on the pinned animation to later unset this value.
+ if (stack.mStackId == PINNED_STACK_ID) {
+ mPreserveNonFloatingState = true;
+ } else {
+ mPreserveNonFloatingState = false;
+ }
+
getParent().removeChild(this);
stack.addTask(this, position, showForAllUsers(), moveParents);
@@ -593,7 +610,8 @@
* we will have a jump at the end.
*/
boolean isFloating() {
- return StackId.tasksAreFloating(mStack.mStackId) && !mStack.isAnimatingBoundsToFullscreen();
+ return StackId.tasksAreFloating(mStack.mStackId)
+ && !mStack.isAnimatingBoundsToFullscreen() && !mPreserveNonFloatingState;
}
WindowState getTopVisibleAppMainWindow() {
@@ -667,6 +685,11 @@
}
@Override
+ void forAllTasks(Consumer<Task> callback) {
+ callback.accept(this);
+ }
+
+ @Override
public String toString() {
return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
}
@@ -675,6 +698,10 @@
return toShortString();
}
+ void clearPreserveNonFloatingState() {
+ mPreserveNonFloatingState = false;
+ }
+
@Override
public String toShortString() {
return "Task=" + mTaskId;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 1bbe1d0..24cb464 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -30,8 +30,10 @@
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Environment;
+import android.os.Handler;
import android.util.ArraySet;
import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy.ScreenOffListener;
import android.view.WindowManagerPolicy.StartingSurface;
import com.google.android.collect.Sets;
@@ -40,6 +42,7 @@
import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
@@ -83,6 +86,7 @@
Environment::getDataSystemCeDirectory);
private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
+ private final Handler mHandler = new Handler();
TaskSnapshotController(WindowManagerService service) {
mService = service;
@@ -114,8 +118,13 @@
// We need to take a snapshot of the task if and only if all activities of the task are
// either closing or hidden.
getClosingTasks(closingApps, mTmpTasks);
- for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
- final Task task = mTmpTasks.valueAt(i);
+ snapshotTasks(mTmpTasks);
+
+ }
+
+ private void snapshotTasks(ArraySet<Task> tasks) {
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ final Task task = tasks.valueAt(i);
final int mode = getSnapshotMode(task);
final TaskSnapshot snapshot;
switch (mode) {
@@ -284,6 +293,33 @@
mPersister.setPaused(paused);
}
+ /**
+ * Called when screen is being turned off.
+ */
+ void screenTurningOff(ScreenOffListener listener) {
+ if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+ listener.onScreenOff();
+ return;
+ }
+
+ // We can't take a snapshot when screen is off, so take a snapshot now!
+ mHandler.post(() -> {
+ try {
+ synchronized (mService.mWindowMap) {
+ mTmpTasks.clear();
+ mService.mRoot.forAllTasks(task -> {
+ if (task.isVisible()) {
+ mTmpTasks.add(task);
+ }
+ });
+ snapshotTasks(mTmpTasks);
+ }
+ } finally {
+ listener.onScreenOff();
+ }
+ });
+ }
+
void dump(PrintWriter pw, String prefix) {
mCache.dump(pw, prefix);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 0287070..297e288 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -39,6 +39,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
+import java.util.ArrayList;
/**
* Persists {@link TaskSnapshot}s to disk.
@@ -55,10 +56,13 @@
private static final int QUALITY = 95;
private static final String PROTO_EXTENSION = ".proto";
private static final String BITMAP_EXTENSION = ".jpg";
+ private static final int MAX_STORE_QUEUE_DEPTH = 2;
@GuardedBy("mLock")
private final ArrayDeque<WriteQueueItem> mWriteQueue = new ArrayDeque<>();
@GuardedBy("mLock")
+ private final ArrayDeque<StoreWriteQueueItem> mStoreQueueItems = new ArrayDeque<>();
+ @GuardedBy("mLock")
private boolean mQueueIdling;
@GuardedBy("mLock")
private boolean mPaused;
@@ -153,11 +157,22 @@
@GuardedBy("mLock")
private void sendToQueueLocked(WriteQueueItem item) {
mWriteQueue.offer(item);
+ item.onQueuedLocked();
+ ensureStoreQueueDepthLocked();
if (!mPaused) {
mLock.notifyAll();
}
}
+ @GuardedBy("mLock")
+ private void ensureStoreQueueDepthLocked() {
+ while (mStoreQueueItems.size() > MAX_STORE_QUEUE_DEPTH) {
+ final StoreWriteQueueItem item = mStoreQueueItems.poll();
+ mWriteQueue.remove(item);
+ Slog.i(TAG, "Queue is too deep! Purged item with taskid=" + item.mTaskId);
+ }
+ }
+
private File getDirectory(int userId) {
return new File(mDirectoryResolver.getSystemDirectoryForUser(userId), SNAPSHOTS_DIRNAME);
}
@@ -202,6 +217,9 @@
next = null;
} else {
next = mWriteQueue.poll();
+ if (next != null) {
+ next.onDequeuedLocked();
+ }
}
}
if (next != null) {
@@ -209,11 +227,12 @@
SystemClock.sleep(DELAY_MS);
}
synchronized (mLock) {
- if (!mWriteQueue.isEmpty()) {
+ final boolean writeQueueEmpty = mWriteQueue.isEmpty();
+ if (!writeQueueEmpty && !mPaused) {
continue;
}
try {
- mQueueIdling = true;
+ mQueueIdling = writeQueueEmpty;
mLock.wait();
mQueueIdling = false;
} catch (InterruptedException e) {
@@ -225,6 +244,18 @@
private abstract class WriteQueueItem {
abstract void write();
+
+ /**
+ * Called when this queue item has been put into the queue.
+ */
+ void onQueuedLocked() {
+ }
+
+ /**
+ * Called when this queue item has been taken out of the queue.
+ */
+ void onDequeuedLocked() {
+ }
}
private class StoreWriteQueueItem extends WriteQueueItem {
@@ -239,6 +270,16 @@
}
@Override
+ void onQueuedLocked() {
+ mStoreQueueItems.offer(this);
+ }
+
+ @Override
+ void onDequeuedLocked() {
+ mStoreQueueItems.remove(this);
+ }
+
+ @Override
void write() {
if (!createDirectory(mUserId)) {
Slog.e(TAG, "Unable to create snapshot directory for user dir="
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 2b9e800..3a116bb 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -39,6 +39,7 @@
import static com.android.internal.policy.DecorView.getColorViewLeftInset;
import static com.android.internal.policy.DecorView.getColorViewTopInset;
import static com.android.internal.policy.DecorView.getNavigationBarRect;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -113,10 +114,9 @@
private final Rect mStableInsets = new Rect();
private final Rect mContentInsets = new Rect();
private final Rect mFrame = new Rect();
- private final TaskSnapshot mSnapshot;
+ private TaskSnapshot mSnapshot;
private final CharSequence mTitle;
private boolean mHasDrawn;
- private boolean mReportNextDraw;
private long mShownTime;
private final Handler mHandler;
private boolean mSizeMismatch;
@@ -233,10 +233,14 @@
final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
+ if (DEBUG_STARTING_WINDOW) {
+ Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms");
+ }
return;
}
}
try {
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
mSession.remove(mWindow);
} catch (RemoteException e) {
// Local call.
@@ -255,6 +259,8 @@
private void drawSnapshot() {
final GraphicBuffer buffer = mSnapshot.getSnapshot();
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
+ + mSizeMismatch);
if (mSizeMismatch) {
// The dimensions of the buffer and the window don't match, so attaching the buffer
// will fail. Better create a child window with the exact dimensions and fill the parent
@@ -263,15 +269,14 @@
} else {
drawSizeMatchSnapshot(buffer);
}
- final boolean reportNextDraw;
synchronized (mService.mWindowMap) {
mShownTime = SystemClock.uptimeMillis();
mHasDrawn = true;
- reportNextDraw = mReportNextDraw;
}
- if (reportNextDraw) {
- reportDrawn();
- }
+ reportDrawn();
+
+ // In case window manager leaks us, make sure we don't retain the snapshot.
+ mSnapshot = null;
}
private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
@@ -356,9 +361,6 @@
}
private void reportDrawn() {
- synchronized (mService.mWindowMap) {
- mReportNextDraw = false;
- }
try {
mSession.finishDrawing(mWindow);
} catch (RemoteException e) {
@@ -376,9 +378,6 @@
final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
synchronized (surface.mService.mWindowMap) {
hasDrawn = surface.mHasDrawn;
- if (!hasDrawn) {
- surface.mReportNextDraw = true;
- }
}
if (hasDrawn) {
surface.reportDrawn();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index da7a9f0..9d48ce5 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -139,6 +139,8 @@
// Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
private final Rect mBoundsAfterRotation = new Rect();
+ Rect mPreAnimationBounds = new Rect();
+
TaskStack(WindowManagerService service, int stackId) {
mService = service;
mStackId = stackId;
@@ -336,6 +338,8 @@
} else {
mBoundsAnimationSourceHintBounds.setEmpty();
}
+
+ mPreAnimationBounds.set(mBounds);
}
/**
@@ -1530,10 +1534,17 @@
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mService.mWindowMap) {
mBoundsAnimating = false;
+ for (int i = 0; i < mChildren.size(); i++) {
+ final Task t = mChildren.get(i);
+ t.clearPreserveNonFloatingState();
+ }
mService.requestTraversal();
}
if (mStackId == PINNED_STACK_ID) {
+ // Update to the final bounds if requested. This is done here instead of in the bounds
+ // animator to allow us to coordinate this after we notify the PiP mode changed
+
final PinnedStackWindowController controller =
(PinnedStackWindowController) getController();
if (schedulePipModeChangedCallback && controller != null) {
@@ -1543,8 +1554,6 @@
mBoundsAnimationTarget);
}
- // Update to the final bounds if requested. This is done here instead of in the bounds
- // animator to allow us to coordinate this after we notify the PiP mode changed
if (finalStackSize != null) {
setPinnedStackSize(finalStackSize, null);
}
@@ -1584,8 +1593,12 @@
return mBoundsAnimating;
}
+ public boolean lastAnimatingBoundsWasToFullscreen() {
+ return mBoundsAnimatingToFullscreen;
+ }
+
public boolean isAnimatingBoundsToFullscreen() {
- return mBoundsAnimating && mBoundsAnimatingToFullscreen;
+ return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen();
}
public boolean pinnedStackResizeDisallowed() {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index d64dc0e..d85dd0c 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -52,6 +52,7 @@
/** Is any window animating? */
private boolean mAnimating;
+ private boolean mLastAnimating;
/** Is any app window animating? */
boolean mAppWindowAnimating;
@@ -158,7 +159,6 @@
*/
private void animate(long frameTimeNs) {
boolean transactionOpen = false;
- boolean wasAnimating = false;
try {
synchronized (mService.mWindowMap) {
if (!mInitialized) {
@@ -167,8 +167,7 @@
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
- wasAnimating = mAnimating;
- setAnimating(false);
+ mAnimating = false;
mAppWindowAnimating = false;
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
@@ -269,25 +268,22 @@
mWindowPlacerLocked.requestTraversal();
}
- if (mAnimating && !wasAnimating) {
+ if (mAnimating && !mLastAnimating) {
// Usually app transitions but quite a load onto the system already (with all the
// things happening in app), so pause task snapshot persisting to not increase the
// load.
mService.mTaskSnapshotController.setPersisterPaused(true);
- if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
- Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
- }
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
}
-
- if (!mAnimating && wasAnimating) {
+ if (!mAnimating && mLastAnimating) {
mWindowPlacerLocked.requestTraversal();
mService.mTaskSnapshotController.setPersisterPaused(false);
- if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
- }
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
}
+ mLastAnimating = mAnimating;
+
if (mRemoveReplacedWindows) {
mService.mRoot.removeReplacedWindows();
mRemoveReplacedWindows = false;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 84ba139..600bc5c 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -16,6 +16,11 @@
package com.android.server.wm;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.res.Configuration.EMPTY;
+
import android.annotation.CallSuper;
import android.content.res.Configuration;
import android.util.Pools;
@@ -27,11 +32,6 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.res.Configuration.EMPTY;
-
/**
* Defines common functionality for classes that can hold windows directly or through their
* children in a hierarchy form.
@@ -52,7 +52,7 @@
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
- protected final LinkedList<E> mChildren = new LinkedList();
+ protected final WindowList<E> mChildren = new WindowList<E>();
/** Contains override configuration settings applied to this window container. */
private Configuration mOverrideConfiguration = new Configuration();
@@ -258,7 +258,7 @@
case POSITION_TOP:
if (mChildren.peekLast() != child) {
mChildren.remove(child);
- mChildren.addLast(child);
+ mChildren.add(child);
}
if (includingParents && getParent() != null) {
getParent().positionChildAt(POSITION_TOP, this /* child */,
@@ -627,6 +627,17 @@
wrapper.release();
}
+ /**
+ * For all tasks at or below this container call the callback.
+ *
+ * @param callback Callback to be called for every task.
+ */
+ void forAllTasks(Consumer<Task> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ mChildren.get(i).forAllTasks(callback);
+ }
+ }
+
WindowState getWindow(Predicate<WindowState> callback) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState w = mChildren.get(i).getWindow(callback);
@@ -649,45 +660,50 @@
}
if (mParent != null && mParent == other.mParent) {
- final LinkedList<WindowContainer> list = mParent.mChildren;
+ final WindowList<WindowContainer> list = mParent.mChildren;
return list.indexOf(this) > list.indexOf(other) ? 1 : -1;
}
final LinkedList<WindowContainer> thisParentChain = mTmpChain1;
final LinkedList<WindowContainer> otherParentChain = mTmpChain2;
- getParents(thisParentChain);
- other.getParents(otherParentChain);
+ try {
+ getParents(thisParentChain);
+ other.getParents(otherParentChain);
- // Find the common ancestor of both containers.
- WindowContainer commonAncestor = null;
- WindowContainer thisTop = thisParentChain.peekLast();
- WindowContainer otherTop = otherParentChain.peekLast();
- while (thisTop != null && otherTop != null && thisTop == otherTop) {
- commonAncestor = thisParentChain.removeLast();
- otherParentChain.removeLast();
- thisTop = thisParentChain.peekLast();
- otherTop = otherParentChain.peekLast();
+ // Find the common ancestor of both containers.
+ WindowContainer commonAncestor = null;
+ WindowContainer thisTop = thisParentChain.peekLast();
+ WindowContainer otherTop = otherParentChain.peekLast();
+ while (thisTop != null && otherTop != null && thisTop == otherTop) {
+ commonAncestor = thisParentChain.removeLast();
+ otherParentChain.removeLast();
+ thisTop = thisParentChain.peekLast();
+ otherTop = otherParentChain.peekLast();
+ }
+
+ // Containers don't belong to the same hierarchy???
+ if (commonAncestor == null) {
+ throw new IllegalArgumentException("No in the same hierarchy this="
+ + thisParentChain + " other=" + otherParentChain);
+ }
+
+ // Children are always considered greater than their parents, so if one of the containers
+ // we are comparing it the parent of the other then whichever is the child is greater.
+ if (commonAncestor == this) {
+ return -1;
+ } else if (commonAncestor == other) {
+ return 1;
+ }
+
+ // The position of the first non-common ancestor in the common ancestor list determines
+ // which is greater the which.
+ final WindowList<WindowContainer> list = commonAncestor.mChildren;
+ return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
+ ? 1 : -1;
+ } finally {
+ mTmpChain1.clear();
+ mTmpChain2.clear();
}
-
- // Containers don't belong to the same hierarchy???
- if (commonAncestor == null) {
- throw new IllegalArgumentException("No in the same hierarchy this="
- + thisParentChain + " other=" + otherParentChain);
- }
-
- // Children are always considered greater than their parents, so if one of the containers
- // we are comparing it the parent of the other then whichever is the child is greater.
- if (commonAncestor == this) {
- return -1;
- } else if (commonAncestor == other) {
- return 1;
- }
-
- // The position of the first non-common ancestor in the common ancestor list determines
- // which is greater the which.
- final LinkedList<WindowContainer> list = commonAncestor.mChildren;
- return list.indexOf(thisParentChain.peekLast()) > list.indexOf(otherParentChain.peekLast())
- ? 1 : -1;
}
private void getParents(LinkedList<WindowContainer> parents) {
diff --git a/services/core/java/com/android/server/wm/WindowList.java b/services/core/java/com/android/server/wm/WindowList.java
new file mode 100644
index 0000000..dfeba40
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowList.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import java.util.ArrayList;
+
+/**
+ * An {@link ArrayList} with extended functionality to be used as the children data structure in
+ * {@link WindowContainer}.
+ */
+class WindowList<E> extends ArrayList<E> {
+
+ void addFirst(E e) {
+ add(0, e);
+ }
+
+ E peekLast() {
+ return size() > 0 ? get(size() - 1) : null;
+ }
+
+ E peekFirst() {
+ return size() > 0 ? get(0) : null;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 1b61fca..8279b51 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -51,7 +51,8 @@
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
- static final boolean DEBUG_STARTING_WINDOW = false;
+ static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
+ static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || true;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 63cc9bf..a2ae430 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -203,6 +203,7 @@
import android.view.WindowManagerInternal;
import android.view.WindowManagerPolicy;
import android.view.WindowManagerPolicy.PointerEventListener;
+import android.view.WindowManagerPolicy.ScreenOffListener;
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManagerInternal;
@@ -1521,7 +1522,7 @@
// Try using the target SDK of the root window
if (attachedWindow != null) {
return attachedWindow.mAppToken != null
- && attachedWindow.mAppToken.mTargetSdk > Build.VERSION_CODES.N_MR1;
+ && attachedWindow.mAppToken.mTargetSdk >= Build.VERSION_CODES.O;
} else {
// Otherwise, look at the package
try {
@@ -1532,7 +1533,7 @@
throw new SecurityException("Package " + packageName + " not in UID "
+ callingUid);
}
- if (appInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
+ if (appInfo.targetSdkVersion >= Build.VERSION_CODES.O) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
@@ -1685,6 +1686,10 @@
// re-factor.
atoken.firstWindowDrawn = false;
atoken.clearAllDrawn();
+ final TaskStack stack = atoken.getStack();
+ if (stack != null) {
+ stack.mExitingAppTokens.remove(atoken);
+ }
}
}
@@ -1952,6 +1957,16 @@
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
|| !win.mAppToken.isClientHidden())) {
+
+ // We are about to create a surface, but we didn't run a layout yet. So better run
+ // a layout now that we already know the right size, as a resize call will make the
+ // surface transaction blocking until next vsync and slow us down.
+ // TODO: Ideally we'd create the surface after running layout a bit further down,
+ // but moving this seems to be too risky at this point in the release.
+ if (win.mLayoutSeq == -1) {
+ win.setDisplayLayoutNeeded();
+ mWindowPlacerLocked.performSurfacePlacement(true);
+ }
result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
oldVisibility);
try {
@@ -2083,6 +2098,7 @@
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
+ win.mLastRelayoutContentInsets.set(win.mContentInsets);
outVisibleInsets.set(win.mVisibleInsets);
outStableInsets.set(win.mStableInsets);
outOutsets.set(win.mOutsets);
@@ -2795,6 +2811,11 @@
mH.sendEmptyMessage(H.NOTIFY_KEYGUARD_TRUSTED_CHANGED);
}
+ @Override
+ public void screenTurningOff(ScreenOffListener listener) {
+ mTaskSnapshotController.screenTurningOff(listener);
+ }
+
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 25b6561..2ffa152 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -80,6 +80,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -138,6 +139,7 @@
import com.android.server.input.InputWindowHandle;
import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
@@ -170,7 +172,7 @@
final int mOwnerUid;
/** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */
final boolean mOwnerCanAddInternalSystemWindow;
- final IWindowId mWindowId;
+ final WindowId mWindowId;
WindowToken mToken;
// The same object as mToken if this is an app window and null for non-app windows.
AppWindowToken mAppToken;
@@ -208,7 +210,7 @@
boolean mHidden; // Used to determine if to show child windows.
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
private boolean mDragResizing;
- private boolean mDragResizingChangeReported;
+ private boolean mDragResizingChangeReported = true;
private int mResizeMode;
private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
@@ -257,6 +259,16 @@
*/
final Rect mContentInsets = new Rect();
final Rect mLastContentInsets = new Rect();
+
+ /**
+ * The last content insets returned to the client in relayout. We use
+ * these in the bounds animation to ensure we only observe inset changes
+ * at the same time that a client resizes it's surface so that we may use
+ * the geometryAppliesWithResize synchronization mechanism to keep
+ * the contents in place.
+ */
+ final Rect mLastRelayoutContentInsets = new Rect();
+
private boolean mContentInsetsChanged;
/**
@@ -577,20 +589,7 @@
mAppToken = mToken.asAppWindowToken();
mOwnerUid = ownerId;
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
- mWindowId = new IWindowId.Stub() {
- @Override
- public void registerFocusObserver(IWindowFocusObserver observer) {
- WindowState.this.registerFocusObserver(observer);
- }
- @Override
- public void unregisterFocusObserver(IWindowFocusObserver observer) {
- WindowState.this.unregisterFocusObserver(observer);
- }
- @Override
- public boolean isFocused() {
- return WindowState.this.isFocused();
- }
- };
+ mWindowId = new WindowId(this);
mAttrs.copyFrom(a);
mViewVisibility = viewVisibility;
mPolicy = mService.mPolicy;
@@ -1145,11 +1144,7 @@
return;
}
- mLastOverscanInsets.set(mOverscanInsets);
- mLastContentInsets.set(mContentInsets);
- mLastVisibleInsets.set(mVisibleInsets);
- mLastStableInsets.set(mStableInsets);
- mLastOutsets.set(mOutsets);
+ updateLastInsetValues();
mService.makeWindowFreezingScreenIfNeededLocked(this);
// If the orientation is changing, or we're starting or ending a drag resizing action,
@@ -1300,7 +1295,7 @@
* otherwise.
*/
boolean wouldBeVisibleIfPolicyIgnored() {
- return mHasSurface && mPolicyVisibility && !isParentWindowHidden()
+ return mHasSurface && !isParentWindowHidden()
&& !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
}
@@ -3791,7 +3786,7 @@
private void logPerformShow(String prefix) {
if (DEBUG_VISIBILITY
- || (DEBUG_STARTING_WINDOW && mAttrs.type == TYPE_APPLICATION_STARTING)) {
+ || (DEBUG_STARTING_WINDOW_VERBOSE && mAttrs.type == TYPE_APPLICATION_STARTING)) {
Slog.v(TAG, prefix + this
+ ": mDrawState=" + mWinAnimator.drawStateToString()
+ " readyForDisplay=" + isReadyForDisplay()
@@ -4394,6 +4389,24 @@
return result;
}
+ /**
+ * @return True if this window has been laid out at least once; false otherwise.
+ */
+ boolean isLaidOut() {
+ return mLayoutSeq != -1;
+ }
+
+ /**
+ * Updates the last inset values to the current ones.
+ */
+ void updateLastInsetValues() {
+ mLastOverscanInsets.set(mOverscanInsets);
+ mLastContentInsets.set(mContentInsets);
+ mLastVisibleInsets.set(mVisibleInsets);
+ mLastStableInsets.set(mStableInsets);
+ mLastOutsets.set(mOutsets);
+ }
+
// 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.
@@ -4411,6 +4424,40 @@
}
}
+ private static final class WindowId extends IWindowId.Stub {
+ private final WeakReference<WindowState> mOuter;
+
+ private WindowId(WindowState outer) {
+
+ // Use a weak reference for the outer class. This is important to prevent the following
+ // leak: Since we send this class to the client process, binder will keep it alive as
+ // long as the client keeps it alive. Now, if the window is removed, we need to clear
+ // out our reference so even though this class is kept alive we don't leak WindowState,
+ // which can keep a whole lot of classes alive.
+ mOuter = new WeakReference<>(outer);
+ }
+
+ @Override
+ public void registerFocusObserver(IWindowFocusObserver observer) {
+ final WindowState outer = mOuter.get();
+ if (outer != null) {
+ outer.registerFocusObserver(observer);
+ }
+ }
+ @Override
+ public void unregisterFocusObserver(IWindowFocusObserver observer) {
+ final WindowState outer = mOuter.get();
+ if (outer != null) {
+ outer.unregisterFocusObserver(observer);
+ }
+ }
+ @Override
+ public boolean isFocused() {
+ final WindowState outer = mOuter.get();
+ return outer != null && outer.isFocused();
+ }
+ }
+
boolean usesRelativeZOrdering() {
if (!isChildWindow()) {
return false;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6cb4ddc..d75afcf 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -30,6 +30,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
@@ -519,7 +520,7 @@
// This must be called while inside a transaction.
boolean commitFinishDrawingLocked() {
- if (DEBUG_STARTING_WINDOW &&
+ if (DEBUG_STARTING_WINDOW_VERBOSE &&
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
+ drawStateToString());
@@ -968,10 +969,8 @@
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
- //TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
- MagnificationSpec spec = mService.mAccessibilityController
- .getMagnificationSpecForWindowLocked(mWin);
+ MagnificationSpec spec = getMagnificationSpec();
+ if (spec != null) {
applyMagnificationSpec(spec, tmpMatrix);
}
@@ -1058,11 +1057,7 @@
TAG, "computeShownFrameLocked: " + this +
" not attached, mAlpha=" + mAlpha);
- MagnificationSpec spec = null;
- //TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
- spec = mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
- }
+ MagnificationSpec spec = getMagnificationSpec();
if (spec != null) {
final Rect frame = mWin.mFrame;
final float tmpFloats[] = mService.mTmpFloats;
@@ -1099,6 +1094,14 @@
}
}
+ private MagnificationSpec getMagnificationSpec() {
+ //TODO (multidisplay): Magnification is supported only for the default display.
+ if (mService.mAccessibilityController != null && mWin.getDisplayId() == DEFAULT_DISPLAY) {
+ return mService.mAccessibilityController.getMagnificationSpecForWindowLocked(mWin);
+ }
+ return null;
+ }
+
/**
* 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
@@ -1136,6 +1139,27 @@
if (StackId.tasksAreFloating(stack.mStackId)) {
w.expandForSurfaceInsets(finalClipRect);
}
+
+ // We may be applying a magnification spec to all windows,
+ // simulating a transformation in screen space, in which case
+ // we need to transform all other screen space values...including
+ // the final crop. This is kind of messed up and we should look
+ // in to actually transforming screen-space via a parent-layer.
+ // b/38322835
+ MagnificationSpec spec = getMagnificationSpec();
+ if (spec != null && !spec.isNop()) {
+ Matrix transform = mWin.mTmpMatrix;
+ RectF finalCrop = mService.mTmpRectF;
+ transform.reset();
+ transform.postScale(spec.scale, spec.scale);
+ transform.postTranslate(-spec.offsetX, -spec.offsetY);
+ transform.mapRect(finalCrop);
+ finalClipRect.top = (int)finalCrop.top;
+ finalClipRect.left = (int)finalCrop.left;
+ finalClipRect.right = (int)finalClipRect.right;
+ finalClipRect.bottom = (int)finalClipRect.bottom;
+ }
+
return true;
}
@@ -1374,7 +1398,23 @@
int posX = mTmpSize.left;
int posY = mTmpSize.top;
task.mStack.getDimBounds(mTmpStackBounds);
+
+ boolean allowStretching = false;
task.mStack.getFinalAnimationSourceHintBounds(mTmpSourceBounds);
+ // If we don't have source bounds, we can attempt to use the content insets
+ // in the following scenario:
+ // 1. We have content insets.
+ // 2. We are not transitioning to full screen
+ // We have to be careful to check "lastAnimatingBoundsWasToFullscreen" rather than
+ // the mBoundsAnimating state, as we may have already left it and only be here
+ // because of the force-scale until resize state.
+ if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
+ || mWin.mLastRelayoutContentInsets.height() > 0)
+ && !task.mStack.lastAnimatingBoundsWasToFullscreen()) {
+ mTmpSourceBounds.set(task.mStack.mPreAnimationBounds);
+ mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
+ allowStretching = true;
+ }
if (!mTmpSourceBounds.isEmpty()) {
// Get the final target stack bounds, if we are not animating, this is just the
// current stack bounds
@@ -1384,14 +1424,24 @@
// and source bounds
float finalWidth = mTmpAnimatingBounds.width();
float initialWidth = mTmpSourceBounds.width();
- float t = (surfaceContentWidth - mTmpStackBounds.width())
+ float tw = (surfaceContentWidth - mTmpStackBounds.width())
/ (surfaceContentWidth - mTmpAnimatingBounds.width());
- mExtraHScale = (initialWidth + t * (finalWidth - initialWidth)) / initialWidth;
- mExtraVScale = mExtraHScale;
+ float th = tw;
+ mExtraHScale = (initialWidth + tw * (finalWidth - initialWidth)) / initialWidth;
+ if (allowStretching) {
+ float finalHeight = mTmpAnimatingBounds.height();
+ float initialHeight = mTmpSourceBounds.height();
+ th = (surfaceContentHeight - mTmpStackBounds.height())
+ / (surfaceContentHeight - mTmpAnimatingBounds.height());
+ mExtraVScale = (initialHeight + tw * (finalHeight - initialHeight))
+ / initialHeight;
+ } else {
+ mExtraVScale = mExtraHScale;
+ }
// Adjust the position to account for the inset bounds
- posX -= (int) (t * mExtraHScale * mTmpSourceBounds.left);
- posY -= (int) (t * mExtraVScale * mTmpSourceBounds.top);
+ posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left);
+ posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top);
// Always clip to the stack bounds since the surface can be larger with the current
// scale
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 675b641..e6c2b1d 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -10,6 +10,7 @@
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
@@ -63,6 +64,7 @@
liblog \
libhardware \
libhardware_legacy \
+ libhidlbase \
libkeystore_binder \
libnativehelper \
libutils \
@@ -93,7 +95,7 @@
android.hardware.ir@1.0 \
android.hardware.light@2.0 \
android.hardware.power@1.0 \
- android.hardware.power@1.1 \
+ android.hardware.tetheroffload.config@1.0 \
android.hardware.thermal@1.0 \
android.hardware.tv.cec@1.0 \
android.hardware.tv.input@1.0 \
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 37ae782..57bb9fe 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -29,7 +29,6 @@
#include <unistd.h>
#include <android/hardware/power/1.0/IPower.h>
-#include <android/hardware/power/1.1/IPower.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -47,8 +46,6 @@
using android::hardware::power::V1_0::PowerStatePlatformSleepState;
using android::hardware::power::V1_0::PowerStateVoter;
using android::hardware::power::V1_0::Status;
-using android::hardware::power::V1_1::PowerStateSubsystem;
-using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
using android::hardware::hidl_vec;
namespace android
@@ -266,105 +263,9 @@
return total_added;
}
-static jint getSubsystemLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
- char *output = (char*)env->GetDirectBufferAddress(outBuf);
- char *offset = output;
- int remaining = (int)env->GetDirectBufferCapacity(outBuf);
- int total_added = -1;
-
- //This is a IPower 1.1 API
- sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 = nullptr;
-
- if (outBuf == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", "null argument");
- return -1;
- }
-
- {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- if (!getPowerHal()) {
- ALOGE("Power Hal not loaded");
- return -1;
- }
-
- //Trying to cast to 1.1, this will succeed only for devices supporting 1.1
- gPowerHal_1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHal);
- if (gPowerHal_1_1 == nullptr) {
- //This device does not support IPower@1.1, exiting gracefully
- return 0;
- }
-
- Return<void> ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&offset, &remaining, &total_added](hidl_vec<PowerStateSubsystem> subsystems,
- Status status) {
-
- if (status != Status::SUCCESS)
- return;
-
- for (size_t i = 0; i < subsystems.size(); i++) {
- int added;
- const PowerStateSubsystem &subsystem = subsystems[i];
-
- added = snprintf(offset, remaining,
- "subsystem_%zu name=%s ", i + 1, subsystem.name.c_str());
- if (added < 0) {
- break;
- }
-
- if (added > remaining) {
- added = remaining;
- }
-
- offset += added;
- remaining -= added;
- total_added += added;
-
- for (size_t j = 0; j < subsystem.states.size(); j++) {
- const PowerStateSubsystemSleepState& state = subsystem.states[j];
- added = snprintf(offset, remaining,
- "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " last entry TS(ms)=%" PRIu64 " ",
- j + 1, state.name.c_str(), state.residencyInMsecSinceBoot,
- state.totalTransitions, state.lastEntryTimestampMs);
- if (added < 0) {
- break;
- }
-
- if (added > remaining) {
- added = remaining;
- }
-
- offset += added;
- remaining -= added;
- total_added += added;
- }
-
- if (remaining <= 0) {
- /* rewrite NULL character*/
- offset--;
- total_added--;
- ALOGE("PowerHal: buffer not enough");
- break;
- }
- }
- }
- );
-
- if (!ret.isOk()) {
- ALOGE("getSubsystemLowPowerStats() failed: power HAL service not available");
- gPowerHal = nullptr;
- return -1;
- }
- }
-
- *offset = 0;
- total_added += 1;
- return total_added;
-}
-
static const JNINativeMethod method_table[] = {
{ "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
{ "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
- { "getSubsystemLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getSubsystemLowPowerStats },
};
int register_android_server_BatteryStatsService(JNIEnv *env)
diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
new file mode 100644
index 0000000..241ccf6
--- /dev/null
+++ b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <error.h>
+#include <hidl/HidlSupport.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netlink.h>
+#include <sys/socket.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
+
+#define LOG_TAG "OffloadHardwareInterface"
+#include <utils/Log.h>
+
+namespace android {
+
+using hardware::hidl_handle;
+using hardware::hidl_string;
+using hardware::tetheroffload::config::V1_0::IOffloadConfig;
+
+namespace {
+
+inline const sockaddr * asSockaddr(const sockaddr_nl *nladdr) {
+ return reinterpret_cast<const sockaddr *>(nladdr);
+}
+
+int conntrackSocket(unsigned groups) {
+ base::unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
+ if (s.get() < 0) return -errno;
+
+ const struct sockaddr_nl bind_addr = {
+ .nl_family = AF_NETLINK,
+ .nl_pad = 0,
+ .nl_pid = 0,
+ .nl_groups = groups,
+ };
+ if (bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) != 0) {
+ return -errno;
+ }
+
+ const struct sockaddr_nl kernel_addr = {
+ .nl_family = AF_NETLINK,
+ .nl_pad = 0,
+ .nl_pid = 0,
+ .nl_groups = groups,
+ };
+ if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
+ return -errno;
+ }
+
+ return s.release();
+}
+
+// Return a hidl_handle that owns the file descriptor owned by fd, and will
+// auto-close it (otherwise there would be double-close problems).
+//
+// Rely upon the compiler to eliminate the constexprs used for clarity.
+hidl_handle&& handleFromFileDescriptor(base::unique_fd fd) {
+ hidl_handle h;
+
+ NATIVE_HANDLE_DECLARE_STORAGE(storage, 0, 0);
+ static constexpr int kNumFds = 1;
+ static constexpr int kNumInts = 0;
+ native_handle_t *nh = native_handle_init(storage, kNumFds, kNumInts);
+ nh->data[0] = fd.release();
+
+ static constexpr bool kTakeOwnership = true;
+ h.setTo(nh, kTakeOwnership);
+
+ return std::move(h);
+}
+
+} // namespace
+
+static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload(
+ JNIEnv* /* env */) {
+ sp<IOffloadConfig> configInterface = IOffloadConfig::getService();
+ if (configInterface.get() == nullptr) {
+ ALOGD("Could not find IOffloadConfig service.");
+ return false;
+ }
+
+ // Per the IConfigOffload definition:
+ //
+ // fd1 A file descriptor bound to the following netlink groups
+ // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
+ //
+ // fd2 A file descriptor bound to the following netlink groups
+ // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
+ base::unique_fd
+ fd1(conntrackSocket(NFNLGRP_CONNTRACK_NEW | NFNLGRP_CONNTRACK_DESTROY)),
+ fd2(conntrackSocket(NFNLGRP_CONNTRACK_UPDATE | NFNLGRP_CONNTRACK_DESTROY));
+ if (fd1.get() < 0 || fd2.get() < 0) {
+ ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
+ return false;
+ }
+
+ hidl_handle h1(handleFromFileDescriptor(std::move(fd1))),
+ h2(handleFromFileDescriptor(std::move(fd2)));
+
+ bool rval;
+ hidl_string msg;
+ configInterface->setHandles(h1, h2,
+ [&rval, &msg](bool success, const hidl_string& errMsg) {
+ rval = success;
+ msg = errMsg;
+ });
+ if (!rval) {
+ ALOGE("IOffloadConfig::setHandles() error: %s", msg.c_str());
+ }
+
+ return rval;
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "configOffload", "()Z",
+ (void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload },
+};
+
+int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) {
+ return jniRegisterNativeMethods(env,
+ "com/android/server/connectivity/tethering/OffloadHardwareInterface",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/services/core/jni/com_android_server_radio_RadioService.cpp b/services/core/jni/com_android_server_radio_RadioService.cpp
index c424d30..73887bb 100644
--- a/services/core/jni/com_android_server_radio_RadioService.cpp
+++ b/services/core/jni/com_android_server_radio_RadioService.cpp
@@ -49,10 +49,12 @@
static Mutex gContextMutex;
-static jclass gTunerClass;
-static jmethodID gTunerCstor;
-
-static jclass gServiceClass;
+static struct {
+ struct {
+ jclass clazz;
+ jmethodID cstor;
+ } Tuner;
+} gjni;
struct ServiceContext {
ServiceContext() {}
@@ -123,6 +125,8 @@
static jobject nativeOpenTuner(JNIEnv *env, jobject obj, long nativeContext, jint moduleId,
jobject bandConfig, bool withAudio, jobject callback) {
ALOGV("nativeOpenTuner()");
+ EnvWrapper wrap(env);
+
if (callback == nullptr) {
ALOGE("Callback is empty");
return nullptr;
@@ -146,7 +150,8 @@
Region region;
BandConfig bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
- jobject tuner = env->NewObject(gTunerClass, gTunerCstor, callback, halRev, region, withAudio);
+ auto tuner = wrap(env->NewObject(gjni.Tuner.clazz, gjni.Tuner.cstor,
+ callback, halRev, region, withAudio));
if (tuner == nullptr) {
ALOGE("Unable to create new tuner object.");
return nullptr;
@@ -165,13 +170,12 @@
ALOGE("Couldn't open tuner");
ALOGE_IF(hidlResult.isOk(), "halResult = %d", halResult);
ALOGE_IF(!hidlResult.isOk(), "hidlResult = %s", hidlResult.description().c_str());
- env->DeleteLocalRef(tuner);
return nullptr;
}
Tuner::setHalTuner(env, tuner, halTuner);
ALOGI("Opened tuner %p", halTuner.get());
- return tuner;
+ return tuner.release();
}
static const JNINativeMethod gRadioServiceMethods[] = {
@@ -192,13 +196,10 @@
register_android_server_radio_convert(env);
auto tunerClass = FindClassOrDie(env, "com/android/server/radio/Tuner");
- gTunerClass = MakeGlobalRefOrDie(env, tunerClass);
- gTunerCstor = GetMethodIDOrDie(env, tunerClass, "<init>",
+ gjni.Tuner.clazz = MakeGlobalRefOrDie(env, tunerClass);
+ gjni.Tuner.cstor = GetMethodIDOrDie(env, tunerClass, "<init>",
"(Landroid/hardware/radio/ITunerCallback;IIZ)V");
- auto serviceClass = FindClassOrDie(env, "com/android/server/radio/RadioService");
- gServiceClass = MakeGlobalRefOrDie(env, serviceClass);
-
auto res = jniRegisterNativeMethods(env, "com/android/server/radio/RadioService",
gRadioServiceMethods, NELEM(gRadioServiceMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp
index 052823f..b92136a 100644
--- a/services/core/jni/com_android_server_radio_Tuner.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner.cpp
@@ -48,8 +48,14 @@
static struct {
struct {
+ jclass clazz;
+ jmethodID cstor;
+ jmethodID add;
+ } ArrayList;
+ struct {
jfieldID nativeContext;
jfieldID region;
+ jfieldID tunerCallback;
} Tuner;
} gjni;
@@ -59,7 +65,6 @@
HalRevision mHalRev;
sp<V1_0::ITuner> mHalTuner;
sp<V1_1::ITuner> mHalTuner11;
- sp<TunerCallback> mNativeCallback;
private:
DISALLOW_COPY_AND_ASSIGN(TunerContext);
@@ -74,17 +79,16 @@
/**
* Always lock gContextMutex when using native context.
*/
-static TunerContext& getNativeContext(JNIEnv *env, jobject obj) {
- return getNativeContext(env->GetLongField(obj, gjni.Tuner.nativeContext));
+static TunerContext& getNativeContext(JNIEnv *env, JavaRef<jobject> const &jTuner) {
+ return getNativeContext(env->GetLongField(jTuner.get(), gjni.Tuner.nativeContext));
}
-static jlong nativeInit(JNIEnv *env, jobject obj, jobject clientCallback, jint halRev) {
+static jlong nativeInit(JNIEnv *env, jobject obj, jint halRev) {
ALOGV("nativeInit()");
AutoMutex _l(gContextMutex);
auto ctx = new TunerContext();
ctx->mHalRev = static_cast<HalRevision>(halRev);
- ctx->mNativeCallback = new TunerCallback(env, obj, clientCallback, ctx->mHalRev);
static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
return reinterpret_cast<jlong>(ctx);
@@ -98,12 +102,12 @@
delete ctx;
}
-void setHalTuner(JNIEnv *env, jobject obj, sp<V1_0::ITuner> halTuner) {
+void setHalTuner(JNIEnv *env, JavaRef<jobject> const &jTuner, sp<V1_0::ITuner> halTuner) {
ALOGV("setHalTuner(%p)", halTuner.get());
ALOGE_IF(halTuner == nullptr, "HAL tuner is a nullptr");
AutoMutex _l(gContextMutex);
- auto& ctx = getNativeContext(env, obj);
+ auto& ctx = getNativeContext(env, jTuner);
ctx.mHalTuner = halTuner;
ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
@@ -114,21 +118,18 @@
sp<V1_0::ITuner> getHalTuner(jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto tuner = getNativeContext(nativeContext).mHalTuner;
- LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner not set");
+ LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner is not open");
return tuner;
}
sp<V1_1::ITuner> getHalTuner11(jlong nativeContext) {
AutoMutex _l(gContextMutex);
- auto tuner = getNativeContext(nativeContext).mHalTuner11;
- LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner not set");
- return tuner;
+ return getNativeContext(nativeContext).mHalTuner11;
}
-sp<ITunerCallback> getNativeCallback(JNIEnv *env, jobject obj) {
- AutoMutex _l(gContextMutex);
- auto& ctx = getNativeContext(env, obj);
- return ctx.mNativeCallback;
+sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
+ return TunerCallback::getNativeCallback(env,
+ env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
}
Region getRegion(JNIEnv *env, jobject obj) {
@@ -138,16 +139,16 @@
static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(nativeContext);
+ if (ctx.mHalTuner == nullptr) return;
ALOGI("Closing tuner %p", ctx.mHalTuner.get());
- ctx.mNativeCallback->detach();
ctx.mHalTuner11 = nullptr;
ctx.mHalTuner = nullptr;
- ctx.mNativeCallback = nullptr;
}
static void nativeSetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext, jobject config) {
ALOGV("nativeSetConfiguration()");
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return;
Region region_unused;
BandConfig bandConfigHal = convert::BandConfigToHal(env, config, region_unused);
@@ -159,6 +160,7 @@
Region region) {
ALOGV("nativeSetConfiguration()");
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return nullptr;
BandConfig halConfig;
Result halResult;
@@ -177,6 +179,7 @@
bool directionDown, bool skipSubChannel) {
ALOGV("nativeStep()");
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return;
auto dir = convert::DirectionToHal(directionDown);
convert::ThrowIfFailed(env, halTuner->step(dir, skipSubChannel));
@@ -186,6 +189,7 @@
bool directionDown, bool skipSubChannel) {
ALOGV("nativeScan()");
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return;
auto dir = convert::DirectionToHal(directionDown);
convert::ThrowIfFailed(env, halTuner->scan(dir, skipSubChannel));
@@ -195,6 +199,7 @@
jint channel, jint subChannel) {
ALOGV("nativeTune(%d, %d)", channel, subChannel);
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return;
convert::ThrowIfFailed(env, halTuner->tune(channel, subChannel));
}
@@ -202,6 +207,7 @@
static void nativeCancel(JNIEnv *env, jobject obj, jlong nativeContext) {
ALOGV("nativeCancel()");
auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return;
convert::ThrowIfFailed(env, halTuner->cancel());
}
@@ -210,31 +216,126 @@
ALOGV("nativeGetProgramInformation()");
auto halTuner10 = getHalTuner(nativeContext);
auto halTuner11 = getHalTuner11(nativeContext);
+ if (halTuner10 == nullptr) return nullptr;
- V1_1::ProgramInfo halInfo;
+ JavaRef<jobject> jInfo;
Result halResult;
Return<void> hidlResult;
if (halTuner11 != nullptr) {
hidlResult = halTuner11->getProgramInformation_1_1([&](Result result,
const V1_1::ProgramInfo& info) {
halResult = result;
- halInfo = info;
+ if (result != Result::OK) return;
+ jInfo = convert::ProgramInfoFromHal(env, info);
});
} else {
hidlResult = halTuner10->getProgramInformation([&](Result result,
const V1_0::ProgramInfo& info) {
halResult = result;
- halInfo.base = info;
+ if (result != Result::OK) return;
+ jInfo = convert::ProgramInfoFromHal(env, info);
});
}
+ if (jInfo != nullptr) return jInfo.release();
+ convert::ThrowIfFailed(env, hidlResult, halResult);
+ return nullptr;
+}
+
+static bool nativeStartBackgroundScan(JNIEnv *env, jobject obj, jlong nativeContext) {
+ ALOGV("nativeStartBackgroundScan()");
+ auto halTuner = getHalTuner11(nativeContext);
+ if (halTuner == nullptr) {
+ ALOGI("Background scan is not supported with HAL < 1.1");
+ return false;
+ }
+
+ auto halResult = halTuner->startBackgroundScan();
+
+ if (halResult.isOk() && halResult == ProgramListResult::UNAVAILABLE) return false;
+ return !convert::ThrowIfFailed(env, halResult);
+}
+
+static jobject nativeGetProgramList(JNIEnv *env, jobject obj, jlong nativeContext, jstring jFilter) {
+ ALOGV("nativeGetProgramList()");
+ EnvWrapper wrap(env);
+ auto halTuner = getHalTuner11(nativeContext);
+ if (halTuner == nullptr) {
+ ALOGI("Program list is not supported with HAL < 1.1");
+ return nullptr;
+ }
+
+ JavaRef<jobject> jList;
+ ProgramListResult halResult = ProgramListResult::NOT_INITIALIZED;
+ auto filter = env->GetStringUTFChars(jFilter, nullptr);
+ auto hidlResult = halTuner->getProgramList(filter,
+ [&](ProgramListResult result, const hidl_vec<V1_1::ProgramInfo>& programList) {
+ halResult = result;
+ if (halResult != ProgramListResult::OK) return;
+
+ jList = wrap(env->NewObject(gjni.ArrayList.clazz, gjni.ArrayList.cstor));
+ for (auto& program : programList) {
+ auto jProgram = convert::ProgramInfoFromHal(env, program);
+ env->CallBooleanMethod(jList.get(), gjni.ArrayList.add, jProgram.get());
+ }
+ });
+
if (convert::ThrowIfFailed(env, hidlResult, halResult)) return nullptr;
- return convert::ProgramInfoFromHal(env, halInfo).release();
+ return jList.release();
+}
+
+static bool nativeIsAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext) {
+ ALOGV("nativeIsAnalogForced()");
+ auto halTuner = getHalTuner11(nativeContext);
+ if (halTuner == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Forced analog switch is not supported with HAL < 1.1");
+ return false;
+ }
+
+ bool isForced;
+ Result halResult;
+ auto hidlResult = halTuner->isAnalogForced([&](Result result, bool isForcedRet) {
+ halResult = result;
+ isForced = isForcedRet;
+ });
+
+ if (convert::ThrowIfFailed(env, hidlResult, halResult)) return false;
+
+ return isForced;
+}
+
+static void nativeSetAnalogForced(JNIEnv *env, jobject obj, jlong nativeContext, bool isForced) {
+ ALOGV("nativeSetAnalogForced()");
+ auto halTuner = getHalTuner11(nativeContext);
+ if (halTuner == nullptr) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Forced analog switch is not supported with HAL < 1.1");
+ return;
+ }
+
+ auto halResult = halTuner->setAnalogForced(isForced);
+ convert::ThrowIfFailed(env, halResult);
+}
+
+static bool nativeIsAntennaConnected(JNIEnv *env, jobject obj, jlong nativeContext) {
+ ALOGV("nativeIsAntennaConnected()");
+ auto halTuner = getHalTuner(nativeContext);
+ if (halTuner == nullptr) return false;
+
+ bool isConnected = false;
+ Result halResult;
+ auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
+ halResult = result;
+ isConnected = config.antennaConnected;
+ });
+ convert::ThrowIfFailed(env, hidlResult, halResult);
+ return isConnected;
}
static const JNINativeMethod gTunerMethods[] = {
- { "nativeInit", "(Landroid/hardware/radio/ITunerCallback;I)J", (void*)nativeInit },
+ { "nativeInit", "(I)J", (void*)nativeInit },
{ "nativeFinalize", "(J)V", (void*)nativeFinalize },
{ "nativeClose", "(J)V", (void*)nativeClose },
{ "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
@@ -247,6 +348,12 @@
{ "nativeCancel", "(J)V", (void*)nativeCancel },
{ "nativeGetProgramInformation", "(J)Landroid/hardware/radio/RadioManager$ProgramInfo;",
(void*)nativeGetProgramInformation },
+ { "nativeStartBackgroundScan", "(J)Z", (void*)nativeStartBackgroundScan },
+ { "nativeGetProgramList", "(JLjava/lang/String;)Ljava/util/List;",
+ (void*)nativeGetProgramList },
+ { "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
+ { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
+ { "nativeIsAntennaConnected", "(J)Z", (void*)nativeIsAntennaConnected },
};
} // namespace Tuner
@@ -256,11 +363,18 @@
void register_android_server_radio_Tuner(JavaVM *vm, JNIEnv *env) {
using namespace server::radio::Tuner;
- register_android_server_radio_Tuner_TunerCallback(vm, env);
+ register_android_server_radio_TunerCallback(vm, env);
auto tunerClass = FindClassOrDie(env, "com/android/server/radio/Tuner");
gjni.Tuner.nativeContext = GetFieldIDOrDie(env, tunerClass, "mNativeContext", "J");
gjni.Tuner.region = GetFieldIDOrDie(env, tunerClass, "mRegion", "I");
+ gjni.Tuner.tunerCallback = GetFieldIDOrDie(env, tunerClass, "mTunerCallback",
+ "Lcom/android/server/radio/TunerCallback;");
+
+ auto arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
+ gjni.ArrayList.clazz = MakeGlobalRefOrDie(env, arrayListClass);
+ gjni.ArrayList.cstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
+ gjni.ArrayList.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
auto res = jniRegisterNativeMethods(env, "com/android/server/radio/Tuner",
gTunerMethods, NELEM(gTunerMethods));
diff --git a/services/core/jni/com_android_server_radio_Tuner.h b/services/core/jni/com_android_server_radio_Tuner.h
index 73fee7f..f653832 100644
--- a/services/core/jni/com_android_server_radio_Tuner.h
+++ b/services/core/jni/com_android_server_radio_Tuner.h
@@ -19,6 +19,8 @@
#include "com_android_server_radio_types.h"
+#include "JavaRef.h"
+
#include <android/hardware/broadcastradio/1.1/ITuner.h>
#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
#include <jni.h>
@@ -32,9 +34,11 @@
namespace radio {
namespace Tuner {
-void setHalTuner(JNIEnv *env, jobject obj, sp<hardware::broadcastradio::V1_0::ITuner> halTuner);
+void setHalTuner(JNIEnv *env, JavaRef<jobject> const &jTuner,
+ sp<hardware::broadcastradio::V1_0::ITuner> halTuner);
-sp<hardware::broadcastradio::V1_1::ITunerCallback> getNativeCallback(JNIEnv *env, jobject obj);
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
+getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner);
Region getRegion(JNIEnv *env, jobject obj);
diff --git a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
index 4986091..1290c7a 100644
--- a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
@@ -29,7 +29,7 @@
namespace android {
namespace server {
namespace radio {
-namespace Tuner {
+namespace TunerCallback {
using hardware::Return;
using hardware::hidl_vec;
@@ -45,12 +45,16 @@
static JavaVM *gvm = nullptr;
-static jclass gITunerCallbackClass;
static struct {
- jmethodID onError;
- jmethodID onConfigurationChanged;
- jmethodID onProgramInfoChanged;
-} gITunerCallbackMethods;
+ struct {
+ jclass clazz;
+ jfieldID nativeContext;
+ jmethodID handleHwFailure;
+ jmethodID onError;
+ jmethodID onConfigurationChanged;
+ jmethodID onProgramInfoChanged;
+ } TunerCallback;
+} gjni;
// from frameworks/base/core/java/android/hardware/radio/RadioTuner.java
enum class TunerError : jint {
@@ -61,15 +65,56 @@
CONFIG = 4,
};
-TunerCallback::TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback, HalRevision halRev)
+static Mutex gContextMutex;
+
+class NativeCallback : public ITunerCallback {
+ jobject mJTuner;
+ jobject mJCallback;
+ NativeCallbackThread mCallbackThread;
+ HalRevision mHalRev;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeCallback);
+
+public:
+ NativeCallback(JNIEnv *env, jobject jTuner, jobject jCallback, HalRevision halRev);
+ virtual ~NativeCallback();
+
+ void detach();
+
+ virtual Return<void> hardwareFailure();
+ virtual Return<void> configChange(Result result, const BandConfig& config);
+ virtual Return<void> tuneComplete(Result result, const V1_0::ProgramInfo& info);
+ virtual Return<void> afSwitch(const V1_0::ProgramInfo& info);
+ virtual Return<void> antennaStateChange(bool connected);
+ virtual Return<void> trafficAnnouncement(bool active);
+ virtual Return<void> emergencyAnnouncement(bool active);
+ virtual Return<void> newMetadata(uint32_t channel, uint32_t subChannel,
+ const hidl_vec<MetaData>& metadata);
+ virtual Return<void> tuneComplete_1_1(Result result, const V1_1::ProgramInfo& info);
+ virtual Return<void> afSwitch_1_1(const V1_1::ProgramInfo& info);
+ virtual Return<void> backgroundScanAvailable(bool isAvailable);
+ virtual Return<void> backgroundScanComplete(ProgramListResult result);
+ virtual Return<void> programListChanged();
+};
+
+struct TunerCallbackContext {
+ TunerCallbackContext() {}
+
+ sp<NativeCallback> mNativeCallback;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TunerCallbackContext);
+};
+
+NativeCallback::NativeCallback(JNIEnv *env, jobject jTuner, jobject jCallback, HalRevision halRev)
: mCallbackThread(gvm), mHalRev(halRev) {
- ALOGV("TunerCallback()");
- mTuner = env->NewGlobalRef(tuner);
- mClientCallback = env->NewGlobalRef(clientCallback);
+ ALOGV("NativeCallback()");
+ mJTuner = env->NewGlobalRef(jTuner);
+ mJCallback = env->NewGlobalRef(jCallback);
}
-TunerCallback::~TunerCallback() {
- ALOGV("~TunerCallback()");
+NativeCallback::~NativeCallback() {
+ ALOGV("~NativeCallback()");
// stop callback thread before dereferencing client callback
mCallbackThread.stop();
@@ -77,41 +122,43 @@
JNIEnv *env = nullptr;
gvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4);
if (env != nullptr) {
- env->DeleteGlobalRef(mTuner);
- env->DeleteGlobalRef(mClientCallback);
+ env->DeleteGlobalRef(mJTuner);
+ env->DeleteGlobalRef(mJCallback);
}
}
-void TunerCallback::detach() {
+void NativeCallback::detach() {
// stop callback thread to ignore further calls
mCallbackThread.stop();
}
-Return<void> TunerCallback::hardwareFailure() {
- ALOGE("Not implemented: hardwareFailure");
+Return<void> NativeCallback::hardwareFailure() {
+ mCallbackThread.enqueue([this](JNIEnv *env) {
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.handleHwFailure);
+ });
+
return Return<void>();
}
-Return<void> TunerCallback::configChange(Result result, const BandConfig& config) {
+Return<void> NativeCallback::configChange(Result result, const BandConfig& config) {
ALOGV("configChange(%d)", result);
mCallbackThread.enqueue([result, config, this](JNIEnv *env) {
if (result == Result::OK) {
- auto region = getRegion(env, mTuner);
+ auto region = Tuner::getRegion(env, mJTuner);
auto jConfig = convert::BandConfigFromHal(env, config, region);
if (jConfig == nullptr) return;
- env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onConfigurationChanged,
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.onConfigurationChanged,
jConfig.get());
} else {
- env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onError,
- TunerError::CONFIG);
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.onError, TunerError::CONFIG);
}
});
return Return<void>();
}
-Return<void> TunerCallback::tuneComplete(Result result, const V1_0::ProgramInfo& info) {
+Return<void> NativeCallback::tuneComplete(Result result, const V1_0::ProgramInfo& info) {
ALOGV("tuneComplete(%d)", result);
if (mHalRev > HalRevision::V1_0) {
@@ -125,87 +172,148 @@
return tuneComplete_1_1(result, info_1_1);
}
-Return<void> TunerCallback::tuneComplete_1_1(Result result, const V1_1::ProgramInfo& info) {
+Return<void> NativeCallback::tuneComplete_1_1(Result result, const V1_1::ProgramInfo& info) {
ALOGV("tuneComplete_1_1(%d)", result);
mCallbackThread.enqueue([result, info, this](JNIEnv *env) {
if (result == Result::OK) {
auto jInfo = convert::ProgramInfoFromHal(env, info);
if (jInfo == nullptr) return;
- env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onProgramInfoChanged,
- jInfo.get());
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.onProgramInfoChanged, jInfo.get());
} else {
TunerError cause = TunerError::CANCELLED;
if (result == Result::TIMEOUT) cause = TunerError::SCAN_TIMEOUT;
- env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onError, cause);
+ env->CallVoidMethod(mJCallback, gjni.TunerCallback.onError, cause);
}
});
return Return<void>();
}
-Return<void> TunerCallback::afSwitch(const V1_0::ProgramInfo& info) {
+Return<void> NativeCallback::afSwitch(const V1_0::ProgramInfo& info) {
ALOGE("Not implemented: afSwitch");
return Return<void>();
}
-Return<void> TunerCallback::afSwitch_1_1(const V1_1::ProgramInfo& info) {
+Return<void> NativeCallback::afSwitch_1_1(const V1_1::ProgramInfo& info) {
ALOGE("Not implemented: afSwitch_1_1");
return Return<void>();
}
-Return<void> TunerCallback::antennaStateChange(bool connected) {
+Return<void> NativeCallback::antennaStateChange(bool connected) {
ALOGE("Not implemented: antennaStateChange");
return Return<void>();
}
-Return<void> TunerCallback::trafficAnnouncement(bool active) {
+Return<void> NativeCallback::trafficAnnouncement(bool active) {
ALOGE("Not implemented: trafficAnnouncement");
return Return<void>();
}
-Return<void> TunerCallback::emergencyAnnouncement(bool active) {
+Return<void> NativeCallback::emergencyAnnouncement(bool active) {
ALOGE("Not implemented: emergencyAnnouncement");
return Return<void>();
}
-Return<void> TunerCallback::newMetadata(uint32_t channel, uint32_t subChannel,
+Return<void> NativeCallback::newMetadata(uint32_t channel, uint32_t subChannel,
const hidl_vec<MetaData>& metadata) {
ALOGE("Not implemented: newMetadata");
return Return<void>();
}
-Return<void> TunerCallback::backgroundScanAvailable(bool isAvailable) {
+Return<void> NativeCallback::backgroundScanAvailable(bool isAvailable) {
ALOGE("Not implemented: backgroundScanAvailable");
return Return<void>();
}
-Return<void> TunerCallback::backgroundScanComplete(ProgramListResult result) {
+Return<void> NativeCallback::backgroundScanComplete(ProgramListResult result) {
ALOGE("Not implemented: backgroundScanComplete");
return Return<void>();
}
-Return<void> TunerCallback::programListChanged() {
+Return<void> NativeCallback::programListChanged() {
ALOGE("Not implemented: programListChanged");
return Return<void>();
}
-} // namespace Tuner
+static TunerCallbackContext& getNativeContext(jlong nativeContextHandle) {
+ auto nativeContext = reinterpret_cast<TunerCallbackContext*>(nativeContextHandle);
+ LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
+ return *nativeContext;
+}
+
+/**
+ * Always lock gContextMutex when using native context.
+ */
+static TunerCallbackContext& getNativeContext(JNIEnv *env, jobject jTunerCb) {
+ return getNativeContext(env->GetLongField(jTunerCb, gjni.TunerCallback.nativeContext));
+}
+
+static jlong nativeInit(JNIEnv *env, jobject obj, jobject jTuner, jint jHalRev) {
+ ALOGV("nativeInit()");
+ AutoMutex _l(gContextMutex);
+
+ auto halRev = static_cast<HalRevision>(jHalRev);
+
+ auto ctx = new TunerCallbackContext();
+ ctx->mNativeCallback = new NativeCallback(env, jTuner, obj, halRev);
+
+ static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
+ return reinterpret_cast<jlong>(ctx);
+}
+
+static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) {
+ ALOGV("nativeFinalize()");
+ AutoMutex _l(gContextMutex);
+
+ auto ctx = reinterpret_cast<TunerCallbackContext*>(nativeContext);
+ delete ctx;
+}
+
+static void nativeDetach(JNIEnv *env, jobject obj, jlong nativeContext) {
+ ALOGV("nativeDetach()");
+ AutoMutex _l(gContextMutex);
+ auto& ctx = getNativeContext(nativeContext);
+
+ if (ctx.mNativeCallback == nullptr) return;
+ ctx.mNativeCallback->detach();
+ ctx.mNativeCallback = nullptr;
+}
+
+sp<ITunerCallback> getNativeCallback(JNIEnv *env, jobject jTunerCallback) {
+ AutoMutex _l(gContextMutex);
+ auto& ctx = getNativeContext(env, jTunerCallback);
+ return ctx.mNativeCallback;
+}
+
+static const JNINativeMethod gTunerCallbackMethods[] = {
+ { "nativeInit", "(Lcom/android/server/radio/Tuner;I)J", (void*)nativeInit },
+ { "nativeFinalize", "(J)V", (void*)nativeFinalize },
+ { "nativeDetach", "(J)V", (void*)nativeDetach },
+};
+
+} // namespace TunerCallback
} // namespace radio
} // namespace server
-void register_android_server_radio_Tuner_TunerCallback(JavaVM *vm, JNIEnv *env) {
- using namespace server::radio::Tuner;
+void register_android_server_radio_TunerCallback(JavaVM *vm, JNIEnv *env) {
+ using namespace server::radio::TunerCallback;
gvm = vm;
- auto iTunerCallbackClass = FindClassOrDie(env, "android/hardware/radio/ITunerCallback");
- gITunerCallbackClass = MakeGlobalRefOrDie(env, iTunerCallbackClass);
- gITunerCallbackMethods.onError = GetMethodIDOrDie(env, gITunerCallbackClass, "onError", "(I)V");
- gITunerCallbackMethods.onConfigurationChanged = GetMethodIDOrDie(env, gITunerCallbackClass,
+ auto tunerCbClass = FindClassOrDie(env, "com/android/server/radio/TunerCallback");
+ gjni.TunerCallback.clazz = MakeGlobalRefOrDie(env, tunerCbClass);
+ gjni.TunerCallback.nativeContext = GetFieldIDOrDie(env, tunerCbClass, "mNativeContext", "J");
+ gjni.TunerCallback.handleHwFailure = GetMethodIDOrDie(env, tunerCbClass, "handleHwFailure", "()V");
+ gjni.TunerCallback.onError = GetMethodIDOrDie(env, tunerCbClass, "onError", "(I)V");
+ gjni.TunerCallback.onConfigurationChanged = GetMethodIDOrDie(env, tunerCbClass,
"onConfigurationChanged", "(Landroid/hardware/radio/RadioManager$BandConfig;)V");
- gITunerCallbackMethods.onProgramInfoChanged = GetMethodIDOrDie(env, gITunerCallbackClass,
+ gjni.TunerCallback.onProgramInfoChanged = GetMethodIDOrDie(env, tunerCbClass,
"onProgramInfoChanged", "(Landroid/hardware/radio/RadioManager$ProgramInfo;)V");
+
+ auto res = jniRegisterNativeMethods(env, "com/android/server/radio/TunerCallback",
+ gTunerCallbackMethods, NELEM(gTunerCallbackMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
}
} // namespace android
diff --git a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
index 31208e9..35a4d69 100644
--- a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
+++ b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
@@ -14,9 +14,12 @@
* limitations under the License.
*/
-#ifndef _ANDROID_SERVER_RADIO_TUNER_TUNERCALLBACK_H
-#define _ANDROID_SERVER_RADIO_TUNER_TUNERCALLBACK_H
+// TODO(b/36863239): rename s/_Tuner_TunerCallback/_TunerCallback/, as this
+// module is no longer a part of Tuner - it's an independent java class.
+#ifndef _ANDROID_SERVER_RADIO_TUNERCALLBACK_H
+#define _ANDROID_SERVER_RADIO_TUNERCALLBACK_H
+#include "JavaRef.h"
#include "NativeCallbackThread.h"
#include "com_android_server_radio_types.h"
@@ -25,50 +28,18 @@
namespace android {
-void register_android_server_radio_Tuner_TunerCallback(JavaVM *vm, JNIEnv *env);
+void register_android_server_radio_TunerCallback(JavaVM *vm, JNIEnv *env);
namespace server {
namespace radio {
-namespace Tuner {
+namespace TunerCallback {
-class TunerCallback : public hardware::broadcastradio::V1_1::ITunerCallback {
- jobject mTuner;
- jobject mClientCallback;
- NativeCallbackThread mCallbackThread;
- HalRevision mHalRev;
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
+getNativeCallback(JNIEnv *env, jobject jTunerCallback);
- DISALLOW_COPY_AND_ASSIGN(TunerCallback);
-
-public:
- TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback, HalRevision halRev);
- virtual ~TunerCallback();
-
- void detach();
-
- virtual hardware::Return<void> hardwareFailure();
- virtual hardware::Return<void> configChange(hardware::broadcastradio::V1_0::Result result,
- const hardware::broadcastradio::V1_0::BandConfig& config);
- virtual hardware::Return<void> tuneComplete(hardware::broadcastradio::V1_0::Result result,
- const hardware::broadcastradio::V1_0::ProgramInfo& info);
- virtual hardware::Return<void> afSwitch(
- const hardware::broadcastradio::V1_0::ProgramInfo& info);
- virtual hardware::Return<void> antennaStateChange(bool connected);
- virtual hardware::Return<void> trafficAnnouncement(bool active);
- virtual hardware::Return<void> emergencyAnnouncement(bool active);
- virtual hardware::Return<void> newMetadata(uint32_t channel, uint32_t subChannel,
- const hardware::hidl_vec<hardware::broadcastradio::V1_0::MetaData>& metadata);
- virtual hardware::Return<void> tuneComplete_1_1(hardware::broadcastradio::V1_0::Result result,
- const hardware::broadcastradio::V1_1::ProgramInfo& info);
- virtual hardware::Return<void> afSwitch_1_1(const hardware::broadcastradio::V1_1::ProgramInfo& info);
- virtual hardware::Return<void> backgroundScanAvailable(bool isAvailable);
- virtual hardware::Return<void> backgroundScanComplete(
- hardware::broadcastradio::V1_1::ProgramListResult result);
- virtual hardware::Return<void> programListChanged();
-};
-
-} // namespace Tuner
+} // namespace TunerCallback
} // namespace radio
} // namespace server
} // namespace android
-#endif // _ANDROID_SERVER_RADIO_TUNER_TUNERCALLBACK_H
+#endif // _ANDROID_SERVER_RADIO_TUNERCALLBACK_H
diff --git a/services/core/jni/com_android_server_radio_convert.cpp b/services/core/jni/com_android_server_radio_convert.cpp
index 8ad899a..19abf8a 100644
--- a/services/core/jni/com_android_server_radio_convert.cpp
+++ b/services/core/jni/com_android_server_radio_convert.cpp
@@ -37,6 +37,7 @@
using V1_0::MetadataType;
using V1_0::Result;
using V1_0::Rds;
+using V1_1::ProgramListResult;
static struct {
struct {
@@ -78,23 +79,31 @@
jmethodID putBitmapFromNative;
jmethodID putClockFromNative;
} RadioMetadata;
+
+ struct {
+ jclass clazz;
+ jmethodID cstor;
+ } RuntimeException;
+
+ struct {
+ jclass clazz;
+ jmethodID cstor;
+ } ParcelableException;
} gjni;
-template <typename T>
-static bool ThrowIfFailedHidl(JNIEnv *env, const Return<T> &hidlResult) {
+bool __ThrowIfFailedHidl(JNIEnv *env, const hardware::details::return_status &hidlResult) {
if (hidlResult.isOk()) return false;
- jniThrowExceptionFmt(env, "java/lang/RuntimeException",
- "HIDL call failed: %s", hidlResult.description().c_str());
+ ThrowParcelableRuntimeException(env, "HIDL call failed: " + hidlResult.description());
return true;
}
-static bool ThrowIfFailed(JNIEnv *env, const Result halResult) {
+bool __ThrowIfFailed(JNIEnv *env, const Result halResult) {
switch (halResult) {
case Result::OK:
return false;
case Result::NOT_INITIALIZED:
- jniThrowException(env, "java/lang/RuntimeException", "Result::NOT_INITIALIZED");
+ ThrowParcelableRuntimeException(env, "Result::NOT_INITIALIZED");
return true;
case Result::INVALID_ARGUMENTS:
jniThrowException(env, "java/lang/IllegalArgumentException",
@@ -104,23 +113,43 @@
jniThrowException(env, "java/lang/IllegalStateException", "Result::INVALID_STATE");
return true;
case Result::TIMEOUT:
- jniThrowException(env, "java/lang/RuntimeException",
- "Result::TIMEOUT (unexpected here)");
+ ThrowParcelableRuntimeException(env, "Result::TIMEOUT (unexpected here)");
return true;
default:
- jniThrowExceptionFmt(env, "java/lang/RuntimeException",
- "Unknown failure, result: %d", halResult);
+ ThrowParcelableRuntimeException(env, "Unknown failure, result: "
+ + std::to_string(static_cast<int32_t>(halResult)));
return true;
}
}
-bool ThrowIfFailed(JNIEnv *env, const Return<void> &hidlResult, Result halResult) {
- return ThrowIfFailedHidl(env, hidlResult) || ThrowIfFailed(env, halResult);
+bool __ThrowIfFailed(JNIEnv *env, const ProgramListResult halResult) {
+ switch (halResult) {
+ case ProgramListResult::NOT_READY:
+ jniThrowException(env, "java/lang/IllegalStateException", "Scan is in progress");
+ return true;
+ case ProgramListResult::NOT_STARTED:
+ jniThrowException(env, "java/lang/IllegalStateException", "Scan has not been started");
+ return true;
+ case ProgramListResult::UNAVAILABLE:
+ ThrowParcelableRuntimeException(env,
+ "ProgramListResult::UNAVAILABLE (unexpected here)");
+ return true;
+ default:
+ return __ThrowIfFailed(env, static_cast<Result>(halResult));
+ }
}
-bool ThrowIfFailed(JNIEnv *env, const Return<Result> &hidlResult) {
- return ThrowIfFailedHidl(env, hidlResult)
- || ThrowIfFailed(env, static_cast<Result>(hidlResult));
+void ThrowParcelableRuntimeException(JNIEnv *env, const std::string& msg) {
+ EnvWrapper wrap(env);
+
+ auto jMsg = wrap(env->NewStringUTF(msg.c_str()));
+ auto runtimeExc = wrap(env->NewObject(gjni.RuntimeException.clazz,
+ gjni.RuntimeException.cstor, jMsg.get()));
+ auto parcelableExc = wrap(env->NewObject(gjni.ParcelableException.clazz,
+ gjni.ParcelableException.cstor, runtimeExc.get()));
+
+ auto res = env->Throw(static_cast<jthrowable>(parcelableExc.get()));
+ ALOGE_IF(res != JNI_OK, "Couldn't throw parcelable runtime exception");
}
static Rds RdsForRegion(bool rds, Region region) {
@@ -279,19 +308,27 @@
return jMetadata;
}
-JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info11) {
+static JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info10,
+ const V1_1::ProgramInfo *info11) {
ALOGV("ProgramInfoFromHal()");
EnvWrapper wrap(env);
- auto& info10 = info11.base;
auto jMetadata = MetadataFromHal(env, info10.metadata);
- auto jVendorExtension = wrap(env->NewStringUTF(info11.vendorExension.c_str()));
+ auto jVendorExtension = info11 ?
+ wrap(env->NewStringUTF(info11->vendorExension.c_str())) : nullptr;
return wrap(env->NewObject(gjni.ProgramInfo.clazz, gjni.ProgramInfo.cstor, info10.channel,
info10.subChannel, info10.tuned, info10.stereo, info10.digital, info10.signalStrength,
- jMetadata.get(), info11.flags, jVendorExtension.get()));
+ jMetadata.get(), info11 ? info11->flags : 0, jVendorExtension.get()));
}
+JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info) {
+ return ProgramInfoFromHal(env, info, nullptr);
+}
+
+JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info) {
+ return ProgramInfoFromHal(env, info.base, &info);
+}
} // namespace convert
} // namespace radio
@@ -345,6 +382,16 @@
"putBitmapFromNative", "(I[B)I");
gjni.RadioMetadata.putClockFromNative = GetMethodIDOrDie(env, radioMetadataClass,
"putClockFromNative", "(IJI)I");
+
+ auto runtimeExcClass = FindClassOrDie(env, "java/lang/RuntimeException");
+ gjni.RuntimeException.clazz = MakeGlobalRefOrDie(env, runtimeExcClass);
+ gjni.RuntimeException.cstor = GetMethodIDOrDie(env, runtimeExcClass, "<init>",
+ "(Ljava/lang/String;)V");
+
+ auto parcelableExcClass = FindClassOrDie(env, "android/os/ParcelableException");
+ gjni.ParcelableException.clazz = MakeGlobalRefOrDie(env, parcelableExcClass);
+ gjni.ParcelableException.cstor = GetMethodIDOrDie(env, parcelableExcClass, "<init>",
+ "(Ljava/lang/Throwable;)V");
}
} // namespace android
diff --git a/services/core/jni/com_android_server_radio_convert.h b/services/core/jni/com_android_server_radio_convert.h
index 811f653..6f6774b 100644
--- a/services/core/jni/com_android_server_radio_convert.h
+++ b/services/core/jni/com_android_server_radio_convert.h
@@ -34,16 +34,33 @@
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
-bool ThrowIfFailed(JNIEnv *env, const hardware::Return<V1_0::Result> &hidlResult);
-bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult, V1_0::Result halResult);
-
JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region ®ion);
V1_0::Direction DirectionToHal(bool directionDown);
+JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info);
JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info);
+
+void ThrowParcelableRuntimeException(JNIEnv *env, const std::string& msg);
+
+// These three are only for internal use by template functions below.
+bool __ThrowIfFailedHidl(JNIEnv *env,
+ const hardware::details::return_status &hidlResult);
+bool __ThrowIfFailed(JNIEnv *env, const V1_0::Result halResult);
+bool __ThrowIfFailed(JNIEnv *env, const V1_1::ProgramListResult halResult);
+
+template <typename T>
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult, const T halResult) {
+ return __ThrowIfFailedHidl(env, hidlResult) || __ThrowIfFailed(env, halResult);
+}
+
+template <typename T>
+bool ThrowIfFailed(JNIEnv *env, const hardware::Return<T> &hidlResult) {
+ return __ThrowIfFailedHidl(env, hidlResult) || __ThrowIfFailed(env, static_cast<T>(hidlResult));
+}
+
} // namespace convert
} // namespace radio
} // namespace server
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 79c9b417..c3617e0 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -42,6 +42,7 @@
int register_android_server_location_ContextHubService(JNIEnv* env);
int register_android_server_location_GnssLocationProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
+int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_tv_TvUinputBridge(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -84,6 +85,7 @@
register_android_server_location_ContextHubService(env);
register_android_server_location_GnssLocationProvider(env);
register_android_server_connectivity_Vpn(env);
+ register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 911bb2a..136d335 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -254,6 +254,8 @@
private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
+ private static final String TAG_PASSWORD_VALIDITY = "password-validity";
+
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
@@ -478,6 +480,8 @@
public static class DevicePolicyData {
@NonNull PasswordMetrics mActivePasswordMetrics = new PasswordMetrics();
int mFailedPasswordAttempts = 0;
+ boolean mPasswordStateHasBeenSetSinceBoot = false;
+ boolean mPasswordValidAtLastCheckpoint = false;
int mUserHandle;
int mPasswordOwner = -1;
@@ -2574,19 +2578,14 @@
out.endTag(null, "failed-password-attempts");
}
- // Don't save metrics for FBE devices
- final PasswordMetrics metrics = policy.mActivePasswordMetrics;
- if (!mInjector.storageManagerIsFileBasedEncryptionEnabled() && !metrics.isDefault()) {
- out.startTag(null, "active-password");
- out.attribute(null, "quality", Integer.toString(metrics.quality));
- out.attribute(null, "length", Integer.toString(metrics.length));
- out.attribute(null, "uppercase", Integer.toString(metrics.upperCase));
- out.attribute(null, "lowercase", Integer.toString(metrics.lowerCase));
- out.attribute(null, "letters", Integer.toString(metrics.letters));
- out.attribute(null, "numeric", Integer.toString(metrics.numeric));
- out.attribute(null, "symbols", Integer.toString(metrics.symbols));
- out.attribute(null, "nonletter", Integer.toString(metrics.nonLetter));
- out.endTag(null, "active-password");
+ // For FDE devices only, we save this flag so we can report on password sufficiency
+ // before the user enters their password for the first time after a reboot. For
+ // security reasons, we don't want to store the full set of active password metrics.
+ if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
+ out.startTag(null, TAG_PASSWORD_VALIDITY);
+ out.attribute(null, ATTR_VALUE,
+ Boolean.toString(policy.mPasswordValidAtLastCheckpoint));
+ out.endTag(null, TAG_PASSWORD_VALIDITY);
}
for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) {
@@ -2864,19 +2863,14 @@
} else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) {
policy.mInitBundle = PersistableBundle.restoreFromXml(parser);
} else if ("active-password".equals(tag)) {
- if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
- // Remove this from FBE devices
- needsRewrite = true;
- } else {
- final PasswordMetrics m = policy.mActivePasswordMetrics;
- m.quality = Integer.parseInt(parser.getAttributeValue(null, "quality"));
- m.length = Integer.parseInt(parser.getAttributeValue(null, "length"));
- m.upperCase = Integer.parseInt(parser.getAttributeValue(null, "uppercase"));
- m.lowerCase = Integer.parseInt(parser.getAttributeValue(null, "lowercase"));
- m.letters = Integer.parseInt(parser.getAttributeValue(null, "letters"));
- m.numeric = Integer.parseInt(parser.getAttributeValue(null, "numeric"));
- m.symbols = Integer.parseInt(parser.getAttributeValue(null, "symbols"));
- m.nonLetter = Integer.parseInt(parser.getAttributeValue(null, "nonletter"));
+ // Remove password metrics from saved settings, as we no longer wish to store
+ // these on disk
+ needsRewrite = true;
+ } else if (TAG_PASSWORD_VALIDITY.equals(tag)) {
+ if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) {
+ // This flag is only used for FDE devices
+ policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
}
} else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) {
policy.mPasswordTokenHandle = Long.parseLong(
@@ -3453,11 +3447,24 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.quality != quality) {
ap.minimumPasswordMetrics.quality = quality;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
}
+ /**
+ * Updates flag in memory that tells us whether the user's password currently satisfies the
+ * requirements set by all of the user's active admins. This should be called before
+ * {@link #saveSettingsLocked} whenever the password or the admin policies have changed.
+ */
+ @GuardedBy("DevicePolicyManagerService.this")
+ private void updatePasswordValidityCheckpointLocked(int userHandle) {
+ DevicePolicyData policy = getUserData(userHandle);
+ policy.mPasswordValidAtLastCheckpoint = isActivePasswordSufficientForUserLocked(
+ policy, policy.mUserHandle, false);
+ }
+
@Override
public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) {
if (!mHasFeature) {
@@ -3540,6 +3547,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.length != length) {
ap.minimumPasswordMetrics.length = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3584,6 +3592,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3796,6 +3805,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.upperCase != length) {
ap.minimumPasswordMetrics.upperCase = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3837,6 +3847,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.lowerCase != length) {
ap.minimumPasswordMetrics.lowerCase = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3881,6 +3892,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.letters != length) {
ap.minimumPasswordMetrics.letters = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3928,6 +3940,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.numeric != length) {
ap.minimumPasswordMetrics.numeric = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -3975,6 +3988,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.symbols != length) {
ap.minimumPasswordMetrics.symbols = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -4022,6 +4036,7 @@
who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent);
if (ap.minimumPasswordMetrics.nonLetter != length) {
ap.minimumPasswordMetrics.nonLetter = length;
+ updatePasswordValidityCheckpointLocked(mInjector.userHandleGetCallingUserId());
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
}
}
@@ -4093,6 +4108,16 @@
DevicePolicyData policy, int userHandle, boolean parent) {
enforceUserUnlocked(userHandle, parent);
+ if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()
+ && !policy.mPasswordStateHasBeenSetSinceBoot) {
+ // Before user enters their password for the first time after a reboot, return the
+ // value of this flag, which tells us whether the password was valid the last time
+ // settings were saved. If DPC changes password requirements on boot so that the
+ // current password no longer meets the requirements, this value will be stale until
+ // the next time the password is entered.
+ return policy.mPasswordValidAtLastCheckpoint;
+ }
+
final int requiredPasswordQuality = getPasswordQuality(null, userHandle, parent);
if (policy.mActivePasswordMetrics.quality < requiredPasswordQuality) {
return false;
@@ -5436,6 +5461,7 @@
DevicePolicyData policy = getUserData(userHandle);
synchronized (this) {
policy.mActivePasswordMetrics = metrics;
+ policy.mPasswordStateHasBeenSetSinceBoot = true;
}
}
@@ -5460,6 +5486,7 @@
try {
synchronized (this) {
policy.mFailedPasswordAttempts = 0;
+ updatePasswordValidityCheckpointLocked(userId);
saveSettingsLocked(userId);
updatePasswordExpirationsLocked(userId);
setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java
new file mode 100644
index 0000000..343d237
--- /dev/null
+++ b/services/net/java/android/net/util/SharedLog.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.StringJoiner;
+
+
+/**
+ * Class to centralize logging functionality for tethering.
+ *
+ * All access to class methods other than dump() must be on the same thread.
+ *
+ * @hide
+ */
+public class SharedLog {
+ private final static int DEFAULT_MAX_RECORDS = 500;
+ private final static String COMPONENT_DELIMITER = ".";
+
+ private enum Category {
+ NONE,
+ ERROR,
+ MARK,
+ WARN,
+ };
+
+ private final LocalLog mLocalLog;
+ // The tag to use for output to the system log. This is not output to the
+ // LocalLog because that would be redundant.
+ private final String mTag;
+ // The component (or subcomponent) of a system that is sharing this log.
+ // This can grow in depth if components call forSubComponent() to obtain
+ // their SharedLog instance. The tag is not included in the component for
+ // brevity.
+ private final String mComponent;
+
+ public SharedLog(String tag) {
+ this(DEFAULT_MAX_RECORDS, tag);
+ }
+
+ public SharedLog(int maxRecords, String tag) {
+ this(new LocalLog(maxRecords), tag, tag);
+ }
+
+ private SharedLog(LocalLog localLog, String tag, String component) {
+ mLocalLog = localLog;
+ mTag = tag;
+ mComponent = component;
+ }
+
+ public SharedLog forSubComponent(String component) {
+ if (!isRootLogInstance()) {
+ component = mComponent + COMPONENT_DELIMITER + component;
+ }
+ return new SharedLog(mLocalLog, mTag, component);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
+ }
+
+ //////
+ // Methods that both log an entry and emit it to the system log.
+ //////
+
+ public void e(Exception e) {
+ Log.e(mTag, record(Category.ERROR, e.toString()));
+ }
+
+ public void e(String msg) {
+ Log.e(mTag, record(Category.ERROR, msg));
+ }
+
+ public void i(String msg) {
+ Log.i(mTag, record(Category.NONE, msg));
+ }
+
+ public void w(String msg) {
+ Log.w(mTag, record(Category.WARN, msg));
+ }
+
+ //////
+ // Methods that only log an entry (and do NOT emit to the system log).
+ //////
+
+ public void log(String msg) {
+ record(Category.NONE, msg);
+ }
+
+ public void mark(String msg) {
+ record(Category.MARK, msg);
+ }
+
+ private String record(Category category, String msg) {
+ final String entry = logLine(category, msg);
+ mLocalLog.log(entry);
+ return entry;
+ }
+
+ private String logLine(Category category, String msg) {
+ final StringJoiner sj = new StringJoiner(" ");
+ if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
+ if (category != Category.NONE) sj.add(category.toString());
+ return sj.add(msg).toString();
+ }
+
+ // Check whether this SharedLog instance is nominally the top level in
+ // a potential hierarchy of shared logs (the root of a tree),
+ // or is a subcomponent within the hierarchy.
+ private boolean isRootLogInstance() {
+ return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
+ }
+}
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 267d2a6..0812783 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -99,7 +99,7 @@
when(mMockContext.getPackageManager()).thenReturn(mPm);
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
- upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
+ upgrade.targetSdkVersion = Build.VERSION_CODES.O;
try {
when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
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 0f8c815..2c9c114 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -119,7 +119,7 @@
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
final ApplicationInfo upgrade = new ApplicationInfo();
- upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
+ upgrade.targetSdkVersion = Build.VERSION_CODES.O;
when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
@@ -1232,6 +1232,15 @@
}
@Test
+ public void testBadgingForUserAll() throws Exception {
+ try {
+ mHelper.badgingEnabled(UserHandle.ALL);
+ } catch (Exception e) {
+ fail("just don't throw");
+ }
+ }
+
+ @Test
public void testBadgingOverrideUserIsolation() throws Exception {
Secure.putIntForUser(getContext().getContentResolver(),
Secure.NOTIFICATION_BADGING, 0,
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index f281bd7..33e4165 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -154,7 +154,7 @@
withUserSetupCompleteValue(true);
boolean useWakeLock = false;
- assertTrue(mGestureLauncherService.handleCameraLaunchGesture(useWakeLock, FAKE_SOURCE));
+ assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
}
@@ -163,7 +163,7 @@
withUserSetupCompleteValue(false);
boolean useWakeLock = false;
- assertFalse(mGestureLauncherService.handleCameraLaunchGesture(useWakeLock, FAKE_SOURCE));
+ assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
index 8afe853..72820f1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ActionReplacingCallbackTest.java
@@ -25,6 +25,9 @@
import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -45,12 +48,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
/**
@@ -63,15 +67,50 @@
private static final int NON_ROOT_NODE_ID = 0xAAAA5555;
private static final long INTERROGATING_TID = 0x1234FACE;
- private static final AccessibilityAction[] ACTIONS_FROM_REPLACER =
- {ACTION_CLICK, ACTION_EXPAND};
- private static final AccessibilityAction[] A11Y_FOCUS_ACTIONS =
- {ACTION_ACCESSIBILITY_FOCUS, ACTION_CLEAR_ACCESSIBILITY_FOCUS};
// We expect both the replacer actions and a11y focus actions to appear
private static final AccessibilityAction[] REQUIRED_ACTIONS_ON_ROOT_TO_SERVICE =
{ACTION_CLICK, ACTION_EXPAND, ACTION_ACCESSIBILITY_FOCUS,
ACTION_CLEAR_ACCESSIBILITY_FOCUS};
+ private static final Matcher<AccessibilityNodeInfo> HAS_NO_ACTIONS =
+ new BaseMatcher<AccessibilityNodeInfo>() {
+ @Override
+ public boolean matches(Object o) {
+ AccessibilityNodeInfo node = (AccessibilityNodeInfo) o;
+ if (!node.getActionList().isEmpty()) return false;
+ return (!node.isScrollable() && !node.isLongClickable() && !node.isClickable()
+ && !node.isContextClickable() && !node.isDismissable() && !node.isFocusable());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Has no actions");
+ }
+ };
+
+ private static final Matcher<AccessibilityNodeInfo> HAS_EXPECTED_ACTIONS_ON_ROOT =
+ new BaseMatcher<AccessibilityNodeInfo>() {
+ @Override
+ public boolean matches(Object o) {
+ AccessibilityNodeInfo node = (AccessibilityNodeInfo) o;
+ List<AccessibilityAction> actions = node.getActionList();
+ if ((actions.size() != 4) || !actions.contains(ACTION_CLICK)
+ || !actions.contains(ACTION_EXPAND)
+ || !actions.contains(ACTION_ACCESSIBILITY_FOCUS)) {
+ return false;
+ }
+ return (!node.isScrollable() && !node.isLongClickable()
+ && !node.isLongClickable() && node.isClickable()
+ && !node.isContextClickable() && !node.isDismissable()
+ && !node.isFocusable());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("Has only 4 actions expected on root");
+ }
+ };
+
@Mock IAccessibilityInteractionConnectionCallback mMockServiceCallback;
@Mock IAccessibilityInteractionConnection mMockReplacerConnection;
@@ -118,9 +157,10 @@
eq(INTERACTION_ID));
AccessibilityNodeInfo infoSentToService = mInfoCaptor.getValue();
assertEquals(AccessibilityNodeInfo.ROOT_NODE_ID, infoSentToService.getSourceNodeId());
- assertInfoHasExactlyTheseActions(infoSentToService, REQUIRED_ACTIONS_ON_ROOT_TO_SERVICE);
+ assertThat(infoSentToService, HAS_EXPECTED_ACTIONS_ON_ROOT);
}
+ @Test
public void testCallbacks_singleNonrootNodeThenReplacer_returnsNodeWithNoActions()
throws RemoteException {
AccessibilityNodeInfo infoFromApp = AccessibilityNodeInfo.obtain();
@@ -136,9 +176,10 @@
eq(INTERACTION_ID));
AccessibilityNodeInfo infoSentToService = mInfoCaptor.getValue();
assertEquals(NON_ROOT_NODE_ID, infoSentToService.getSourceNodeId());
- assertTrue(infoSentToService.getActionList().isEmpty());
+ assertThat(infoSentToService, HAS_NO_ACTIONS);
}
+ @Test
public void testCallbacks_replacerThenSingleRootNode_returnsNodeWithReplacedActions()
throws RemoteException {
mActionReplacingCallback.setFindAccessibilityNodeInfosResult(getReplacerNodes(),
@@ -154,9 +195,10 @@
eq(INTERACTION_ID));
AccessibilityNodeInfo infoSentToService = mInfoCaptor.getValue();
assertEquals(AccessibilityNodeInfo.ROOT_NODE_ID, infoSentToService.getSourceNodeId());
- assertInfoHasExactlyTheseActions(infoSentToService, REQUIRED_ACTIONS_ON_ROOT_TO_SERVICE);
+ assertThat(infoSentToService, HAS_EXPECTED_ACTIONS_ON_ROOT);
}
+ @Test
public void testCallbacks_multipleNodesThenReplacer_clearsActionsAndAddsSomeToRoot()
throws RemoteException {
mActionReplacingCallback
@@ -173,11 +215,11 @@
mInfoListCaptor.getValue(), AccessibilityNodeInfo.ROOT_NODE_ID);
AccessibilityNodeInfo otherInfoSentToService = getNodeWithIdFromList(
mInfoListCaptor.getValue(), NON_ROOT_NODE_ID);
- assertInfoHasExactlyTheseActions(
- rootInfoSentToService, REQUIRED_ACTIONS_ON_ROOT_TO_SERVICE);
- assertTrue(otherInfoSentToService.getActionList().isEmpty());
+ assertThat(rootInfoSentToService, HAS_EXPECTED_ACTIONS_ON_ROOT);
+ assertThat(otherInfoSentToService, HAS_NO_ACTIONS);
}
+ @Test
public void testCallbacks_replacerThenMultipleNodes_clearsActionsAndAddsSomeToRoot()
throws RemoteException {
mActionReplacingCallback.setFindAccessibilityNodeInfosResult(getReplacerNodes(),
@@ -194,18 +236,18 @@
mInfoListCaptor.getValue(), AccessibilityNodeInfo.ROOT_NODE_ID);
AccessibilityNodeInfo otherInfoSentToService = getNodeWithIdFromList(
mInfoListCaptor.getValue(), NON_ROOT_NODE_ID);
- assertInfoHasExactlyTheseActions(
- rootInfoSentToService, REQUIRED_ACTIONS_ON_ROOT_TO_SERVICE);
- assertTrue(otherInfoSentToService.getActionList().isEmpty());
+ assertThat(rootInfoSentToService, HAS_EXPECTED_ACTIONS_ON_ROOT);
+ assertThat(otherInfoSentToService, HAS_NO_ACTIONS);
}
+ @Test
public void testConstructor_actionReplacerThrowsException_passesDataToService()
throws RemoteException {
doThrow(RemoteException.class).when(mMockReplacerConnection)
.findAccessibilityNodeInfoByAccessibilityId(eq(AccessibilityNodeInfo.ROOT_NODE_ID),
- (Region) anyObject(), mInteractionIdCaptor.capture(),
- eq(mActionReplacingCallback), eq(0), eq(INTERROGATING_PID),
- eq(INTERROGATING_TID), (MagnificationSpec) anyObject(), eq(null));
+ (Region) anyObject(), anyInt(), (ActionReplacingCallback) anyObject(),
+ eq(0), eq(INTERROGATING_PID), eq(INTERROGATING_TID),
+ (MagnificationSpec) anyObject(), eq(null));
ActionReplacingCallback actionReplacingCallback = new ActionReplacingCallback(
mMockServiceCallback, mMockReplacerConnection, INTERACTION_ID, INTERROGATING_PID,
INTERROGATING_TID);
@@ -214,16 +256,17 @@
AccessibilityNodeInfo infoFromApp = AccessibilityNodeInfo.obtain();
infoFromApp.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID, APP_WINDOW_ID);
infoFromApp.addAction(ACTION_CONTEXT_CLICK);
+ infoFromApp.setContextClickable(true);
actionReplacingCallback.setFindAccessibilityNodeInfoResult(infoFromApp, INTERACTION_ID);
verify(mMockServiceCallback).setFindAccessibilityNodeInfoResult(mInfoCaptor.capture(),
eq(INTERACTION_ID));
AccessibilityNodeInfo infoSentToService = mInfoCaptor.getValue();
assertEquals(AccessibilityNodeInfo.ROOT_NODE_ID, infoSentToService.getSourceNodeId());
- assertEquals(1, infoSentToService.getActionList().size());
- assertEquals(ACTION_CONTEXT_CLICK, infoSentToService.getActionList().get(0));
+ assertThat(infoSentToService, HAS_NO_ACTIONS);
}
+ @Test
public void testSetPerformAccessibilityActionResult_actsAsPassThrough() throws RemoteException {
mActionReplacingCallback.setPerformAccessibilityActionResult(true, INTERACTION_ID);
verify(mMockServiceCallback).setPerformAccessibilityActionResult(true, INTERACTION_ID);
@@ -236,9 +279,9 @@
AccessibilityNodeInfo root = AccessibilityNodeInfo.obtain();
root.setSourceNodeId(AccessibilityNodeInfo.ROOT_NODE_ID,
AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID);
- for (AccessibilityAction action : ACTIONS_FROM_REPLACER) {
- root.addAction(action);
- }
+ root.addAction(ACTION_CLICK);
+ root.addAction(ACTION_EXPAND);
+ root.setClickable(true);
// Second node should have no effect
AccessibilityNodeInfo other = AccessibilityNodeInfo.obtain();
@@ -249,13 +292,6 @@
return Arrays.asList(root, other);
}
- private void assertInfoHasExactlyTheseActions(
- AccessibilityNodeInfo info, AccessibilityAction[] actions) {
- List<AccessibilityAction> nodeActions = info.getActionList();
- assertEquals(new HashSet<AccessibilityAction>(nodeActions),
- new HashSet<AccessibilityAction>(Arrays.asList(actions)));
- }
-
private AccessibilityNodeInfo getNodeWithIdFromList(
List<AccessibilityNodeInfo> infos, long id) {
for (AccessibilityNodeInfo info : infos) {
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 2663aaf..f4c4ea9 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -16,10 +16,10 @@
package com.android.server.appwidget;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -35,10 +35,8 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IntentSender;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutServiceInternal;
-import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.test.InstrumentationTestCase;
@@ -113,19 +111,18 @@
ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
// Set up users.
when(mMockShortcutService.requestPinAppWidget(anyString(),
- any(AppWidgetProviderInfo.class), any(Bundle.class), any(IntentSender.class), anyInt()))
+ any(AppWidgetProviderInfo.class), eq(null), eq(null), anyInt()))
.thenReturn(true);
assertTrue(mManager.requestPinAppWidget(provider, null, null));
final ArgumentCaptor<AppWidgetProviderInfo> providerCaptor =
ArgumentCaptor.forClass(AppWidgetProviderInfo.class);
verify(mMockShortcutService, times(1)).requestPinAppWidget(anyString(),
- providerCaptor.capture(), any(null), eq(null), anyInt());
+ providerCaptor.capture(), eq(null), eq(null), anyInt());
assertEquals(provider, providerCaptor.getValue().provider);
}
public void testIsRequestPinAppWidgetSupported() {
- ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
// Set up users.
when(mMockShortcutService.isRequestPinItemSupported(anyInt(), anyInt()))
.thenReturn(true, false);
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java
new file mode 100644
index 0000000..4e3de64
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupUtilsTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class FullBackupUtilsTest {
+ @Mock private ParcelFileDescriptor mParcelFileDescriptorMock;
+ @Mock private OutputStream mOutputStreamMock;
+ private File mTemporaryFile;
+ private ByteArrayOutputStream mByteArrayOutputStream;
+ private ParcelFileDescriptor mTemporaryFileDescriptor;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mTemporaryFile = File.createTempFile("backup-data", ".txt");
+ mByteArrayOutputStream = new ByteArrayOutputStream();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mTemporaryFileDescriptor != null) {
+ mTemporaryFileDescriptor.close();
+ }
+ if (mTemporaryFile != null) {
+ mTemporaryFile.delete();
+ }
+ }
+
+ @Test
+ public void routeSocketDataToOutput_inPipeIsNull_throwsNPE() throws Exception {
+ try {
+ FullBackupUtils.routeSocketDataToOutput(null, mOutputStreamMock);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test
+ public void routeSocketDataToOutput_outNull_throwsNPE() throws Exception {
+ try {
+ FullBackupUtils.routeSocketDataToOutput(mParcelFileDescriptorMock, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ @Test
+ public void routeSocketDataToOutput_emptyInput_throwsEOFException() throws Exception {
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ try {
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mOutputStreamMock);
+ fail();
+ } catch (EOFException expected) {
+ }
+
+ verifyZeroInteractions(mOutputStreamMock);
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_incompleteChunkSizeInput_throwsEOFException()
+ throws Exception {
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeByte(100);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ try {
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mOutputStreamMock);
+ fail();
+ } catch (EOFException expected) {
+ }
+
+ verifyZeroInteractions(mOutputStreamMock);
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_validEmptyInput_doesNotWriteAnything() throws Exception {
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(0);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor, mOutputStreamMock);
+
+ verifyZeroInteractions(mOutputStreamMock);
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_notEnoughData_throwsEOFException() throws Exception {
+ byte[] data = createFakeDataArray(100);
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(data.length + 1);
+ outputStream.write(data);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ try {
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mByteArrayOutputStream);
+ fail();
+ } catch (EOFException expected) {
+ }
+
+ verify(mOutputStreamMock, never()).close();
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_oneSmallChunk_writesOutputCorrectly() throws Exception {
+ byte[] data = createFakeDataArray(100);
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(data.length);
+ outputStream.write(data);
+ outputStream.writeInt(0);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mByteArrayOutputStream);
+
+ assertThat(mByteArrayOutputStream.toByteArray()).isEqualTo(data);
+ verify(mOutputStreamMock, never()).close();
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_oneLargeChunk_writesOutputCorrectly() throws Exception {
+ byte[] data = createFakeDataArray(128000);
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(data.length);
+ outputStream.write(data);
+ outputStream.writeInt(0);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mByteArrayOutputStream);
+
+ assertThat(mByteArrayOutputStream.toByteArray()).isEqualTo(data);
+ verify(mOutputStreamMock, never()).close();
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_twoSmallChunks_writesOutputCorrectly() throws Exception {
+ byte[] data = createFakeDataArray(200);
+ int chunk1Length = 97;
+ int chunk2Length = data.length - chunk1Length;
+
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(chunk1Length);
+ outputStream.write(data, 0, chunk1Length);
+ outputStream.writeInt(chunk2Length);
+ outputStream.write(data, chunk1Length, chunk2Length);
+ outputStream.writeInt(0);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mByteArrayOutputStream);
+
+ assertThat(mByteArrayOutputStream.toByteArray()).isEqualTo(data);
+ verify(mOutputStreamMock, never()).close();
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ @Test
+ public void routeSocketDataToOutput_twoLargeChunks_writesOutputCorrectly() throws Exception {
+ byte[] data = createFakeDataArray(256000);
+ int chunk1Length = 127313;
+ int chunk2Length = data.length - chunk1Length;
+
+ DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(mTemporaryFile));
+ outputStream.writeInt(chunk1Length);
+ outputStream.write(data, 0, chunk1Length);
+ outputStream.writeInt(chunk2Length);
+ outputStream.write(data, chunk1Length, chunk2Length);
+ outputStream.writeInt(0);
+ outputStream.close();
+
+ mTemporaryFileDescriptor = ParcelFileDescriptor.open(mTemporaryFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+
+ FullBackupUtils.routeSocketDataToOutput(mTemporaryFileDescriptor,
+ mByteArrayOutputStream);
+
+ assertThat(mByteArrayOutputStream.toByteArray()).isEqualTo(data);
+ verify(mOutputStreamMock, never()).close();
+ assertThat(mTemporaryFileDescriptor.getFileDescriptor().valid()).isTrue();
+ }
+
+ private static byte[] createFakeDataArray(int length) {
+ byte[] data = new byte[length];
+ new Random(3742).nextBytes(data);
+ return data;
+ }
+}
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 c2b0ea5..fb74d05 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,6 +26,7 @@
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.PasswordMetrics;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -3836,6 +3837,80 @@
assertTrue(dpm.clearResetPasswordToken(admin1));
}
+ public void testIsActivePasswordSufficient() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ mContext.packageName = admin1.getPackageName();
+ setupDeviceOwner();
+
+ dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX);
+ dpm.setPasswordMinimumLength(admin1, 8);
+ dpm.setPasswordMinimumLetters(admin1, 6);
+ dpm.setPasswordMinimumLowerCase(admin1, 3);
+ dpm.setPasswordMinimumUpperCase(admin1, 1);
+ dpm.setPasswordMinimumNonLetter(admin1, 1);
+ dpm.setPasswordMinimumNumeric(admin1, 1);
+ dpm.setPasswordMinimumSymbols(admin1, 0);
+
+ PasswordMetrics passwordMetricsNoSymbols = new PasswordMetrics(
+ DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
+ 8, 2,
+ 6, 1,
+ 0, 1);
+
+ setActivePasswordState(passwordMetricsNoSymbols);
+ assertTrue(dpm.isActivePasswordSufficient());
+
+ initializeDpms();
+ reset(mContext.spiedContext);
+ assertTrue(dpm.isActivePasswordSufficient());
+
+ // This call simulates the user entering the password for the first time after a reboot.
+ // This causes password metrics to be reloaded into memory. Until this happens,
+ // dpm.isActivePasswordSufficient() will continue to return its last checkpointed value,
+ // even if the DPC changes password requirements so that the password no longer meets the
+ // requirements. This is a known limitation of the current implementation of
+ // isActivePasswordSufficient() - see b/34218769.
+ setActivePasswordState(passwordMetricsNoSymbols);
+ assertTrue(dpm.isActivePasswordSufficient());
+
+ dpm.setPasswordMinimumSymbols(admin1, 1);
+ // This assertion would fail if we had not called setActivePasswordState() again after
+ // initializeDpms() - see previous comment.
+ assertFalse(dpm.isActivePasswordSufficient());
+
+ initializeDpms();
+ reset(mContext.spiedContext);
+ assertFalse(dpm.isActivePasswordSufficient());
+
+ PasswordMetrics passwordMetricsWithSymbols = new PasswordMetrics(
+ DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 9,
+ 7, 2,
+ 5, 1,
+ 1, 2);
+
+ setActivePasswordState(passwordMetricsWithSymbols);
+ assertTrue(dpm.isActivePasswordSufficient());
+ }
+
+ private void setActivePasswordState(PasswordMetrics passwordMetrics) {
+ int userHandle = UserHandle.getUserId(mContext.binder.callingUid);
+ final long ident = mContext.binder.clearCallingIdentity();
+ try {
+ dpm.setActivePasswordState(passwordMetrics, userHandle);
+ dpm.reportPasswordChanged(userHandle);
+
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED);
+ intent.setComponent(admin1);
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(mContext.binder.callingUid));
+
+ verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+ MockUtils.checkIntent(intent),
+ MockUtils.checkUserHandle(userHandle));
+ } finally {
+ mContext.binder.restoreCallingIdentity(ident);
+ }
+ }
+
public void testIsCurrentInputMethodSetByOwnerForDeviceOwner() throws Exception {
final String currentIme = Settings.Secure.DEFAULT_INPUT_METHOD;
final Uri currentImeUri = Settings.Secure.getUriFor(currentIme);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index a2b4568..7de46d9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -31,6 +31,7 @@
import android.os.FileUtils;
import android.os.IProgressListener;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.security.KeyStore;
import android.test.AndroidTestCase;
@@ -85,7 +86,7 @@
mDevicePolicyManager = mock(DevicePolicyManager.class);
mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
- mDevicePolicyManager);
+ mDevicePolicyManager, mock(StorageManager.class));
mStorage = new LockSettingsStorageTestable(mContext,
new File(getContext().getFilesDir(), "locksettings"));
File storageDir = mStorage.mStorageDir;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 4665441..449a54c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -28,6 +28,7 @@
import android.database.sqlite.SQLiteDatabase;
import android.os.FileUtils;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.test.AndroidTestCase;
import com.android.internal.widget.LockPatternUtils;
@@ -69,7 +70,8 @@
when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
- mock(NotificationManager.class), mock(DevicePolicyManager.class));
+ mock(NotificationManager.class), mock(DevicePolicyManager.class),
+ mock(StorageManager.class));
mStorage = new LockSettingsStorageTestable(context,
new File(getContext().getFilesDir(), "locksettings"));
mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
@@ -336,7 +338,7 @@
assertArrayEquals(data, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
assertEquals(null, mStorage.readSyntheticPasswordState(0, 1234L, "state"));
- mStorage.deleteSyntheticPasswordState(10, 1234L, "state", true);
+ mStorage.deleteSyntheticPasswordState(10, 1234L, "state");
assertEquals(null, mStorage.readSyntheticPasswordState(10, 1234L, "state"));
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index c76a83e..8da33a8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -21,19 +21,23 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.os.UserManager;
+import android.os.storage.StorageManager;
public class MockLockSettingsContext extends ContextWrapper {
private UserManager mUserManager;
private NotificationManager mNotificationManager;
private DevicePolicyManager mDevicePolicyManager;
+ private StorageManager mStorageManager;
public MockLockSettingsContext(Context base, UserManager userManager,
- NotificationManager notificationManager, DevicePolicyManager devicePolicyManager) {
+ NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
+ StorageManager storageManager) {
super(base);
mUserManager = userManager;
mNotificationManager = notificationManager;
mDevicePolicyManager = devicePolicyManager;
+ mStorageManager = storageManager;
}
@Override
@@ -44,6 +48,8 @@
return mNotificationManager;
} else if (DEVICE_POLICY_SERVICE.equals(name)) {
return mDevicePolicyManager;
+ } else if (STORAGE_SERVICE.equals(name)) {
+ return mStorageManager;
} else {
throw new RuntimeException("System service not mocked: " + name);
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
index ac46bae..89e18b4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockStorageManager.java
@@ -500,4 +500,9 @@
throw new UnsupportedOperationException();
}
+ @Override
+ public void secdiscard(String path) throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 1284b1b..0e8960e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -498,6 +498,7 @@
pkg.mRestrictedAccountType = "foo19";
pkg.mRequiredAccountType = "foo20";
pkg.mOverlayTarget = "foo21";
+ pkg.mOverlayPriority = 100;
pkg.mSigningKeys = new ArraySet<>();
pkg.mUpgradeKeySets = new ArraySet<>();
pkg.mKeySetMapping = new ArrayMap<>();
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
index a8c39c4..6706969 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/PreloadAppsInstallerTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -32,6 +33,7 @@
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import com.android.internal.util.test.FakeSettingsProvider;
@@ -40,20 +42,20 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.File;
import java.util.ArrayList;
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class PreloadAppsInstallerTest {
private static final int TEST_DEMO_USER = 111;
- private @Mock Context mContext;
+ private Context mContext;
private @Mock IPackageManager mIpm;
private MockContentResolver mContentResolver;
private File mPreloadsAppsDirectory;
@@ -66,6 +68,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
@@ -89,7 +92,9 @@
@After
public void tearDown() {
- FileUtils.deleteContentsAndDir(mPreloadsAppsDirectory);
+ if (mPreloadsAppsDirectory != null) {
+ FileUtils.deleteContentsAndDir(mPreloadsAppsDirectory);
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
index ce5b8cb..2e13d29 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -38,6 +38,7 @@
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
@@ -59,6 +60,7 @@
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.util.ArrayMap;
@@ -72,9 +74,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.compat.ArgumentMatcher;
@@ -82,7 +84,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-@RunWith(JUnit4.class)
+@RunWith(AndroidJUnit4.class)
@SmallTest
public class RetailDemoModeServiceTest {
private static final int TEST_DEMO_USER = 111;
@@ -90,7 +92,7 @@
private static final String TEST_CAMERA_PKG = "test.cameraapp";
private static final String TEST_PRELOADS_DIR_NAME = "test_preloads";
- private @Mock Context mContext;
+ private Context mContext;
private @Mock UserManager mUm;
private @Mock PackageManager mPm;
private @Mock IPackageManager mIpm;
@@ -113,12 +115,11 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- Context originalContext = InstrumentationRegistry.getContext();
- when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
- when(mContext.getResources()).thenReturn(originalContext.getResources());
+ mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
when(mContext.getSystemServiceName(eq(JobScheduler.class))).thenReturn(
Context.JOB_SCHEDULER_SERVICE);
when(mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(mJobScheduler);
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm);
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
mContactsProvider = new MockContactsProvider(mContext);
@@ -129,12 +130,10 @@
mTestPreloadsDir = new File(InstrumentationRegistry.getContext().getFilesDir(),
TEST_PRELOADS_DIR_NAME);
- Settings.Global.putString(mContentResolver,
- Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, "");
- Settings.Global.putInt(mContentResolver,
- Settings.Global.DEVICE_PROVISIONED, 1);
- Settings.Global.putInt(mContentResolver,
- Settings.Global.DEVICE_DEMO_MODE, 1);
+ Settings.Global.putString(mContentResolver, Settings.Global.RETAIL_DEMO_MODE_CONSTANTS, "");
+ Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 1);
+ Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 1);
+
// Initialize RetailDemoModeService
mInjector = new TestInjector();
mService = new RetailDemoModeService(mInjector);
@@ -143,7 +142,9 @@
@After
public void tearDown() {
- FileUtils.deleteContentsAndDir(mTestPreloadsDir);
+ if (mTestPreloadsDir != null) {
+ FileUtils.deleteContentsAndDir(mTestPreloadsDir);
+ }
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index dcbedb6..da3b9c9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -97,7 +97,8 @@
final WindowTestUtils.TestAppWindowContainerController controller =
createAppWindowController();
controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true);
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false);
waitUntilHandlersIdle();
final AppWindowToken atoken = controller.getAppWindowToken(mDisplayContent);
assertHasStartingWindow(atoken);
@@ -113,11 +114,12 @@
final WindowTestUtils.TestAppWindowContainerController controller2 =
createAppWindowController();
controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true);
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false);
waitUntilHandlersIdle();
controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
- true, true, false, true);
+ true, true, false, true, false);
waitUntilHandlersIdle();
assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
@@ -134,10 +136,11 @@
// Surprise, ...! Transfer window in the middle of the creation flow.
controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
- true, true, false, true);
+ true, true, false, true, false);
});
controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
- android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true);
+ android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+ false);
waitUntilHandlersIdle();
assertNoStartingWindow(controller1.getAppWindowToken(mDisplayContent));
assertHasStartingWindow(controller2.getAppWindowToken(mDisplayContent));
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index f9254ad..856e940 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -34,6 +34,7 @@
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.util.SparseIntArray;
import java.util.Arrays;
import java.util.LinkedList;
@@ -239,7 +240,7 @@
@Test
@Ignore
public void testFocusedWindowMultipleDisplays() throws Exception {
- // Create a focusable window and check that focus is calcualted correctly
+ // Create a focusable window and check that focus is calculated correctly
final WindowState window1 =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
assertEquals(window1, sWm.mRoot.computeFocusedWindow());
@@ -310,6 +311,24 @@
assertEquals(afterStackCount - 1, mDisplayContent.getStaskPosById(PINNED_STACK_ID));
}
+ /**
+ * Test that WM does not report displays to AM that are pending to be removed.
+ */
+ @Test
+ public void testDontReportDeferredRemoval() {
+ // Create a display and add an animating window to it.
+ final DisplayContent dc = createNewDisplay();
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.mAnimatingExit = true;
+ // Request display removal, it should be deferred.
+ dc.removeIfPossible();
+ // Request ordered display ids from WM.
+ final SparseIntArray orderedDisplayIds = new SparseIntArray();
+ sWm.getDisplaysInFocusOrder(orderedDisplayIds);
+ // Make sure that display that is marked for removal is not reported.
+ assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
+ }
+
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
int expectedBaseHeight, int expectedBaseDensity) {
assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 8108909..39c0de8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -90,14 +90,42 @@
long ms = SystemClock.elapsedRealtime();
mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
- mPersister.persistSnapshot(3, mTestUserId, createSnapshot());
- mPersister.persistSnapshot(4, mTestUserId, createSnapshot());
- mPersister.persistSnapshot(5, mTestUserId, createSnapshot());
- mPersister.persistSnapshot(6, mTestUserId, createSnapshot());
+ mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
+ mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
+ mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
+ mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
mPersister.waitForQueueEmpty();
assertTrue(SystemClock.elapsedRealtime() - ms > 500);
}
+ /**
+ * Tests that too many store write queue items are being purged.
+ */
+ @Test
+ public void testPurging() {
+ mPersister.persistSnapshot(100, mTestUserId, createSnapshot());
+ mPersister.waitForQueueEmpty();
+ mPersister.setPaused(true);
+ mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
+ mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
+ mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
+ mPersister.persistSnapshot(3, mTestUserId, createSnapshot());
+ mPersister.persistSnapshot(4, mTestUserId, createSnapshot());
+ mPersister.setPaused(false);
+ mPersister.waitForQueueEmpty();
+
+ // Make sure 1,2 were purged but removeObsoleteFiles wasn't.
+ final File[] existsFiles = new File[] {
+ new File(sFilesDir.getPath() + "/snapshots/3.proto"),
+ new File(sFilesDir.getPath() + "/snapshots/4.proto")};
+ final File[] nonExistsFiles = new File[] {
+ new File(sFilesDir.getPath() + "/snapshots/100.proto"),
+ new File(sFilesDir.getPath() + "/snapshots/1.proto"),
+ new File(sFilesDir.getPath() + "/snapshots/1.proto")};
+ assertTrueForFiles(existsFiles, File::exists, " must exist");
+ assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
+ }
+
@Test
public void testGetTaskId() {
RemoveObsoleteFilesQueueItem removeObsoleteFilesQueueItem =
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 be53667..623d77b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -366,6 +366,11 @@
}
@Override
+ public void screenTurningOff(ScreenOffListener screenOffListener) {
+
+ }
+
+ @Override
public void screenTurnedOff() {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index d9349ed..b83532c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -115,11 +115,11 @@
}
WindowState getFirstChild() {
- return mChildren.getFirst();
+ return mChildren.peekFirst();
}
WindowState getLastChild() {
- return mChildren.getLast();
+ return mChildren.peekLast();
}
int positionInParent() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4ba457d..0de3c7c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -39,6 +39,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
@@ -80,6 +81,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.File;
@@ -137,6 +139,7 @@
AppOpsManager mAppOps;
UserManager mUserManager;
PackageManager mPackageManager;
+ PackageManagerInternal mPackageManagerInternal;
AppWidgetManager mAppWidgetManager;
IDeviceIdleController mDeviceIdleController;
private DisplayManager mDisplayManager;
@@ -179,6 +182,7 @@
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
mPackageManager = getContext().getPackageManager();
+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mHandler = new H(BackgroundThread.get().getLooper());
File systemDataDir = new File(Environment.getDataDirectory(), "system");
@@ -407,6 +411,10 @@
}
}
+ private boolean shouldObfuscateInstantAppsForCaller(int callingUid) {
+ return !mPackageManagerInternal.canAccessInstantApps(callingUid);
+ }
+
void clearAppIdleForPackage(String packageName, int userId) {
synchronized (mAppIdleLock) {
mAppIdleHistory.clearUsage(packageName, userId);
@@ -704,6 +712,11 @@
final long elapsedRealtime = SystemClock.elapsedRealtime();
convertToSystemTimeLocked(event);
+ if (event.getPackageName() != null
+ && mPackageManagerInternal.isPackageEphemeral(userId, event.getPackageName())) {
+ event.mFlags |= Event.FLAG_IS_PACKAGE_INSTANT_APP;
+ }
+
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
service.reportEvent(event);
@@ -807,7 +820,8 @@
/**
* Called by the Binder stub.
*/
- List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime) {
+ List<UsageStats> queryUsageStats(int userId, int bucketType, long beginTime, long endTime,
+ boolean obfuscateInstantApps) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
if (!validRange(timeNow, beginTime, endTime)) {
@@ -816,7 +830,20 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- return service.queryUsageStats(bucketType, beginTime, endTime);
+ List<UsageStats> list = service.queryUsageStats(bucketType, beginTime, endTime);
+
+ // Mangle instant app names *using their current state (not whether they were ephemeral
+ // when the data was recorded)*.
+ if (obfuscateInstantApps) {
+ for (int i = list.size() - 1; i >= 0; i--) {
+ final UsageStats stats = list.get(i);
+ if (mPackageManagerInternal.isPackageEphemeral(userId, stats.mPackageName)) {
+ list.set(i, stats.getObfuscatedForInstantApp());
+ }
+ }
+ }
+
+ return list;
}
}
@@ -840,7 +867,8 @@
/**
* Called by the Binder stub.
*/
- UsageEvents queryEvents(int userId, long beginTime, long endTime) {
+ UsageEvents queryEvents(int userId, long beginTime, long endTime,
+ boolean shouldObfuscateInstantApps) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
if (!validRange(timeNow, beginTime, endTime)) {
@@ -849,7 +877,7 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- return service.queryEvents(beginTime, endTime);
+ return service.queryEvents(beginTime, endTime, shouldObfuscateInstantApps);
}
}
@@ -884,10 +912,15 @@
}
}
- boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime) {
+ boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime,
+ boolean shouldObfuscateInstantApps) {
if (isParoledOrCharging()) {
return false;
}
+ if (shouldObfuscateInstantApps &&
+ mPackageManagerInternal.isPackageEphemeral(userId, packageName)) {
+ return false;
+ }
return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
}
@@ -1353,11 +1386,14 @@
return null;
}
+ final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
+ Binder.getCallingUid());
+
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
final List<UsageStats> results = UsageStatsService.this.queryUsageStats(
- userId, bucketType, beginTime, endTime);
+ userId, bucketType, beginTime, endTime, obfuscateInstantApps);
if (results != null) {
return new ParceledListSlice<>(results);
}
@@ -1395,10 +1431,14 @@
return null;
}
+ final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
+ Binder.getCallingUid());
+
final int userId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
- return UsageStatsService.this.queryEvents(userId, beginTime, endTime);
+ return UsageStatsService.this.queryEvents(userId, beginTime, endTime,
+ obfuscateInstantApps);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1412,10 +1452,12 @@
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
+ final boolean obfuscateInstantApps = shouldObfuscateInstantAppsForCaller(
+ Binder.getCallingUid());
final long token = Binder.clearCallingIdentity();
try {
return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId,
- SystemClock.elapsedRealtime());
+ SystemClock.elapsedRealtime(), obfuscateInstantApps);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1647,9 +1689,10 @@
@Override
public List<UsageStats> queryUsageStatsForUser(
- int userId, int intervalType, long beginTime, long endTime) {
+ int userId, int intervalType, long beginTime, long endTime,
+ boolean obfuscateInstantApps) {
return UsageStatsService.this.queryUsageStats(
- userId, intervalType, beginTime, endTime);
+ userId, intervalType, beginTime, endTime, obfuscateInstantApps);
}
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 96f3305..cc53a9c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -26,7 +26,10 @@
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
+import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.Log;
+import android.util.LogWriter;
import java.io.IOException;
import java.net.ProtocolException;
@@ -35,6 +38,8 @@
* UsageStats reader/writer for version 1 of the XML format.
*/
final class UsageStatsXmlV1 {
+ private static final String TAG = "UsageStatsXmlV1";
+
private static final String PACKAGES_TAG = "packages";
private static final String PACKAGE_TAG = "package";
@@ -51,6 +56,7 @@
// Attributes
private static final String PACKAGE_ATTR = "package";
+ private static final String FLAGS_ATTR = "flags";
private static final String CLASS_ATTR = "class";
private static final String TOTAL_TIME_ACTIVE_ATTR = "timeActive";
private static final String COUNT_ATTR = "count";
@@ -70,7 +76,6 @@
if (pkg == null) {
throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
}
-
final UsageStats stats = statsOut.getOrCreateUsageStats(pkg);
// Apply the offset to the beginTime to find the absolute time.
@@ -149,11 +154,12 @@
if (packageName == null) {
throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
}
-
final String className = XmlUtils.readStringAttribute(parser, CLASS_ATTR);
final UsageEvents.Event event = statsOut.buildEvent(packageName, className);
+ event.mFlags = XmlUtils.readIntAttribute(parser, FLAGS_ATTR, 0);
+
// Apply the offset to the beginTime to find the absolute time of this event.
event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR);
@@ -256,6 +262,7 @@
if (event.mClass != null) {
XmlUtils.writeStringAttribute(xml, CLASS_ATTR, event.mClass);
}
+ XmlUtils.writeIntAttribute(xml, FLAGS_ATTR, event.mFlags);
XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
switch (event.mEventType) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 8d335a5..0abbb82 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -19,11 +19,8 @@
import android.app.usage.ConfigurationStats;
import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
-import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.SystemClock;
import android.content.Context;
@@ -312,7 +309,8 @@
return queryStats(bucketType, beginTime, endTime, sConfigStatsCombiner);
}
- UsageEvents queryEvents(final long beginTime, final long endTime) {
+ UsageEvents queryEvents(final long beginTime, final long endTime,
+ boolean obfuscateInstantApps) {
final ArraySet<String> names = new ArraySet<>();
List<UsageEvents.Event> results = queryStats(UsageStatsManager.INTERVAL_DAILY,
beginTime, endTime, new StatCombiner<UsageEvents.Event>() {
@@ -334,7 +332,10 @@
return;
}
- final UsageEvents.Event event = stats.events.valueAt(i);
+ UsageEvents.Event event = stats.events.valueAt(i);
+ if (obfuscateInstantApps) {
+ event = event.getObfuscatedIfInstantApp();
+ }
names.add(event.mPackage);
if (event.mClass != null) {
names.add(event.mClass);
@@ -586,6 +587,7 @@
if (event.mShortcutId != null) {
pw.printPair("shortcutId", event.mShortcutId);
}
+ pw.printHexPair("flags", event.mFlags);
pw.println();
}
pw.decreaseIndent();
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.aidl b/telephony/java/android/telephony/ImsiEncryptionInfo.aidl
new file mode 100644
index 0000000..080e30a
--- /dev/null
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.aidl
@@ -0,0 +1,19 @@
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable ImsiEncryptionInfo;
diff --git a/telephony/java/android/telephony/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
new file mode 100644
index 0000000..ecb9d25
--- /dev/null
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Class to represent information sent by the carrier, which will be used to encrypt
+ * the IMSI + IMPI. The ecryption is being done by WLAN, and the modem.
+ *
+ * @hide
+ */
+public final class ImsiEncryptionInfo implements Parcelable {
+
+ private static final String LOG_TAG = "ImsiEncryptionInfo";
+ private static final boolean DBG = false;
+
+
+ private final String mcc;
+ private final String mnc;
+ private final PublicKey publicKey;
+ private final String keyIdentifier;
+ private final int keyType;
+
+ public ImsiEncryptionInfo(String mcc, String mnc, int keyType, String keyIdentifier,
+ PublicKey publicKey) {
+ this.mcc = mcc;
+ this.mnc = mnc;
+ this.keyType = keyType;
+ this.publicKey = publicKey;
+ this.keyIdentifier = keyIdentifier;
+ }
+
+ public ImsiEncryptionInfo(Parcel in) {
+ int length = in.readInt();
+ byte b[] = new byte[length];
+ in.readByteArray(b);
+ publicKey = makeKeyObject(b);
+ mcc = in.readString();
+ mnc = in.readString();
+ keyIdentifier = in.readString();
+ keyType = in.readInt();
+
+ }
+
+ public String getMnc() {
+ return this.mnc;
+ }
+
+ public String getMcc() {
+ return this.mcc;
+ }
+
+ public String getKeyIdentifier() {
+ return this.keyIdentifier;
+ }
+
+ public int getKeyType() {
+ return this.keyType;
+ }
+
+ public PublicKey getPublicKey() {
+ return this.publicKey;
+ }
+
+ private static PublicKey makeKeyObject(byte[] publicKeyBytes) {
+ try {
+ X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(publicKeyBytes);
+ return KeyFactory.getInstance("RSA").generatePublic(pubKeySpec);
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException ex) {
+ Log.e(LOG_TAG, "Error makeKeyObject: unable to convert into PublicKey", ex);
+ }
+ return null;
+ }
+
+ /** Implement the Parcelable interface */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<ImsiEncryptionInfo> CREATOR =
+ new Parcelable.Creator<ImsiEncryptionInfo>() {
+ @Override
+ public ImsiEncryptionInfo createFromParcel(Parcel in) {
+ return new ImsiEncryptionInfo(in);
+ }
+
+ @Override
+ public ImsiEncryptionInfo[] newArray(int size) {
+ return new ImsiEncryptionInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ byte[] b = publicKey.getEncoded();
+ dest.writeInt(b.length);
+ dest.writeByteArray(b);
+ dest.writeString(mcc);
+ dest.writeString(mnc);
+ dest.writeString(keyIdentifier);
+ dest.writeInt(keyType);
+ }
+
+ @Override
+ public String toString(){
+ return "[ImsiEncryptionInfo "
+ + "mcc=" + mcc
+ + "mnc=" + mnc
+ + "publicKey=" + publicKey
+ + ", keyIdentifier=" + keyIdentifier
+ + ", keyType=" + keyType
+ + "]";
+ }
+}
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index 58262e1..251d5bb 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -24,10 +24,10 @@
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
-import android.telephony.mbms.IMbmsStreamingManagerCallback;
-import android.telephony.mbms.IStreamingServiceCallback;
import android.telephony.mbms.MbmsException;
+import android.telephony.mbms.MbmsStreamingManagerCallback;
import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.StreamingServiceCallback;
import android.telephony.mbms.StreamingServiceInfo;
import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log;
@@ -77,14 +77,14 @@
};
private List<ServiceListener> mServiceListeners = new LinkedList<>();
- private IMbmsStreamingManagerCallback mCallbackToApp;
+ private MbmsStreamingManagerCallback mCallbackToApp;
private final String mAppName;
private final Context mContext;
private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
/** @hide */
- private MbmsStreamingManager(Context context, IMbmsStreamingManagerCallback listener,
+ private MbmsStreamingManager(Context context, MbmsStreamingManagerCallback listener,
String streamingAppName, int subscriptionId) {
mContext = context;
mAppName = streamingAppName;
@@ -106,7 +106,7 @@
* @param subscriptionId The subscription ID to use.
*/
public static MbmsStreamingManager create(Context context,
- IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
+ MbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
throws MbmsException {
MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
streamingAppName, subscriptionId);
@@ -116,10 +116,10 @@
/**
* Create a new MbmsStreamingManager using the system default data subscription ID.
- * See {@link #create(Context, IMbmsStreamingManagerCallback, String, int)}.
+ * See {@link #create(Context, MbmsStreamingManagerCallback, String, int)}.
*/
public static MbmsStreamingManager create(Context context,
- IMbmsStreamingManagerCallback listener, String streamingAppName)
+ MbmsStreamingManagerCallback listener, String streamingAppName)
throws MbmsException {
int subId = SubscriptionManager.getDefaultSubscriptionId();
MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
@@ -155,13 +155,12 @@
*
* This may throw an {@link MbmsException} containing one of the following errors:
* {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
- * {@link MbmsException#ERROR_NOT_YET_INITIALIZED}
+ * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION}
* {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
*
- * Asynchronous error codes via the {@link IMbmsStreamingManagerCallback#error(int, String)}
+ * Asynchronous error codes via the {@link MbmsStreamingManagerCallback#error(int, String)}
* callback can include any of the errors except:
* {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
- * {@link MbmsException#ERROR_INVALID_SERVICE_ID}
* {@link MbmsException#ERROR_END_OF_SESSION}
*/
public void getStreamingServices(List<String> classList) throws MbmsException {
@@ -180,36 +179,37 @@
/**
* Starts streaming a requested service, reporting status to the indicated listener.
- * Returns an object used to control that stream.
+ * Returns an object used to control that stream. The stream may not be ready for consumption
+ * immediately upon return from this method -- wait until the streaming state has been
+ * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateChanged(int)}.
*
- * May throw an IllegalArgumentException or RemoteException.
+ * May throw an {@link MbmsException} containing any of the following error codes:
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+ * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION}
+ * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ *
+ * May also throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
*
* Asynchronous errors through the listener include any of the errors
*/
public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
- IStreamingServiceCallback listener) {
- return null;
- }
+ StreamingServiceCallback listener) throws MbmsException {
+ if (mService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
- /**
- * Lists all the services currently being streamed to the device by this application
- * on this given subId. Results are returned asynchronously through the previously
- * registered callback.
- *
- * May throw a RemoteException.
- *
- * The return value is a success/error-code with the following possible values:
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
- *
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_UNABLED_TO_START_SERVICE</li>
- * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
- * <li>ERROR_MSDC_END_OF_SESSION</li>
- *
- */
- public int getActiveStreamingServices() {
- return 0;
+ try {
+ int returnCode = mService.startStreaming(
+ mAppName, mSubscriptionId, serviceInfo.getServiceId(), listener);
+ if (returnCode != MbmsException.SUCCESS) {
+ throw new MbmsException(returnCode);
+ }
+ } catch (RemoteException e) {
+ throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
+ }
+
+ return new StreamingService(
+ mAppName, mSubscriptionId, mService, serviceInfo, listener);
}
private void bindAndInitialize() throws MbmsException {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index cf2d27e..4e1c15f 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -16,7 +16,10 @@
package android.telephony;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -30,6 +33,8 @@
import android.os.Parcelable;
import android.util.DisplayMetrics;
+import java.util.Arrays;
+
/**
* A Parcelable class for Subscription Information.
*/
@@ -110,11 +115,34 @@
private String mCountryIso;
/**
+ * Whether the subscription is an embedded one.
+ */
+ private boolean mIsEmbedded;
+
+ /**
+ * The access rules for this subscription, if it is embedded and defines any.
+ */
+ @Nullable
+ private UiccAccessRule[] mAccessRules;
+
+ /**
* @hide
*/
public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, int mcc, int mnc, String countryIso) {
+ this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
+ roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */,
+ null /* accessRules */);
+ }
+
+ /**
+ * @hide
+ */
+ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
+ CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
+ Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded,
+ @Nullable UiccAccessRule[] accessRules) {
this.mId = id;
this.mIccId = iccId;
this.mSimSlotIndex = simSlotIndex;
@@ -128,6 +156,8 @@
this.mMcc = mcc;
this.mMnc = mnc;
this.mCountryIso = countryIso;
+ this.mIsEmbedded = isEmbedded;
+ this.mAccessRules = accessRules;
}
/**
@@ -284,6 +314,79 @@
return this.mCountryIso;
}
+ /**
+ * @return whether the subscription is an embedded one.
+ * @hide
+ *
+ * TODO(b/35851809): Make this public.
+ */
+ public boolean isEmbedded() {
+ return this.mIsEmbedded;
+ }
+
+ /**
+ * Checks whether the app with the given context is authorized to manage this subscription
+ * according to its metadata. Only supported for embedded subscriptions (if {@link #isEmbedded}
+ * returns true).
+ *
+ * @param context Context of the application to check.
+ * @return whether the app is authorized to manage this subscription per its metadata.
+ * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @hide
+ *
+ * TODO(b/35851809): Make this public.
+ */
+ public boolean canManageSubscription(Context context) {
+ return canManageSubscription(context, context.getPackageName());
+ }
+
+ /**
+ * Checks whether the given app is authorized to manage this subscription according to its
+ * metadata. Only supported for embedded subscriptions (if {@link #isEmbedded} returns true).
+ *
+ * @param context Any context.
+ * @param packageName Package name of the app to check.
+ * @return whether the app is authorized to manage this subscription per its metadata.
+ * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @hide
+ */
+ public boolean canManageSubscription(Context context, String packageName) {
+ if (!isEmbedded()) {
+ throw new UnsupportedOperationException("Not an embedded subscription");
+ }
+ if (mAccessRules == null) {
+ return false;
+ }
+ PackageManager packageManager = context.getPackageManager();
+ PackageInfo packageInfo;
+ try {
+ packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("Unknown package: " + packageName, e);
+ }
+ for (UiccAccessRule rule : mAccessRules) {
+ if (rule.getCarrierPrivilegeStatus(packageInfo)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return the {@link UiccAccessRule}s dictating who is authorized to manage this subscription.
+ * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public @Nullable UiccAccessRule[] getAccessRules() {
+ if (!isEmbedded()) {
+ throw new UnsupportedOperationException("Not an embedded subscription");
+ }
+ return mAccessRules;
+ }
+
public static final Parcelable.Creator<SubscriptionInfo> CREATOR = new Parcelable.Creator<SubscriptionInfo>() {
@Override
public SubscriptionInfo createFromParcel(Parcel source) {
@@ -300,9 +403,12 @@
int mnc = source.readInt();
String countryIso = source.readString();
Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
+ boolean isEmbedded = source.readBoolean();
+ UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR);
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
- nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
+ nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
+ isEmbedded, accessRules);
}
@Override
@@ -326,6 +432,8 @@
dest.writeInt(mMnc);
dest.writeString(mCountryIso);
mIconBitmap.writeToParcel(dest, flags);
+ dest.writeBoolean(mIsEmbedded);
+ dest.writeTypedArray(mAccessRules, flags);
}
@Override
@@ -355,6 +463,7 @@
+ " displayName=" + mDisplayName + " carrierName=" + mCarrierName
+ " nameSource=" + mNameSource + " iconTint=" + mIconTint
+ " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
- + " mnc " + mMnc + "}";
+ + " mnc " + mMnc + " isEmbedded " + mIsEmbedded
+ + " accessRules " + Arrays.toString(mAccessRules) + "}";
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7f616ad..77525ff 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -24,17 +24,17 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.Uri;
-import android.telephony.Rlog;
import android.os.Handler;
import android.os.Message;
-import android.os.ServiceManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.DisplayMetrics;
-import com.android.internal.telephony.ISub;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
+import com.android.internal.telephony.ISub;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.PhoneConstants;
+
import java.util.ArrayList;
import java.util.List;
@@ -45,7 +45,8 @@
* You do not instantiate this class directly; instead, you retrieve
* a reference to an instance through {@link #from}.
* <p>
- * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE.
+ * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE unless otherwise
+ * specified.
*/
public class SubscriptionManager {
private static final String LOG_TAG = "SubscriptionManager";
@@ -260,6 +261,32 @@
public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
/**
+ * TelephonyProvider column name for whether a subscription is embedded (that is, present on an
+ * eSIM).
+ * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+ * @hide
+ */
+ public static final String IS_EMBEDDED = "is_embedded";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: BLOB
+ * @hide
+ */
+ public static final String ACCESS_RULES = "access_rules";
+
+ /**
+ * TelephonyProvider column name identifying whether an embedded subscription is on a removable
+ * card. Such subscriptions are marked inaccessible as soon as the current card is removed.
+ * Otherwise, they will remain accessible unless explicitly deleted. Only present if
+ * {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+ * @hide
+ */
+ public static final String IS_REMOVABLE = "is_removable";
+
+ /**
* TelephonyProvider column name for extreme threat in CB settings
* @hide
*/
@@ -633,6 +660,112 @@
}
/**
+ * Gets the SubscriptionInfo(s) of all available subscriptions, if any.
+ *
+ * <p>Available subscriptions include active ones (those with a non-negative
+ * {@link SubscriptionInfo#getSimSlotIndex()}) as well as inactive but installed embedded
+ * subscriptions.
+ *
+ * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
+ * {@link SubscriptionInfo#getSubscriptionId}.
+ *
+ * @return Sorted list of the current {@link SubscriptionInfo} records available on the
+ * device.
+ * <ul>
+ * <li>
+ * If null is returned the current state is unknown but if a
+ * {@link OnSubscriptionsChangedListener} has been registered
+ * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future.
+ * <li>
+ * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
+ * <li>
+ * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
+ * then by {@link SubscriptionInfo#getSubscriptionId}.
+ * </ul>
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public List<SubscriptionInfo> getAvailableSubscriptionInfoList() {
+ List<SubscriptionInfo> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return result;
+ }
+
+ /**
+ * Gets the SubscriptionInfo(s) of all embedded subscriptions accessible to the calling app, if
+ * any.
+ *
+ * <p>Only those subscriptions for which the calling app has carrier privileges per the
+ * subscription metadata, if any, will be included in the returned list.
+ *
+ * <p>The records will be sorted by {@link SubscriptionInfo#getSimSlotIndex} then by
+ * {@link SubscriptionInfo#getSubscriptionId}.
+ *
+ * @return Sorted list of the current embedded {@link SubscriptionInfo} records available on the
+ * device which are accessible to the caller.
+ * <ul>
+ * <li>
+ * If null is returned the current state is unknown but if a
+ * {@link OnSubscriptionsChangedListener} has been registered
+ * {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be invoked in the future.
+ * <li>
+ * If the list is empty then there are no {@link SubscriptionInfo} records currently available.
+ * <li>
+ * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex}
+ * then by {@link SubscriptionInfo#getSubscriptionId}.
+ * </ul>
+ * @hide
+ *
+ * TODO(b/35851809): Make this public.
+ */
+ public List<SubscriptionInfo> getAccessibleSubscriptionInfoList() {
+ List<SubscriptionInfo> result = null;
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ result = iSub.getAccessibleSubscriptionInfoList(mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return result;
+ }
+
+ /**
+ * Request a refresh of the platform cache of profile information.
+ *
+ * <p>Should be called by the EuiccService implementation whenever this information changes due
+ * to an operation done outside the scope of a request initiated by the platform to the
+ * EuiccService. There is no need to refresh for downloads, deletes, or other operations that
+ * were made through the EuiccService.
+ *
+ * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public void requestEmbeddedSubscriptionInfoListRefresh() {
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.requestEmbeddedSubscriptionInfoListRefresh();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ }
+
+ /**
* @return the count of all subscriptions in the database, this includes
* all subscriptions that have been seen.
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c8ff08c..233a8d1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -72,6 +72,11 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -143,6 +148,12 @@
static public final int OTASP_SIM_UNPROVISIONED = 5;
+ /** @hide */
+ static public final int KEY_TYPE_EPDDG = 1;
+
+ /** @hide */
+ static public final int KEY_TYPE_WLAN = 2;
+
private final Context mContext;
private final int mSubId;
private SubscriptionManager mSubscriptionManager;
@@ -2334,6 +2345,73 @@
}
/**
+ * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * This includes the public key and the key identifier. For multi-sim devices, if no subId
+ * has been specified, we will return the value for the dafault data sim.
+ * Return null if it is unavailable.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param keyType whether the key is being used for wlan or epdg. Valid key types are
+ * {@link TelephonyManager#KEY_TYPE_EPDDG} or
+ * {@link TelephonyManager#KEY_TYPE_WLAN}.
+ * @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
+ * IMSI and IMPI. This includes the public key and the key identifier. This information
+ * will be stored in the device keystore.
+ * @hide
+ */
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+ try {
+ IPhoneSubInfo info = getSubscriberInfo();
+ if (info == null) return null;
+ int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
+ if (keyType != KEY_TYPE_EPDDG && keyType != KEY_TYPE_WLAN) {
+ throw new IllegalArgumentException("Invalid key type");
+ }
+ return info.getCarrierInfoForImsiEncryption(subId, keyType,
+ mContext.getOpPackageName());
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException", ex);
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException", ex);
+ return null;
+ }
+ }
+
+ /**
+ * Sets the Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * This includes the public key and the key identifier. This information will be stored in the
+ * device keystore.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * @param imsiEncryptionInfo which includes the Key Type, the Public Key
+ * (java.security.PublicKey) and the Key Identifier.and the Key Identifier.
+ * The keyIdentifier Attribute value pair that helps a server locate
+ * the private key to decrypt the permanent identity. This field is
+ * optional and if it is present then it’s always separated from encrypted
+ * permanent identity with “,”. Key identifier AVP is presented in ASCII string
+ * with “name=value” format.
+ * @hide
+ */
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
+ try {
+ IPhoneSubInfo info = getSubscriberInfo();
+ if (info == null) return;
+ info.setCarrierInfoForImsiEncryption(mSubId, mContext.getOpPackageName(),
+ imsiEncryptionInfo);
+ } catch (NullPointerException ex) {
+ // This could happen before phone restarts due to crashing
+ return;
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setCarrierInfoForImsiEncryption RemoteException", ex);
+ return;
+ }
+ }
+
+ /**
* Returns the Group Identifier Level1 for a GSM phone.
* Return null if it is unavailable.
*/
diff --git a/telephony/java/android/telephony/UiccAccessRule.java b/telephony/java/android/telephony/UiccAccessRule.java
index 1ac4c5c..e42a758 100644
--- a/telephony/java/android/telephony/UiccAccessRule.java
+++ b/telephony/java/android/telephony/UiccAccessRule.java
@@ -16,7 +16,6 @@
package android.telephony;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.os.Parcel;
@@ -63,7 +62,11 @@
* Encode these access rules as a byte array which can be parsed with {@link #decodeRules}.
* @hide
*/
- public static byte[] encodeRules(UiccAccessRule[] accessRules) {
+ @Nullable
+ public static byte[] encodeRules(@Nullable UiccAccessRule[] accessRules) {
+ if (accessRules == null) {
+ return null;
+ }
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(baos);
@@ -72,7 +75,12 @@
for (UiccAccessRule accessRule : accessRules) {
output.writeInt(accessRule.mCertificateHash.length);
output.write(accessRule.mCertificateHash);
- output.writeUTF(accessRule.mPackageName);
+ if (accessRule.mPackageName != null) {
+ output.writeBoolean(true);
+ output.writeUTF(accessRule.mPackageName);
+ } else {
+ output.writeBoolean(false);
+ }
output.writeLong(accessRule.mAccessType);
}
output.close();
@@ -87,7 +95,11 @@
* Decodes a byte array generated with {@link #encodeRules}.
* @hide
*/
- public static UiccAccessRule[] decodeRules(byte[] encodedRules) {
+ @Nullable
+ public static UiccAccessRule[] decodeRules(@Nullable byte[] encodedRules) {
+ if (encodedRules == null) {
+ return null;
+ }
ByteArrayInputStream bais = new ByteArrayInputStream(encodedRules);
try (DataInputStream input = new DataInputStream(bais)) {
input.readInt(); // version; currently ignored
@@ -97,7 +109,7 @@
int certificateHashLength = input.readInt();
byte[] certificateHash = new byte[certificateHashLength];
input.readFully(certificateHash);
- String packageName = input.readUTF();
+ String packageName = input.readBoolean() ? input.readUTF() : null;
long accessType = input.readLong();
accessRules[i] = new UiccAccessRule(certificateHash, packageName, accessType);
}
diff --git a/telephony/java/android/telephony/euicc/EuiccInfo.aidl b/telephony/java/android/telephony/euicc/EuiccInfo.aidl
new file mode 100644
index 0000000..3cfba75
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.euicc;
+
+parcelable EuiccInfo;
diff --git a/telephony/java/android/telephony/euicc/EuiccInfo.java b/telephony/java/android/telephony/euicc/EuiccInfo.java
new file mode 100644
index 0000000..5bfff08
--- /dev/null
+++ b/telephony/java/android/telephony/euicc/EuiccInfo.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.euicc;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information about an eUICC chip/device.
+ *
+ * @see EuiccManager#getEuiccInfo
+ * @hide
+ *
+ * TODO(b/35851809): Make this public.
+ */
+// WARNING: Do not add any privacy-sensitive fields to this class (such as an eUICC identifier)!
+// This API is accessible to all applications. Privacy-sensitive fields should be returned in their
+// own APIs guarded with appropriate permission checks.
+public final class EuiccInfo implements Parcelable {
+
+ public static final Creator<EuiccInfo> CREATOR =
+ new Creator<EuiccInfo>() {
+ @Override
+ public EuiccInfo createFromParcel(Parcel in) {
+ return new EuiccInfo(in);
+ }
+
+ @Override
+ public EuiccInfo[] newArray(int size) {
+ return new EuiccInfo[size];
+ }
+ };
+
+ /**
+ * Version of the operating system running on the eUICC. This field is hardware-specific and is
+ * not guaranteed to match any particular format.
+ */
+ @Nullable
+ public final String osVersion;
+
+ public EuiccInfo(@Nullable String osVersion) {
+ this.osVersion = osVersion;
+ }
+
+ private EuiccInfo(Parcel in) {
+ osVersion = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(osVersion);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 8bc0be6..be32f72 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -17,7 +17,6 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
@@ -124,6 +123,16 @@
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
/**
+ * Key for an extra set on {@link #getDefaultDownloadableSubscriptionList} PendingIntent result
+ * callbacks providing the list of available downloadable subscriptions.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS =
+ "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
+
+ /**
* Key for an extra set on {@link PendingIntent} result callbacks providing the resolution
* pending intent for {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}s.
* @hide
@@ -195,10 +204,11 @@
/**
* Attempt to download the given {@link DownloadableSubscription}.
*
- * <p>Requires the calling app to be authorized to manage both the currently-active subscription
- * and the subscription to be downloaded according to the subscription metadata. Without the
- * former, a {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the
- * callback intent to prompt the user to accept the download.
+ * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+ * or the calling app must be authorized to manage both the currently-active subscription and
+ * the subscription to be downloaded according to the subscription metadata. Without the former,
+ * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+ * intent to prompt the user to accept the download.
*
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -261,8 +271,9 @@
* For example, this may indicate whether the user has consented or may include the input
* they provided.
* @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
*/
- @SystemApi
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
if (!isEnabled()) {
PendingIntent callbackIntent =
@@ -299,7 +310,6 @@
*
* TODO(b/35851809): Make this a SystemApi.
*/
- @SystemApi
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -313,6 +323,153 @@
}
}
+ /**
+ * Gets metadata for subscription which are available for download on this device.
+ *
+ * <p>Subscriptions returned here may be passed to {@link #downloadSubscription}. They may have
+ * been pre-assigned to this particular device, for example. The callback will be triggered with
+ * an Intent with {@link #EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS} set to the
+ * list of available subscriptions upon success.
+ *
+ * <p>Requires that the calling app has the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
+ * internal system use only.
+ *
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ * @hide
+ *
+ * TODO(b/35851809): Make this a SystemApi.
+ */
+ public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.getDefaultDownloadableSubscriptionList(callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns information about the eUICC chip/device.
+ *
+ * @return the {@link EuiccInfo}. May be null if {@link #isEnabled()} is false or the eUICC is
+ * not ready.
+ */
+ @Nullable
+ public EuiccInfo getEuiccInfo() {
+ if (!isEnabled()) {
+ return null;
+ }
+ try {
+ return mController.getEuiccInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Deletes the given subscription.
+ *
+ * <p>If this subscription is currently active, the device will first switch away from it onto
+ * an "empty" subscription.
+ *
+ * <p>Requires that the calling app has carrier privileges according to the metadata of the
+ * profile to be deleted, or the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission.
+ *
+ * @param subscriptionId the ID of the subscription to delete.
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ */
+ public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.deleteSubscription(
+ subscriptionId, mContext.getOpPackageName(), callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Switch to (enable) the given subscription.
+ *
+ * <p>Requires the {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+ * or the calling app must be authorized to manage both the currently-active subscription and
+ * the subscription to be enabled according to the subscription metadata. Without the former,
+ * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
+ * intent to prompt the user to accept the download.
+ *
+ * @param subscriptionId the ID of the subscription to enable. May be
+ * {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
+ * current profile without activating another profile to replace it.
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ */
+ public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.switchToSubscription(
+ subscriptionId, mContext.getOpPackageName(), callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Update the nickname for the given subscription.
+ *
+ * <p>Requires that the calling app has the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
+ * internal system use only.
+ *
+ * @param subscriptionId the ID of the subscription to update.
+ * @param nickname the new nickname to apply.
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ * @hide
+ */
+ public void updateSubscriptionNickname(
+ int subscriptionId, String nickname, PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.updateSubscriptionNickname(subscriptionId, nickname, callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Erase all subscriptions and reset the eUICC.
+ *
+ * <p>Requires that the calling app has the
+ * {@link android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission. This is for
+ * internal system use only.
+ *
+ * @param callbackIntent a PendingIntent to launch when the operation completes.
+ * @hide
+ */
+ public void eraseSubscriptions(PendingIntent callbackIntent) {
+ if (!isEnabled()) {
+ sendUnavailableError(callbackIntent);
+ return;
+ }
+ try {
+ mController.eraseSubscriptions(callbackIntent);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private static void sendUnavailableError(PendingIntent callbackIntent) {
try {
callbackIntent.send(EMBEDDED_SUBSCRIPTION_RESULT_GENERIC_ERROR);
diff --git a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
index 7b4ecf2..891edad 100755
--- a/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
@@ -17,15 +17,13 @@
package android.telephony.mbms;
import android.net.Uri;
-import android.telephony.SignalStrength;
-import android.telephony.mbms.StreamingService;
/**
* @hide
*/
oneway interface IStreamingServiceCallback {
void error(int errorCode, String message);
- void streamStateChanged(in StreamingService service, int state);
+ void streamStateChanged(int state);
void uriUpdated(in Uri uri);
- void signalStrengthUpdated(in SignalStrength signalStrength);
+ void broadcastSignalStrengthUpdated(int signalStrength);
}
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index e8680ea..a0ded9b 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -27,16 +27,14 @@
public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
public static final int ERROR_UNABLE_TO_START_SERVICE = 8;
- public static final int ERROR_INVALID_SERVICE_ID = 9;
+ public static final int ERROR_STREAM_ALREADY_STARTED = 9;
public static final int ERROR_END_OF_SESSION = 10;
- public static final int ERROR_NOT_YET_INITIALIZED = 11;
- public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 12;
private final int mErrorCode;
/** @hide
* TODO: future systemapi
- * */
+ */
public MbmsException(int errorCode) {
super();
mErrorCode = errorCode;
diff --git a/telephony/java/android/telephony/mbms/StreamingService.aidl b/telephony/java/android/telephony/mbms/StreamingService.aidl
deleted file mode 100755
index 0c286f3..0000000
--- a/telephony/java/android/telephony/mbms/StreamingService.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.telephony.mbms;
-
-parcelable StreamingService;
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
index 8cc6043..ac5fbdf 100644
--- a/telephony/java/android/telephony/mbms/StreamingService.java
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -19,46 +19,60 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.SignalStrength;
+import android.os.RemoteException;
+import android.telephony.mbms.vendor.IMbmsStreamingService;
+import android.util.Log;
/**
* @hide
*/
public class StreamingService {
-
+ private static final String LOG_TAG = "MbmsStreamingService";
public final static int STATE_STOPPED = 1;
public final static int STATE_STARTED = 2;
public final static int STATE_STALLED = 3;
+ private final String mAppName;
+ private final int mSubscriptionId;
+ private final IMbmsStreamingService mService;
+ private final StreamingServiceInfo mServiceInfo;
+ private final IStreamingServiceCallback mCallback;
/**
+ * @hide
*/
- StreamingService(StreamingServiceInfo streamingServiceInfo,
- IStreamingServiceCallback listener) {
+ public StreamingService(String appName,
+ int subscriptionId,
+ IMbmsStreamingService service,
+ StreamingServiceInfo streamingServiceInfo,
+ IStreamingServiceCallback callback) {
+ mAppName = appName;
+ mSubscriptionId = subscriptionId;
+ mService = service;
+ mServiceInfo = streamingServiceInfo;
+ mCallback = callback;
}
/**
* Retreive the Uri used to play this stream.
*
- * This may throw a RemoteException.
+ * This may throw a {@link MbmsException} with the error code
+ * {@link MbmsException#ERROR_UNKNOWN_REMOTE_EXCEPTION}
+ * @return The {@link Uri} to pass to the streaming client.
*/
- public Uri getPlaybackUri() {
- return null;
+ public Uri getPlaybackUri() throws MbmsException {
+ try {
+ return mService.getPlaybackUri(mAppName, mSubscriptionId, mServiceInfo.getServiceId());
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Caught remote exception calling getPlaybackUri: " + e);
+ throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
+ }
}
/**
* Retreive the info for this StreamingService.
*/
public StreamingServiceInfo getInfo() {
- return null;
- }
-
- /**
- * Retreive the current state of this stream.
- *
- * This may throw a RemoteException.
- */
- public int getState() {
- return STATE_STOPPED;
+ return mServiceInfo;
}
/**
@@ -69,41 +83,13 @@
public void stopStreaming() {
}
- /**
- * Switch this stream to a different service. Used for smooth transitions.
- *
- * This may throw a RemoteException.
- *
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_MSDC_UNABLE_TO_INITIALIZE</li>
- */
- public void switchStream(StreamingServiceInfo streamingServiceInfo) {
- }
-
- public void dispose() {
- }
-
- public static final Parcelable.Creator<StreamingService> CREATOR =
- new Parcelable.Creator<StreamingService>() {
- @Override
- public StreamingService createFromParcel(Parcel in) {
- return new StreamingService(in);
+ public void dispose() throws MbmsException {
+ try {
+ mService.disposeStream(mAppName, mSubscriptionId, mServiceInfo.getServiceId());
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Caught remote exception calling disposeStream: " + e);
+ throw new MbmsException(MbmsException.ERROR_UNKNOWN_REMOTE_EXCEPTION);
}
-
- @Override
- public StreamingService[] newArray(int size) {
- return new StreamingService[size];
- }
- };
-
- private StreamingService(Parcel in) {
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- }
-
- public int describeContents() {
- return 0;
}
}
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
index 7f5c486..bd0a1b3 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -17,14 +17,21 @@
package android.telephony.mbms;
import android.net.Uri;
-import android.telephony.SignalStrength;
/**
- * A Callback class for use when the applicaiton is actively streaming content.
+ * A Callback class for use when the application is actively streaming content.
* @hide
*/
public class StreamingServiceCallback extends IStreamingServiceCallback.Stub {
+ /**
+ * Indicates broadcast signal strength is not available for this service.
+ *
+ * This may be due to the service no longer being available due to geography
+ * or timing (end of service) or because lack of demand has caused the service
+ * to be delivered via unicast.
+ */
+ public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
public void error(int errorCode, String message) {
// default implementation empty
@@ -36,7 +43,7 @@
* See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED}
* and {@link StreamingService#STATE_STALLED}.
*/
- public void streamStateChanged(StreamingService service, int state) {
+ public void streamStateChanged(int state) {
// default implementation empty
}
@@ -51,19 +58,16 @@
}
/**
- * Signal Strength updated.
+ * Broadcast Signal Strength updated.
*
* This signal strength is the BROADCAST signal strength which,
* depending on technology in play and it's deployment, may be
* stronger or weaker than the traditional UNICAST signal
- * strength.
- *
- * A {@link android.telephony.SignalStrength#getLevel} result of 0 means
- * you don't have coverage for this stream, either due to geographic
- * restrictions, poor tower coverage or something (yards of concrete?)
- * interferring with the signal.
+ * strength. It a simple int from 0-4 for valid levels or
+ * {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
+ * for this service due to timing, geography or popularity.
*/
- public void signalStrengthUpdated(SignalStrength signalStrength) {
+ public void broadcastSignalStrengthUpdated(int signalStrength) {
// default implementation empty
}
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
index fed0a40..8ff7fa7 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -19,9 +19,7 @@
import android.net.Uri;
import android.telephony.mbms.IMbmsStreamingManagerCallback;
import android.telephony.mbms.IStreamingServiceCallback;
-import android.telephony.mbms.StreamingService;
import android.telephony.mbms.StreamingServiceInfo;
-import android.telephony.SignalStrength;
/**
* The interface the opaque MbmsStreamingService will satisfy.
@@ -33,37 +31,19 @@
int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
- /**
- * - Starts streaming the serviceId given.
- * - if the uid/appName/subId don't match a previously registered callback an error will
- * be returned
- * - Streaming status will be sent via the included listener, including an initial
- * URL-change and State-change pair.
- */
int startStreaming(String appName, int subId, String serviceId,
IStreamingServiceCallback listener);
/**
- * Asynchronously fetches all Services being streamed by this uid/appName/subId.
- */
- int getActiveStreamingServices(String appName, int subId);
-
-
- /**
* Per-stream api. Note each specifies what stream they apply to.
*/
Uri getPlaybackUri(String appName, int subId, String serviceId);
- void switchStreams(String appName, int subId, String oldServiceId, String newServiceId);
-
- int getState(String appName, int subId, String serviceId);
-
void stopStreaming(String appName, int subId, String serviceId);
void disposeStream(String appName, int subId, String serviceId);
-
/**
* End of life for all MbmsStreamingManager's created by this uid/appName/subId.
* Ends any streams run under this uid/appname/subId and calls the disposed methods
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index e23d12b..37f47ff 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -16,6 +16,7 @@
package android.telephony.mbms.vendor;
+import android.annotation.Nullable;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.mbms.IMbmsStreamingManagerCallback;
@@ -32,11 +33,12 @@
/**
* Initialize streaming service for this app and subId, registering the listener.
*
+ * May throw an {@link IllegalArgumentException} or a {@link SecurityException}
+ *
* @param listener The callback to use to communicate with the app.
* @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription ID to use.
- * @return {@link MbmsException#SUCCESS}, {@link MbmsException#ERROR_ALREADY_INITIALIZED}, or
- * {@link MbmsException#ERROR_APP_PERMISSIONS_NOT_GRANTED}
+ * @return {@link MbmsException#SUCCESS} or {@link MbmsException#ERROR_ALREADY_INITIALIZED}
*/
@Override
public int initialize(IMbmsStreamingManagerCallback listener, String appName,
@@ -52,6 +54,8 @@
* Note that subsequent calls with the same uid, appName and subId will replace
* the service class list.
*
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
* @param appName The app name as negotiated with the wireless carrier.
* @param subscriptionId The subscription id to use.
* @param serviceClasses The service classes that the app wishes to get info on. The strings
@@ -59,7 +63,6 @@
* carrier.
* @return One of {@link MbmsException#SUCCESS},
* {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND},
- * {@link MbmsException#ERROR_NOT_YET_INITIALIZED}, or
* {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
*/
@Override
@@ -68,30 +71,40 @@
return 0;
}
+ /**
+ * Starts streaming on a particular service. This method may perform asynchronous work. When
+ * the middleware is ready to send bits to the frontend, it should inform the app via
+ * {@link IStreamingServiceCallback#streamStateChanged(int)}.
+ *
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
+ * @param appName The app name as negotiated with the wireless carrier.
+ * @param subscriptionId The subscription id to use.
+ * @param serviceId The ID of the streaming service that the app has requested.
+ * @param listener The listener object on which the app wishes to receive updates.
+ * @return TODO: document possible errors
+ */
@Override
- public int startStreaming(String appName, int subId,
+ public int startStreaming(String appName, int subscriptionId,
String serviceId, IStreamingServiceCallback listener) throws RemoteException {
return 0;
}
+ /**
+ * Retrieves the streaming URI for a particular service. If the middleware is not yet ready to
+ * stream the service, this method may return null.
+ *
+ * May throw an {@link IllegalArgumentException} or an {@link IllegalStateException}
+ *
+ * @param appName The app name as negotiated with the wireless carrier.
+ * @param subscriptionId The subscription id to use.
+ * @param serviceId The ID of the streaming service that the app has requested.
+ * @return An opaque {@link Uri} to be passed to a video player that understands the format.
+ */
@Override
- public int getActiveStreamingServices(String appName, int subId) throws RemoteException {
- return 0;
- }
-
- @Override
- public Uri getPlaybackUri(String appName, int subId, String serviceId) throws RemoteException {
- return null;
- }
-
- @Override
- public void switchStreams(String appName, int subId, String oldServiceId, String newServiceId)
+ public @Nullable Uri getPlaybackUri(String appName, int subscriptionId, String serviceId)
throws RemoteException {
- }
-
- @Override
- public int getState(String appName, int subId, String serviceId) throws RemoteException {
- return 0;
+ return null;
}
@Override
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index bd8492b3..48f07d6 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -45,6 +45,8 @@
public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106;
// No pending incoming call exists
public static final int CODE_LOCAL_NO_PENDING_CALL = 107;
+ // IMS Call ended during conference merge process
+ public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108;
// IMS -> Telephony
// Service unavailable; by power off
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 02baa34..dbd8867 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import android.telephony.ImsiEncryptionInfo;
+
/**
* Interface used to retrieve various phone-related subscriber information.
*
@@ -138,6 +140,18 @@
String getCompleteVoiceMailNumberForSubscriber(int subId);
/**
+ * Retrieves the Carrier information used to encrypt IMSI and IMPI.
+ */
+ ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType,
+ String callingPackage);
+
+ /**
+ * Stores the Carrier information used to encrypt IMSI and IMPI.
+ */
+ void setCarrierInfoForImsiEncryption(int subId, String callingPackage,
+ in ImsiEncryptionInfo imsiEncryptionInfo);
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
String getVoiceMailAlphaTag(String callingPackage);
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 71f2c6b..644ad49 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -94,6 +94,21 @@
int getActiveSubInfoCountMax();
/**
+ * @see android.telephony.SubscriptionManager#getAvailableSubscriptionInfoList
+ */
+ List<SubscriptionInfo> getAvailableSubscriptionInfoList(String callingPackage);
+
+ /**
+ * @see android.telephony.SubscriptionManager#getAccessibleSubscriptionInfoList
+ */
+ List<SubscriptionInfo> getAccessibleSubscriptionInfoList(String callingPackage);
+
+ /**
+ * @see android.telephony.SubscriptionManager#requestEmbeddedSubscriptionInfoListRefresh
+ */
+ oneway void requestEmbeddedSubscriptionInfoListRefresh();
+
+ /**
* Add a new SubscriptionInfo to subinfo database if needed
* @param iccId the IccId of the SIM card
* @param slotIndex the slot which the SIM is inserted
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index 5f03dd9..725b89b 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -20,13 +20,23 @@
import android.content.Intent;
import android.os.Bundle;
import android.telephony.euicc.DownloadableSubscription;
+import android.telephony.euicc.EuiccInfo;
/** @hide */
interface IEuiccController {
oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
in PendingIntent callbackIntent);
+ oneway void getDefaultDownloadableSubscriptionList(in PendingIntent callbackIntent);
String getEid();
oneway void downloadSubscription(in DownloadableSubscription subscription,
boolean switchAfterDownload, String callingPackage, in PendingIntent callbackIntent);
+ EuiccInfo getEuiccInfo();
+ oneway void deleteSubscription(int subscriptionId, String callingPackage,
+ in PendingIntent callbackIntent);
+ oneway void switchToSubscription(int subscriptionId, String callingPackage,
+ in PendingIntent callbackIntent);
+ oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+ in PendingIntent callbackIntent);
+ oneway void eraseSubscriptions(in PendingIntent callbackIntent);
}
\ No newline at end of file
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 8a5fd4b..272653f 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -111,7 +111,6 @@
private Map<String, Intent> mNameToIntent;
- private Map<String, String> mNameToProcess;
private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
private Map<String, String> mNameToResultKey;
private Map<String, List<Long>> mNameToLaunchTime;
@@ -431,7 +430,6 @@
private void createMappings() {
mNameToIntent = new LinkedHashMap<String, Intent>();
- mNameToProcess = new LinkedHashMap<String, String>();
PackageManager pm = getInstrumentation().getContext()
.getPackageManager();
@@ -459,8 +457,9 @@
ri.activityInfo.name);
String appName = ri.loadLabel(pm).toString();
if (appName != null) {
+ // Support launching intent using package name or app name
+ mNameToIntent.put(ri.activityInfo.packageName, startIntent);
mNameToIntent.put(appName, startIntent);
- mNameToProcess.put(appName, ri.activityInfo.processName);
}
}
}
diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk
index 5f7467a..6b5c999 100644
--- a/tests/UsageStatsTest/Android.mk
+++ b/tests/UsageStatsTest/Android.mk
@@ -8,6 +8,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_CERTIFICATE := platform
+
LOCAL_PACKAGE_NAME := UsageStatsTest
include $(BUILD_PACKAGE)
diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml
index 589674a..c27be7b 100644
--- a/tests/UsageStatsTest/AndroidManifest.xml
+++ b/tests/UsageStatsTest/AndroidManifest.xml
@@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Note: Add android:sharedUserId="android.uid.system" to the root element to simulate the system UID
+ caller case.
+-->
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tests.usagestats">
+ package="com.android.tests.usagestats"
+ >
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
diff --git a/tests/UsageStatsTest/res/menu/main.xml b/tests/UsageStatsTest/res/menu/main.xml
index e781058..4ccbc81 100644
--- a/tests/UsageStatsTest/res/menu/main.xml
+++ b/tests/UsageStatsTest/res/menu/main.xml
@@ -2,4 +2,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/log"
android:title="View Log"/>
+ <item android:id="@+id/call_is_app_inactive"
+ android:title="Call isAppInactive()"/>
</menu>
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index c08c1a3..9429d9b 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -16,12 +16,16 @@
package com.android.tests.usagestats;
+import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
+import android.text.InputType;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -30,6 +34,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.EditText;
import android.widget.TextView;
import java.util.ArrayList;
@@ -69,6 +74,9 @@
case R.id.log:
startActivity(new Intent(this, UsageLogActivity.class));
return true;
+ case R.id.call_is_app_inactive:
+ callIsAppInactive();
+ return true;
default:
return super.onOptionsItemSelected(item);
@@ -81,6 +89,41 @@
updateAdapter();
}
+ private void callIsAppInactive() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Enter package name");
+ final EditText input = new EditText(this);
+ input.setInputType(InputType.TYPE_CLASS_TEXT);
+ input.setHint("com.android.tests.usagestats");
+ builder.setView(input);
+
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final String packageName = input.getText().toString().trim();
+ if (!TextUtils.isEmpty(packageName)) {
+ showInactive(packageName);
+ }
+ }
+ });
+ builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
+ private void showInactive(String packageName) {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage(
+ "isAppInactive(\"" + packageName + "\") = "
+ + (mUsageStatsManager.isAppInactive(packageName) ? "true" : "false"));
+ builder.show();
+ }
+
private void updateAdapter() {
long now = System.currentTimeMillis();
long beginTime = now - USAGE_STATS_PERIOD;
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index c1f0038..f0163be 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -107,7 +107,7 @@
public void logTree() {
if (mAssistStructure != null) {
- mAssistStructure.dump();
+ mAssistStructure.dump(true);
}
}
diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java
new file mode 100644
index 0000000..7fd7a63
--- /dev/null
+++ b/tests/net/java/android/net/util/SharedLogTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Vector;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SharedLogTest {
+ private static final String TIMESTAMP_PATTERN =
+ "^[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]";
+ private static final String TIMESTAMP = "mm-dd HH:MM:SS.xxx";
+
+ @Test
+ public void testBasicOperation() {
+ final SharedLog logTop = new SharedLog("top");
+ logTop.mark("first post!");
+
+ final SharedLog logLevel2a = logTop.forSubComponent("twoA");
+ final SharedLog logLevel2b = logTop.forSubComponent("twoB");
+ logLevel2b.e("2b or not 2b");
+ logLevel2a.w("second post?");
+
+ final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
+ logTop.log("still logging");
+ logLevel3.log("3 >> 2");
+ logLevel2a.mark("ok: last post");
+
+ final String[] expected = {
+ TIMESTAMP + " - MARK first post!",
+ TIMESTAMP + " - [twoB] ERROR 2b or not 2b",
+ TIMESTAMP + " - [twoA] WARN second post?",
+ TIMESTAMP + " - still logging",
+ TIMESTAMP + " - [twoA.three] 3 >> 2",
+ TIMESTAMP + " - [twoA] MARK ok: last post",
+ };
+ // Verify the logs are all there and in the correct order.
+ verifyLogLines(expected, logTop);
+
+ // In fact, because they all share the same underlying LocalLog,
+ // every subcomponent SharedLog's dump() is identical.
+ verifyLogLines(expected, logLevel2a);
+ verifyLogLines(expected, logLevel2b);
+ verifyLogLines(expected, logLevel3);
+ }
+
+ private static void verifyLogLines(String[] expected, SharedLog log) {
+ final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+ final PrintWriter pw = new PrintWriter(ostream, true);
+ log.dump(null, pw, null);
+
+ final String dumpOutput = ostream.toString();
+ assertTrue(dumpOutput != null);
+ assertTrue(!"".equals(dumpOutput));
+
+ final String[] lines = dumpOutput.split("\n");
+ assertEquals(expected.length, lines.length);
+
+ for (int i = 0; i < lines.length; i++) {
+ // Fix up the timestamps.
+ lines[i] = lines[i].replaceAll(TIMESTAMP_PATTERN, TIMESTAMP);
+ }
+
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], lines[i]);
+ }
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 0099861..e8a87c7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -362,6 +362,10 @@
mNetworkAgent.sendNetworkScore(mScore);
}
+ public void explicitlySelected(boolean acceptUnvalidated) {
+ mNetworkAgent.explicitlySelected(acceptUnvalidated);
+ }
+
public void addCapability(int capability) {
mNetworkCapabilities.addCapability(capability);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
@@ -797,6 +801,7 @@
// Ensure that the default setting for Captive Portals is used for most tests
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
+ setMobileDataAlwaysOn(false);
}
public void tearDown() throws Exception {
@@ -1595,13 +1600,104 @@
final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
+ // Register a TRACK_DEFAULT request and check that it does not affect lingering.
+ TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(trackDefaultCallback);
+ trackDefaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent.connect(true);
+ callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+ callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+ trackDefaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+
+ // Let linger run its course.
+ callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
+
// Clean up.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ mEthernetNetworkAgent.disconnect();
+ callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ trackDefaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(trackDefaultCallback);
+ }
+
+ @SmallTest
+ public void testExplicitlySelected() {
+ NetworkRequest request = new NetworkRequest.Builder()
+ .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Bring up validated cell.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+
+ // Bring up unvalidated wifi with explicitlySelected=true.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(false);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+
+ // Cell Remains the default.
+ assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ // Lower wifi's score to below than cell, and check that it doesn't disconnect because
+ // it's explicitly selected.
+ mWiFiNetworkAgent.adjustScore(-40);
+ mWiFiNetworkAgent.adjustScore(40);
+ callback.assertNoCallback();
+
+ // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
+ // wifi even though it's unvalidated.
+ mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
+ callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(false);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+
+ // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
+ // network to disconnect.
+ mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
+ callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+
+ // Reconnect, again with explicitlySelected=true, but this time validate.
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.explicitlySelected(false);
+ mWiFiNetworkAgent.connect(true);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+
+ // BUG: the network will no longer linger, even though it's validated and outscored.
+ // TODO: fix this.
+ mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent.connect(true);
+ callback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
+ assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ callback.assertNoCallback();
+
+ // Clean up.
+ mWiFiNetworkAgent.disconnect();
+ mCellNetworkAgent.disconnect();
+ mEthernetNetworkAgent.disconnect();
+
+ callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
}
private void tryNetworkFactoryRequests(int capability) throws Exception {
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 3172c6e..bc89c0f 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -56,6 +56,8 @@
import android.telephony.CarrierConfigManager;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.server.connectivity.tethering.OffloadHardwareInterface;
+import com.android.server.connectivity.tethering.TetheringDependencies;
import org.junit.After;
import org.junit.Before;
@@ -78,7 +80,9 @@
@Mock private INetworkStatsService mStatsService;
@Mock private INetworkPolicyManager mPolicyManager;
@Mock private MockableSystemProperties mSystemProperties;
+ @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
+ @Mock private TetheringDependencies mTetheringDependencies;
@Mock private UsbManager mUsbManager;
@Mock private WifiManager mWifiManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@@ -138,8 +142,11 @@
};
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ when(mTetheringDependencies.getOffloadHardwareInterface())
+ .thenReturn(mOffloadHardwareInterface);
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
- mLooper.getLooper(), mSystemProperties);
+ mLooper.getLooper(), mSystemProperties,
+ mTetheringDependencies);
}
@After
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index a3f33dc..27e683c 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -38,6 +38,7 @@
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
+import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -63,12 +64,14 @@
@Mock private IControlsTethering mTetherHelper;
@Mock private InterfaceConfiguration mInterfaceConfiguration;
@Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
+ @Mock private SharedLog mSharedLog;
private final TestLooper mLooper = new TestLooper();
private TetherInterfaceStateMachine mTestedSm;
private void initStateMachine(int interfaceType) throws Exception {
- mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
+ mTestedSm = new TetherInterfaceStateMachine(
+ IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
@@ -90,12 +93,13 @@
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
}
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
new file mode 100644
index 0000000..9fcd1b5
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED;
+import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.test.BroadcastInterceptingContext;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TetheringConfigurationTest {
+ @Mock private Context mContext;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private Resources mResources;
+ private Context mMockContext;
+ private boolean mHasTelephonyManager;
+
+ private class MockContext extends BroadcastInterceptingContext {
+ MockContext(Context base) {
+ super(base);
+ }
+
+ @Override
+ public Resources getResources() { return mResources; }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.TELEPHONY_SERVICE.equals(name)) {
+ return mHasTelephonyManager ? mTelephonyManager : null;
+ }
+ return super.getSystemService(name);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ mMockContext = new MockContext(mContext);
+ }
+
+ @Test
+ public void testDunFromTelephonyManagerMeansDun() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI});
+ mHasTelephonyManager = true;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+ assertTrue(cfg.isDunRequired);
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+ assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
+ assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
+ // Just to prove we haven't clobbered Wi-Fi:
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+ }
+
+ @Test
+ public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI});
+ mHasTelephonyManager = true;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+ assertFalse(cfg.isDunRequired);
+ assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
+ // Just to prove we haven't clobbered Wi-Fi:
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+ }
+
+ @Test
+ public void testDunFromUpstreamConfigMeansDun() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{TYPE_MOBILE_DUN, TYPE_WIFI});
+ mHasTelephonyManager = false;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+ assertTrue(cfg.isDunRequired);
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
+ // Just to prove we haven't clobbered Wi-Fi:
+ assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_WIFI));
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index c72efb0..9bb392a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -25,11 +25,13 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Handler;
@@ -40,6 +42,7 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.util.SharedLog;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -69,6 +72,7 @@
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
+ @Mock private SharedLog mLog;
private TestStateMachine mSM;
private TestConnectivityManager mCM;
@@ -78,10 +82,12 @@
MockitoAnnotations.initMocks(this);
reset(mContext);
reset(mCS);
+ reset(mLog);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
mCM = spy(new TestConnectivityManager(mContext, mCS));
mSM = new TestStateMachine();
- mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM, mLog);
}
@After public void tearDown() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index bb8f9d1..e6b1c6d 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -25,6 +25,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.support.test.filters.SmallTest;
import android.telephony.TelephonyManager;
import com.android.server.LocalServices;
@@ -34,6 +35,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@SmallTest
public class NetworkStatsAccessTest extends TestCase {
private static final String TEST_PKG = "com.example.test";
private static final int TEST_UID = 12345;
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 9f53c87..2a32b73 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -31,11 +31,11 @@
import android.os.Process;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.MediumTest;
-import com.android.frameworks.servicestests.R;
+import com.android.frameworks.tests.net.R;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -51,7 +51,7 @@
/**
* Tests for {@link NetworkStatsCollection}.
*/
-@MediumTest
+@SmallTest
public class NetworkStatsCollectionTest extends AndroidTestCase {
private static final String TEST_FILE = "test.bin";
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
index 5eee7b9..fe7840d 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsObserversTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java
@@ -38,16 +38,16 @@
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
+import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Process;
-
-import android.os.ConditionVariable;
import android.os.Looper;
-import android.os.Messenger;
import android.os.Message;
+import android.os.Messenger;
+import android.os.Process;
import android.os.UserHandle;
+import android.support.test.filters.SmallTest;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -69,6 +69,7 @@
/**
* Tests for {@link NetworkStatsObservers}.
*/
+@SmallTest
public class NetworkStatsObserversTest extends TestCase {
private static final String TEST_IFACE = "test0";
private static final String TEST_IFACE2 = "test1";
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 728eb73..029693f 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -85,6 +85,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
@@ -119,6 +120,7 @@
* still uses the Easymock structure, which could be simplified.
*/
@RunWith(AndroidJUnit4.class)
+@SmallTest
public class NetworkStatsServiceTest {
private static final String TAG = "NetworkStatsServiceTest";
diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/tests/net/res/raw/netstats_uid_v4
similarity index 100%
rename from services/tests/servicestests/res/raw/netstats_uid_v4
rename to tests/net/res/raw/netstats_uid_v4
Binary files differ
diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/tests/net/res/raw/netstats_v1
similarity index 100%
rename from services/tests/servicestests/res/raw/netstats_v1
rename to tests/net/res/raw/netstats_v1
Binary files differ
diff --git a/tests/radio/Android.mk b/tests/radio/Android.mk
index 46bf9cc..dc55d0b 100644
--- a/tests/radio/Android.mk
+++ b/tests/radio/Android.mk
@@ -22,7 +22,7 @@
# TODO(b/13282254): uncomment when b/13282254 is fixed
# LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/radio/src/android/hardware/radio/tests/RadioTest.java b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
index 25432e3..47e104c 100644
--- a/tests/radio/src/android/hardware/radio/tests/RadioTest.java
+++ b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
@@ -21,6 +21,7 @@
import android.hardware.radio.RadioTuner;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
@@ -28,7 +29,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -47,12 +47,14 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.testng.Assert.assertThrows;
/**
* A test for broadcast radio API.
*/
@RunWith(AndroidJUnit4.class)
public class RadioTest {
+ private static final String TAG = "RadioTest";
public final Context mContext = InstrumentationRegistry.getContext();
@@ -62,6 +64,7 @@
private RadioManager mRadioManager;
private RadioTuner mRadioTuner;
+ private RadioManager.ModuleProperties mModule;
private final List<RadioManager.ModuleProperties> mModules = new ArrayList<>();
@Mock private RadioTuner.Callback mCallback;
@@ -112,8 +115,8 @@
assertNull(mRadioTuner);
// find FM band and build its config
- RadioManager.ModuleProperties module = mModules.get(0);
- for (RadioManager.BandDescriptor band : module.getBands()) {
+ mModule = mModules.get(0);
+ for (RadioManager.BandDescriptor band : mModule.getBands()) {
if (band.getType() == RadioManager.BAND_AM) {
mAmBandDescriptor = (RadioManager.AmBandDescriptor)band;
}
@@ -126,7 +129,7 @@
mAmBandConfig = new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build();
mFmBandConfig = new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build();
- mRadioTuner = mRadioManager.openTuner(module.getId(),
+ mRadioTuner = mRadioManager.openTuner(mModule.getId(),
mFmBandConfig, withAudio, mCallback, null);
assertNotNull(mRadioTuner);
verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any());
@@ -134,9 +137,8 @@
}
private void checkAntenna() {
- // TODO(b/36863239): enable check when isAntennaConnected is implemented
- //boolean isConnected = mRadioTuner.isAntennaConnected();
- //assertTrue(isConnected);
+ boolean isConnected = mRadioTuner.isAntennaConnected();
+ assertTrue(isConnected);
}
@Test
@@ -154,6 +156,21 @@
}
@Test
+ public void testDoubleClose() {
+ openTuner();
+ mRadioTuner.close();
+ mRadioTuner.close();
+ }
+
+ @Test
+ public void testUseAfterClose() {
+ openTuner();
+ mRadioTuner.close();
+ int ret = mRadioTuner.cancel();
+ assertEquals(RadioManager.STATUS_INVALID_OPERATION, ret);
+ }
+
+ @Test
public void testSetAndGetConfiguration() {
openTuner();
@@ -304,4 +321,55 @@
verify(mCallback, after(kCancelTimeoutMs).atMost(1)).onError(RadioTuner.ERROR_CANCELLED);
verify(mCallback, atMost(1)).onProgramInfoChanged(any());
}
+
+ @Test
+ public void testStartBackgroundScan() {
+ openTuner();
+ checkAntenna();
+
+ boolean ret = mRadioTuner.startBackgroundScan();
+ boolean isSupported = mModule.isBackgroundScanningSupported();
+ assertEquals(isSupported, ret);
+ }
+
+ @Test
+ public void testGetProgramList() {
+ openTuner();
+ checkAntenna();
+
+ try {
+ List<RadioManager.ProgramInfo> list = mRadioTuner.getProgramList(null);
+ assertNotNull(list);
+ } catch (IllegalStateException e) {
+ // the list may or may not be ready at this point
+ Log.i(TAG, "Background list is not ready");
+ }
+ }
+
+ @Test
+ public void testForcedAnalog() {
+ openTuner();
+
+ boolean isSupported = true;
+ boolean isForced;
+ try {
+ isForced = mRadioTuner.isAnalogForced();
+ assertFalse(isForced);
+ } catch (IllegalStateException ex) {
+ Log.i(TAG, "Forced analog switch is not supported by this tuner");
+ isSupported = false;
+ }
+
+ if (isSupported) {
+ mRadioTuner.setAnalogForced(true);
+ isForced = mRadioTuner.isAnalogForced();
+ assertTrue(isForced);
+
+ mRadioTuner.setAnalogForced(false);
+ isForced = mRadioTuner.isAnalogForced();
+ assertFalse(isForced);
+ } else {
+ assertThrows(IllegalStateException.class, () -> mRadioTuner.setAnalogForced(true));
+ }
+ }
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 6dfabf1..10244da 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -34,42 +34,43 @@
namespace aapt {
-constexpr const char* sXliffNamespaceUri =
- "urn:oasis:names:tc:xliff:document:1.2";
+constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
-/**
- * Returns true if the element is <skip> or <eat-comment> and can be safely
- * ignored.
- */
-static bool ShouldIgnoreElement(const StringPiece& ns,
- const StringPiece& name) {
+// Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
+static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
return ns.empty() && (name == "skip" || name == "eat-comment");
}
-static uint32_t ParseFormatType(const StringPiece& piece) {
- if (piece == "reference")
+static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
+ if (piece == "reference") {
return android::ResTable_map::TYPE_REFERENCE;
- else if (piece == "string")
+ } else if (piece == "string") {
return android::ResTable_map::TYPE_STRING;
- else if (piece == "integer")
+ } else if (piece == "integer") {
return android::ResTable_map::TYPE_INTEGER;
- else if (piece == "boolean")
+ } else if (piece == "boolean") {
return android::ResTable_map::TYPE_BOOLEAN;
- else if (piece == "color")
+ } else if (piece == "color") {
return android::ResTable_map::TYPE_COLOR;
- else if (piece == "float")
+ } else if (piece == "float") {
return android::ResTable_map::TYPE_FLOAT;
- else if (piece == "dimension")
+ } else if (piece == "dimension") {
return android::ResTable_map::TYPE_DIMENSION;
- else if (piece == "fraction")
+ } else if (piece == "fraction") {
return android::ResTable_map::TYPE_FRACTION;
- else if (piece == "enum")
- return android::ResTable_map::TYPE_ENUM;
- else if (piece == "flags")
- return android::ResTable_map::TYPE_FLAGS;
+ }
return 0;
}
+static uint32_t ParseFormatType(const StringPiece& piece) {
+ if (piece == "enum") {
+ return android::ResTable_map::TYPE_ENUM;
+ } else if (piece == "flags") {
+ return android::ResTable_map::TYPE_FLAGS;
+ }
+ return ParseFormatTypeNoEnumsOrFlags(piece);
+}
+
static uint32_t ParseFormatAttribute(const StringPiece& str) {
uint32_t mask = 0;
for (StringPiece part : util::Tokenize(str, '|')) {
@@ -83,9 +84,7 @@
return mask;
}
-/**
- * A parsed resource ready to be added to the ResourceTable.
- */
+// A parsed resource ready to be added to the ResourceTable.
struct ParsedResource {
ResourceName name;
ConfigDescription config;
@@ -416,8 +415,7 @@
can_be_bag = false;
// Items have their type encoded in the type attribute.
- if (Maybe<StringPiece> maybe_type =
- xml::FindNonEmptyAttribute(parser, "type")) {
+ if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
resource_type = maybe_type.value().to_string();
} else {
diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
@@ -425,13 +423,11 @@
return false;
}
- if (Maybe<StringPiece> maybe_format =
- xml::FindNonEmptyAttribute(parser, "format")) {
+ if (Maybe<StringPiece> maybe_format = xml::FindNonEmptyAttribute(parser, "format")) {
// An explicit format for this resource was specified. The resource will
- // retain
- // its type in its name, but the accepted value for this type is
+ // retain its type in its name, but the accepted value for this type is
// overridden.
- resource_format = ParseFormatType(maybe_format.value());
+ resource_format = ParseFormatTypeNoEnumsOrFlags(maybe_format.value());
if (!resource_format) {
diag_->Error(DiagMessage(out_resource->source)
<< "'" << maybe_format.value()
@@ -1157,21 +1153,25 @@
return true;
}
-bool ResourceParser::ParseArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_ANY);
+bool ResourceParser::ParseArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ uint32_t resource_format = android::ResTable_map::TYPE_ANY;
+ if (Maybe<StringPiece> format_attr = xml::FindNonEmptyAttribute(parser, "format")) {
+ resource_format = ParseFormatTypeNoEnumsOrFlags(format_attr.value());
+ if (resource_format == 0u) {
+ diag_->Error(DiagMessage(source_.WithLine(parser->line_number()))
+ << "'" << format_attr.value() << "' is an invalid format");
+ return false;
+ }
+ }
+ return ParseArrayImpl(parser, out_resource, resource_format);
}
-bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource,
- android::ResTable_map::TYPE_INTEGER);
+bool ResourceParser::ParseIntegerArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_INTEGER);
}
-bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser,
- ParsedResource* out_resource) {
- return ParseArrayImpl(parser, out_resource,
- android::ResTable_map::TYPE_STRING);
+bool ResourceParser::ParseStringArray(xml::XmlPullParser* parser, ParsedResource* out_resource) {
+ return ParseArrayImpl(parser, out_resource, android::ResTable_map::TYPE_STRING);
}
bool ResourceParser::ParseArrayImpl(xml::XmlPullParser* parser,
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 8062c2e6..faa6607 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -571,14 +571,39 @@
}
TEST_F(ResourceParserTest, ParseStringArray) {
- std::string input =
- "<string-array name=\"foo\">\n"
- " <item>\"Werk\"</item>\n"
- "</string-array>\n";
+ std::string input = R"EOF(
+ <string-array name="foo">
+ <item>"Werk"</item>"
+ </string-array>)EOF";
ASSERT_TRUE(TestParse(input));
EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
}
+TEST_F(ResourceParserTest, ParseArrayWithFormat) {
+ std::string input = R"EOF(
+ <array name="foo" format="string">
+ <item>100</item>
+ </array>)EOF";
+ ASSERT_TRUE(TestParse(input));
+
+ Array* array = test::GetValue<Array>(&table_, "array/foo");
+ ASSERT_NE(nullptr, array);
+
+ ASSERT_EQ(1u, array->items.size());
+
+ String* str = ValueCast<String>(array->items[0].get());
+ ASSERT_NE(nullptr, str);
+ EXPECT_EQ(std::string("100"), *str->value);
+}
+
+TEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
+ std::string input = R"EOF(
+ <array name="foo" format="integer">
+ <item>Hi</item>
+ </array>)EOF";
+ ASSERT_FALSE(TestParse(input));
+}
+
TEST_F(ResourceParserTest, ParsePlural) {
std::string input =
"<plurals name=\"foo\">\n"
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index c192d69..5adf04a 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -372,6 +372,8 @@
if (file_type == file::FileType::kDirectory) {
context->GetDiagnostics()->Error(DiagMessage(input_path)
<< "resource file cannot be a directory");
+ } else if (file_type == file::FileType::kNonexistant) {
+ context->GetDiagnostics()->Error(DiagMessage(input_path) << "file not found");
} else {
context->GetDiagnostics()->Error(DiagMessage(input_path)
<< "not a valid resource file");
@@ -488,7 +490,7 @@
// Ensure that we only keep the chunks we care about if we end up
// using the original PNG instead of the crunched one.
PngChunkFilter png_chunk_filter(content);
- std::unique_ptr<Image> image = ReadPng(context, &png_chunk_filter);
+ std::unique_ptr<Image> image = ReadPng(context, path_data.source, &png_chunk_filter);
if (!image) {
return false;
}
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index e4255e7..7ca1f0e 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -69,7 +69,12 @@
bool Rewind() override;
size_t ByteCount() const override { return window_start_; }
- bool HadError() const override { return error_; }
+ bool HadError() const override {
+ return !error_msg_.empty();
+ }
+ std::string GetError() const override {
+ return error_msg_;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(PngChunkFilter);
@@ -79,13 +84,13 @@
android::StringPiece data_;
size_t window_start_ = 0;
size_t window_end_ = 0;
- bool error_ = false;
+ std::string error_msg_;
};
/**
* Reads a PNG from the InputStream into memory as an RGBA Image.
*/
-std::unique_ptr<Image> ReadPng(IAaptContext* context, io::InputStream* in);
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in);
/**
* Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index f9043b5..7073c13 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -16,11 +16,13 @@
#include "compile/Png.h"
+#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "io/Io.h"
using android::StringPiece;
+using android::base::StringPrintf;
namespace aapt {
@@ -73,7 +75,7 @@
window_start_ = 0;
window_end_ = kPngSignatureSize;
} else {
- error_ = true;
+ error_msg_ = "PNG does not start with PNG signature";
}
}
@@ -90,7 +92,7 @@
}
bool PngChunkFilter::Next(const void** buffer, size_t* len) {
- if (error_) {
+ if (HadError()) {
return false;
}
@@ -106,16 +108,21 @@
const size_t kMinChunkHeaderSize = 3 * sizeof(uint32_t);
// Is there enough room for a chunk header?
- if (data_.size() - window_start_ < kMinChunkHeaderSize) {
- error_ = true;
+ if (data_.size() - window_end_ < kMinChunkHeaderSize) {
+ error_msg_ = StringPrintf("Not enough space for a PNG chunk @ byte %zu/%zu", window_end_,
+ data_.size());
return false;
}
// Verify the chunk length.
const uint32_t chunk_len = Peek32LE(data_.data() + window_end_);
- if (((uint64_t)chunk_len) + ((uint64_t)window_end_) + sizeof(uint32_t) > data_.size()) {
+ if ((size_t)chunk_len > data_.size() - window_end_ - kMinChunkHeaderSize) {
// Overflow.
- error_ = true;
+ const uint32_t chunk_type = Peek32LE(data_.data() + window_end_ + sizeof(uint32_t));
+ error_msg_ = StringPrintf(
+ "PNG chunk type %08x is too large: chunk length is %zu but chunk "
+ "starts at byte %zu/%zu",
+ chunk_type, (size_t)chunk_len, window_end_ + kMinChunkHeaderSize, data_.size());
return false;
}
@@ -124,6 +131,16 @@
if (IsPngChunkWhitelisted(chunk_type)) {
// Advance the window to include this chunk.
window_end_ += kMinChunkHeaderSize + chunk_len;
+
+ // Special case the IEND chunk, which MUST appear last and libpng stops parsing once it hits
+ // such a chunk (let's do the same).
+ if (chunk_type == kPngChunkIEND) {
+ // Truncate the data to the end of this chunk. There may be garbage trailing after
+ // (b/38169876)
+ data_ = data_.substr(0, window_end_);
+ break;
+ }
+
} else {
// We want to strip this chunk. If we accumulated a window,
// we must return the window now.
@@ -145,14 +162,14 @@
}
void PngChunkFilter::BackUp(size_t count) {
- if (error_) {
+ if (HadError()) {
return;
}
window_start_ -= count;
}
bool PngChunkFilter::Rewind() {
- if (error_) {
+ if (HadError()) {
return false;
}
window_start_ = 0;
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
index ae98afc..42443d8 100644
--- a/tools/aapt2/compile/PngCrunch.cpp
+++ b/tools/aapt2/compile/PngCrunch.cpp
@@ -73,6 +73,11 @@
static void LogError(png_structp png_ptr, png_const_charp error_msg) {
IDiagnostics* diag = (IDiagnostics*)png_get_error_ptr(png_ptr);
diag->Error(DiagMessage() << error_msg);
+
+ // Causes libpng to longjmp to the spot where setjmp was set. This is how libpng does
+ // error handling. If this custom error handler method were to return, libpng would, by
+ // default, print the error message to stdout and call the same png_longjmp method.
+ png_longjmp(png_ptr, 1);
}
static void ReadDataFromStream(png_structp png_ptr, png_bytep buffer, png_size_t len) {
@@ -82,7 +87,12 @@
size_t in_len;
if (!in->Next(&in_buffer, &in_len)) {
if (in->HadError()) {
- std::string err = in->GetError();
+ std::stringstream error_msg_builder;
+ error_msg_builder << "failed reading from input";
+ if (!in->GetError().empty()) {
+ error_msg_builder << ": " << in->GetError();
+ }
+ std::string err = error_msg_builder.str();
png_error(png_ptr, err.c_str());
}
return;
@@ -103,6 +113,11 @@
while (len > 0) {
if (!out->Next(&out_buffer, &out_len)) {
if (out->HadError()) {
+ std::stringstream err_msg_builder;
+ err_msg_builder << "failed writing to output";
+ if (!out->GetError().empty()) {
+ err_msg_builder << ": " << out->GetError();
+ }
std::string err = out->GetError();
png_error(png_ptr, err.c_str());
}
@@ -126,7 +141,7 @@
}
}
-std::unique_ptr<Image> ReadPng(IAaptContext* context, io::InputStream* in) {
+std::unique_ptr<Image> ReadPng(IAaptContext* context, const Source& source, io::InputStream* in) {
// Read the first 8 bytes of the file looking for the PNG signature.
// Bail early if it does not match.
const png_byte* signature;
@@ -163,6 +178,9 @@
return {};
}
+ // Create a diagnostics that has the source information encoded.
+ SourcePathDiagnostics source_diag(source, context->GetDiagnostics());
+
// Automatically release PNG resources at end of scope.
PngReadStructDeleter png_read_deleter(read_ptr, info_ptr);
@@ -174,7 +192,7 @@
}
// Handle warnings ourselves via IDiagnostics.
- png_set_error_fn(read_ptr, (png_voidp)context->GetDiagnostics(), LogError, LogWarning);
+ png_set_error_fn(read_ptr, (png_voidp)&source_diag, LogError, LogWarning);
// Set up the read functions which read from our custom data sources.
png_set_read_fn(read_ptr, (png_voidp)in, ReadDataFromStream);
@@ -231,8 +249,8 @@
// something
// that can always be represented by 9-patch.
if (width > std::numeric_limits<int32_t>::max() || height > std::numeric_limits<int32_t>::max()) {
- context->GetDiagnostics()->Error(
- DiagMessage() << "PNG image dimensions are too large: " << width << "x" << height);
+ source_diag.Error(DiagMessage()
+ << "PNG image dimensions are too large: " << width << "x" << height);
return {};
}
diff --git a/tools/aapt2/filter/ConfigFilter.cpp b/tools/aapt2/filter/ConfigFilter.cpp
index 66aff82..5fbe77e 100644
--- a/tools/aapt2/filter/ConfigFilter.cpp
+++ b/tools/aapt2/filter/ConfigFilter.cpp
@@ -38,6 +38,43 @@
config_mask_ |= diff_mask;
}
+// Returns true if the locale script of the config should be considered matching
+// the locale script of entry.
+//
+// If both the scripts are empty, the scripts are considered matching for
+// backward compatibility reasons.
+//
+// If only one script is empty, we try to compute it based on the provided
+// language and country. If we could not compute it, we assume it's either a
+// new language we don't know about, or a private use language. We return true
+// since we don't know any better and they might as well be a match.
+//
+// Finally, when we have two scripts (one of which could be computed), we return
+// true if and only if they are an exact match.
+static bool ScriptsMatch(const ConfigDescription& config, const ConfigDescription& entry) {
+ const char* config_script = config.localeScript;
+ const char* entry_script = entry.localeScript;
+ if (config_script[0] == '\0' && entry_script[0] == '\0') {
+ return true; // both scripts are empty. We match for backward compatibility reasons.
+ }
+
+ char script_buffer[sizeof(config.localeScript)];
+ if (config_script[0] == '\0') {
+ android::localeDataComputeScript(script_buffer, config.language, config.country);
+ if (script_buffer[0] == '\0') { // We can't compute the script, so we match.
+ return true;
+ }
+ config_script = script_buffer;
+ } else if (entry_script[0] == '\0') {
+ android::localeDataComputeScript(script_buffer, entry.language, entry.country);
+ if (script_buffer[0] == '\0') { // We can't compute the script, so we match.
+ return true;
+ }
+ entry_script = script_buffer;
+ }
+ return memcmp(config_script, entry_script, sizeof(config.localeScript)) == 0;
+}
+
bool AxisConfigFilter::Match(const ConfigDescription& config) const {
const uint32_t mask = ConfigDescription::DefaultConfig().diff(config);
if ((config_mask_ & mask) == 0) {
@@ -57,12 +94,16 @@
// If the locales differ, but the languages are the same and
// the locale we are matching only has a language specified,
// we match.
- if (config.language[0] &&
- memcmp(config.language, target.language, sizeof(config.language)) ==
- 0) {
- if (config.country[0] == 0) {
- matched_axis |= android::ResTable_config::CONFIG_LOCALE;
- }
+ //
+ // Exception: we won't match if a script is specified for at least
+ // one of the locales and it's different from the other locale's
+ // script. (We will compute the other script if at least one of the
+ // scripts were explicitly set. In cases we can't compute an script,
+ // we match.)
+ if (config.language[0] != '\0' && config.country[0] == '\0' &&
+ config.localeVariant[0] == '\0' && config.language[0] == entry.first.language[0] &&
+ config.language[1] == entry.first.language[1] && ScriptsMatch(config, entry.first)) {
+ matched_axis |= android::ResTable_config::CONFIG_LOCALE;
}
} else if ((diff & diff_mask) ==
android::ResTable_config::CONFIG_SMALLEST_SCREEN_SIZE) {
diff --git a/tools/aapt2/filter/ConfigFilter_test.cpp b/tools/aapt2/filter/ConfigFilter_test.cpp
index 586dd5f..4a31080 100644
--- a/tools/aapt2/filter/ConfigFilter_test.cpp
+++ b/tools/aapt2/filter/ConfigFilter_test.cpp
@@ -109,4 +109,20 @@
EXPECT_TRUE(filter.Match(test::ParseConfigOrDie("kok-rIN")));
}
+TEST(ConfigFilterTest, MatchesScripts) {
+ AxisConfigFilter filter;
+
+ // "sr" gets automatically computed the script "Cyrl"
+ filter.AddConfig(test::ParseConfigOrDie("sr"));
+
+ // "sr" -> "b+sr+Cyrl"
+ EXPECT_TRUE(filter.Match(test::ParseConfigOrDie("b+sr+Cyrl")));
+
+ // The incoming "sr" is also auto-computed to "b+sr+Cyrl".
+ EXPECT_TRUE(filter.Match(test::ParseConfigOrDie("sr")));
+
+ // "sr" -> "b+sr+Cyrl", which doesn't match "Latn".
+ EXPECT_FALSE(filter.Match(test::ParseConfigOrDie("b+sr+Latn")));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
index 1156b01..1a4067f 100644
--- a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -17,4 +17,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.aapt.app.one" coreApp="true">
<uses-sdk android:minSdkVersion="21" />
+
+ <uses-permission-sdk-23 android:name="android.permission.TEST" android:maxSdkVersion="22" />
</manifest>
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index f998d31..53c66a6 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -295,6 +295,7 @@
manifest_action["original-package"];
manifest_action["protected-broadcast"];
manifest_action["uses-permission"];
+ manifest_action["uses-permission-sdk-23"];
manifest_action["permission"];
manifest_action["permission-tree"];
manifest_action["permission-group"];
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e59b74f..cda078a 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -452,6 +452,15 @@
public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
/**
+ * Interface IP mode unspecified.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
+
+ /**
* Interface IP mode for configuration error.
*
* @see updateInterfaceIpState(String, int)
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index 92c7e36..ebf5c2a 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -139,7 +139,7 @@
public String getDeviceInfoHex() {
return String.format(
- Locale.US, "%04x%04x%04x%04x", 6, mDeviceInfo, mCtrlPort, mMaxThroughput);
+ Locale.US, "%04x%04x%04x", mDeviceInfo, mCtrlPort, mMaxThroughput);
}
public String toString() {