Merge "Import translations. DO NOT MERGE" into oc-mr1-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index 38d3e2f..27d3ee4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6,12 +6,13 @@
public static final class Manifest.permission {
ctor public Manifest.permission();
+ field public static final java.lang.String ACCESS_BROADCAST_RADIO = "android.permission.ACCESS_BROADCAST_RADIO";
field public static final java.lang.String ACCESS_CACHE_FILESYSTEM = "android.permission.ACCESS_CACHE_FILESYSTEM";
field public static final java.lang.String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
field public static final java.lang.String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
field public static final java.lang.String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES";
field public static final java.lang.String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
- field public static final java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
+ field public static final deprecated java.lang.String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO";
field public static final java.lang.String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
field public static final java.lang.String ACCESS_MTP = "android.permission.ACCESS_MTP";
@@ -11222,6 +11223,7 @@
method public void setDontKillApp(boolean);
method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallAsInstantApp(boolean);
+ method public void setInstallAsVirtualPreload();
method public void setInstallLocation(int);
method public void setInstallReason(int);
method public void setOriginatingUid(int);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index bdf0562..ea675fb 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1186,6 +1186,16 @@
}
/**
+ * Sets the install as a virtual preload. Will only have effect when called
+ * by the verifier.
+ * {@hide}
+ */
+ @SystemApi
+ public void setInstallAsVirtualPreload() {
+ installFlags |= PackageManager.INSTALL_VIRTUAL_PRELOAD;
+ }
+
+ /**
* Set the reason for installing this package.
*/
public void setInstallReason(@InstallReason int installReason) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 040f85b..cc197a2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -809,6 +809,14 @@
*/
public static final int INSTALL_ALLOCATE_AGGRESSIVE = 0x00008000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that this package
+ * is a virtual preload.
+ *
+ * @hide
+ */
+ public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;
+
/** @hide */
@IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
DONT_KILL_APP
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index abbd793..3a3646b 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.LeakyTypefaceStorage;
import android.graphics.Typeface;
import android.os.Parcel;
import android.text.ParcelableSpan;
@@ -30,11 +31,12 @@
* resource.
*/
public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
- private final String mTypeface;
+ private final String mFamilyName;
private final int mStyle;
private final int mTextSize;
private final ColorStateList mTextColor;
private final ColorStateList mTextColorLink;
+ private final Typeface mTypeface;
/**
* Uses the specified TextAppearance resource to determine the
@@ -55,7 +57,7 @@
*/
public TextAppearanceSpan(Context context, int appearance, int colorList) {
ColorStateList textColor;
-
+
TypedArray a =
context.obtainStyledAttributes(appearance,
com.android.internal.R.styleable.TextAppearance);
@@ -68,28 +70,33 @@
TextAppearance_textSize, -1);
mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0);
- String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily);
- if (family != null) {
- mTypeface = family;
+ mTypeface = a.getFont(com.android.internal.R.styleable.TextAppearance_fontFamily);
+ if (mTypeface != null) {
+ mFamilyName = null;
} else {
- int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0);
+ String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily);
+ if (family != null) {
+ mFamilyName = family;
+ } else {
+ int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0);
- switch (tf) {
- case 1:
- mTypeface = "sans";
- break;
+ switch (tf) {
+ case 1:
+ mFamilyName = "sans";
+ break;
- case 2:
- mTypeface = "serif";
- break;
+ case 2:
+ mFamilyName = "serif";
+ break;
- case 3:
- mTypeface = "monospace";
- break;
+ case 3:
+ mFamilyName = "monospace";
+ break;
- default:
- mTypeface = null;
- break;
+ default:
+ mFamilyName = null;
+ break;
+ }
}
}
@@ -102,7 +109,7 @@
textColor = a.getColorStateList(colorList);
a.recycle();
}
-
+
mTextColor = textColor;
}
@@ -112,15 +119,16 @@
*/
public TextAppearanceSpan(String family, int style, int size,
ColorStateList color, ColorStateList linkColor) {
- mTypeface = family;
+ mFamilyName = family;
mStyle = style;
mTextSize = size;
mTextColor = color;
mTextColorLink = linkColor;
+ mTypeface = null;
}
public TextAppearanceSpan(Parcel src) {
- mTypeface = src.readString();
+ mFamilyName = src.readString();
mStyle = src.readInt();
mTextSize = src.readInt();
if (src.readInt() != 0) {
@@ -133,8 +141,9 @@
} else {
mTextColorLink = null;
}
+ mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
}
-
+
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
@@ -143,7 +152,7 @@
public int getSpanTypeIdInternal() {
return TextUtils.TEXT_APPEARANCE_SPAN;
}
-
+
public int describeContents() {
return 0;
}
@@ -154,7 +163,7 @@
/** @hide */
public void writeToParcelInternal(Parcel dest, int flags) {
- dest.writeString(mTypeface);
+ dest.writeString(mFamilyName);
dest.writeInt(mStyle);
dest.writeInt(mTextSize);
if (mTextColor != null) {
@@ -169,6 +178,7 @@
} else {
dest.writeInt(0);
}
+ LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
}
/**
@@ -176,7 +186,7 @@
* if it does not specify one.
*/
public String getFamily() {
- return mTypeface;
+ return mFamilyName;
}
/**
@@ -226,9 +236,14 @@
@Override
public void updateMeasureState(TextPaint ds) {
- if (mTypeface != null || mStyle != 0) {
+ final Typeface styledTypeface;
+ int style = 0;
+
+ if (mTypeface != null) {
+ style = mStyle;
+ styledTypeface = Typeface.create(mTypeface, style);
+ } else if (mFamilyName != null || mStyle != 0) {
Typeface tf = ds.getTypeface();
- int style = 0;
if (tf != null) {
style = tf.getStyle();
@@ -236,15 +251,19 @@
style |= mStyle;
- if (mTypeface != null) {
- tf = Typeface.create(mTypeface, style);
+ if (mFamilyName != null) {
+ styledTypeface = Typeface.create(mFamilyName, style);
} else if (tf == null) {
- tf = Typeface.defaultFromStyle(style);
+ styledTypeface = Typeface.defaultFromStyle(style);
} else {
- tf = Typeface.create(tf, style);
+ styledTypeface = Typeface.create(tf, style);
}
+ } else {
+ styledTypeface = null;
+ }
- int fake = style & ~tf.getStyle();
+ if (styledTypeface != null) {
+ int fake = style & ~styledTypeface.getStyle();
if ((fake & Typeface.BOLD) != 0) {
ds.setFakeBoldText(true);
@@ -254,7 +273,7 @@
ds.setTextSkewX(-0.25f);
}
- ds.setTypeface(tf);
+ ds.setTypeface(styledTypeface);
}
if (mTextSize > 0) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 1e82054..9fa3239 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -22,6 +22,9 @@
import static android.system.OsConstants.STDERR_FILENO;
import static android.system.OsConstants.STDIN_FILENO;
import static android.system.OsConstants.STDOUT_FILENO;
+import static com.android.internal.os.ZygoteConnectionConstants.CONNECTION_TIMEOUT_MILLIS;
+import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC;
+import static com.android.internal.os.ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
import android.net.Credentials;
import android.net.LocalSocket;
@@ -56,18 +59,6 @@
private static final int[][] intArray2d = new int[0][0];
/**
- * {@link android.net.LocalSocket#setSoTimeout} value for connections.
- * Effectively, the amount of time a requestor has between the start of
- * the request and the completed request. The select-loop mode Zygote
- * doesn't have the logic to return to the select loop in the middle of
- * a request, so we need to time out here to avoid being denial-of-serviced.
- */
- private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
-
- /** max number of arguments that a connection can specify */
- private static final int MAX_ZYGOTE_ARGC = 1024;
-
- /**
* The command socket.
*
* mSocket is retained in the child process in "peer wait" mode, so
@@ -835,10 +826,6 @@
try {
// Do a busy loop here. We can't guarantee that a failure (and thus an exception
// bail) happens in a timely manner.
- //
- // We'll wait up to five seconds. This should give enough time for the fork to go
- // through, but not to trigger the watchdog in the system server.
- final int SLEEP_IN_MS = 5000;
final int BYTES_REQUIRED = 4; // Bytes in an int.
StructPollfd fds[] = new StructPollfd[] {
@@ -847,7 +834,7 @@
byte data[] = new byte[BYTES_REQUIRED];
- int remainingSleepTime = SLEEP_IN_MS;
+ int remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS;
int dataIndex = 0;
long startTime = System.nanoTime();
@@ -859,7 +846,8 @@
int res = android.system.Os.poll(fds, remainingSleepTime);
long endTime = System.nanoTime();
- remainingSleepTime = SLEEP_IN_MS - (int)((endTime - startTime) / 1000000l);
+ int elapsedTimeMs = (int)((endTime - startTime) / 1000000l);
+ remainingSleepTime = WRAPPED_PID_TIMEOUT_MILLIS - elapsedTimeMs;
if (res > 0) {
if ((fds[0].revents & POLLIN) != 0) {
diff --git a/core/java/com/android/internal/os/ZygoteConnectionConstants.java b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
new file mode 100644
index 0000000..506e39f
--- /dev/null
+++ b/core/java/com/android/internal/os/ZygoteConnectionConstants.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+/**
+ * Sharable zygote constants.
+ *
+ * @hide
+ */
+public class ZygoteConnectionConstants {
+ /**
+ * {@link android.net.LocalSocket#setSoTimeout} value for connections.
+ * Effectively, the amount of time a requestor has between the start of
+ * the request and the completed request. The select-loop mode Zygote
+ * doesn't have the logic to return to the select loop in the middle of
+ * a request, so we need to time out here to avoid being denial-of-serviced.
+ */
+ public static final int CONNECTION_TIMEOUT_MILLIS = 1000;
+
+ /** max number of arguments that a connection can specify */
+ public static final int MAX_ZYGOTE_ARGC = 1024;
+
+ /**
+ * Wait time for a wrapped app to report back its pid.
+ *
+ * We'll wait up to thirty seconds. This should give enough time for the fork
+ * to go through, but not to trigger the watchdog in the system server (by default
+ * sixty seconds).
+ *
+ * WARNING: This may trigger the watchdog in debug mode. However, to support
+ * wrapping on lower-end devices we do not have much choice.
+ */
+ public static final int WRAPPED_PID_TIMEOUT_MILLIS = 30000;
+}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 0dbe971..948f203 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -538,7 +538,7 @@
.asInterface(ServiceManager.getService("installd"));
final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
- String sharedLibraries = "";
+ String classPathForElement = "";
for (String classPathElement : classPathElements) {
// System server is fully AOTed and never profiled
// for profile guided compilation.
@@ -570,10 +570,12 @@
final String compilerFilter = systemServerFilter;
final String uuid = StorageManager.UUID_PRIVATE_INTERNAL;
final String seInfo = null;
+ final String classLoaderContext =
+ getSystemServerClassLoaderContext(classPathForElement);
try {
installd.dexopt(classPathElement, Process.SYSTEM_UID, packageName,
instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
- uuid, sharedLibraries, seInfo, false /* downgrade */);
+ uuid, classLoaderContext, seInfo, false /* downgrade */);
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -581,14 +583,36 @@
}
}
- if (!sharedLibraries.isEmpty()) {
- sharedLibraries += ":";
- }
- sharedLibraries += classPathElement;
+ classPathForElement = encodeSystemServerClassPath(
+ classPathForElement, classPathElement);
}
}
/**
+ * Encodes the system server class loader context in a format that is accepted by dexopt.
+ * This assumes the system server is always loaded with a {@link dalvik.system.PathClassLoader}.
+ *
+ * Note that ideally we would use the {@code DexoptUtils} to compute this. However we have no
+ * dependency here on the server so we hard code the logic again.
+ */
+ private static String getSystemServerClassLoaderContext(String classPath) {
+ return classPath == null ? "PCL[]" : "PCL[" + classPath + "]";
+ }
+
+ /**
+ * Encodes the class path in a format accepted by dexopt.
+ * @param classPath the old class path (may be empty).
+ * @param newElement the new class path elements
+ * @return the class path encoding resulted from appending {@code newElement} to
+ * {@code classPath}.
+ */
+ private static String encodeSystemServerClassPath(String classPath, String newElement) {
+ return (classPath == null || classPath.isEmpty())
+ ? newElement
+ : classPath + ":" + newElement;
+ }
+
+ /**
* Prepare the arguments and forks for the system server process.
*
* Returns an {@code Runnable} that provides an entrypoint into system_server code in the
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f36e1ad..d175422 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1527,7 +1527,12 @@
<permission android:name="android.permission.HARDWARE_TEST"
android:protectionLevel="signature" />
- <!-- @SystemApi Allows access to FM
+ <!-- @SystemApi Allows access to Broadcast Radio
+ @hide This is not a third-party API (intended for system apps).-->
+ <permission android:name="android.permission.ACCESS_BROADCAST_RADIO"
+ android:protectionLevel="signature|privileged" />
+
+ <!-- @deprecated @SystemApi Allows access to FM
@hide This is not a third-party API (intended for system apps).-->
<permission android:name="android.permission.ACCESS_FM_RADIO"
android:protectionLevel="signature|privileged" />
diff --git a/core/tests/BroadcastRadioTests/AndroidManifest.xml b/core/tests/BroadcastRadioTests/AndroidManifest.xml
index 0f7d4c7..d9b5522 100644
--- a/core/tests/BroadcastRadioTests/AndroidManifest.xml
+++ b/core/tests/BroadcastRadioTests/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.hardware.radio.tests">
- <uses-permission android:name="android.permission.ACCESS_FM_RADIO" />
+ <uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index 82abbf5..ee40c48 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -91,8 +91,8 @@
assumeTrue(isRadioSupported);
// Check radio access permission
- int res = mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FM_RADIO);
- assertEquals("ACCESS_FM_RADIO permission not granted",
+ int res = mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_BROADCAST_RADIO);
+ assertEquals("ACCESS_BROADCAST_RADIO permission not granted",
PackageManager.PERMISSION_GRANTED, res);
mRadioManager = (RadioManager)mContext.getSystemService(Context.RADIO_SERVICE);
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 19007f9..26741fe 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -107,7 +107,7 @@
<group gid="audio" />
</permission>
- <permission name="android.permission.ACCESS_FM_RADIO" >
+ <permission name="android.permission.ACCESS_BROADCAST_RADIO" >
<!-- /dev/fm is gid media, not audio -->
<group gid="media" />
</permission>
diff --git a/graphics/java/android/graphics/LeakyTypefaceStorage.java b/graphics/java/android/graphics/LeakyTypefaceStorage.java
new file mode 100644
index 0000000..618e60d
--- /dev/null
+++ b/graphics/java/android/graphics/LeakyTypefaceStorage.java
@@ -0,0 +1,86 @@
+/*
+ * 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.graphics;
+
+import com.android.internal.annotations.GuardedBy;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Process;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+
+/**
+ * This class is used for Parceling Typeface object.
+ * Note: Typeface object can not be passed over the process boundary.
+ *
+ * @hide
+ */
+public class LeakyTypefaceStorage {
+ private static final Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static final ArrayList<Typeface> sStorage = new ArrayList<>();
+ @GuardedBy("sLock")
+ private static final ArrayMap<Typeface, Integer> sTypefaceMap = new ArrayMap<>();
+
+ /**
+ * Write typeface to parcel.
+ *
+ * You can't transfer Typeface to a different process. {@link readTypefaceFromParcel} will
+ * return {@code null} if the {@link readTypefaceFromParcel} is called in a different process.
+ *
+ * @param typeface A {@link Typeface} to be written.
+ * @param parcel A {@link Parcel} object.
+ */
+ public static void writeTypefaceToParcel(@Nullable Typeface typeface, @NonNull Parcel parcel) {
+ parcel.writeInt(Process.myPid());
+ synchronized (sLock) {
+ final int id;
+ final Integer i = sTypefaceMap.get(typeface);
+ if (i != null) {
+ id = i.intValue();
+ } else {
+ id = sStorage.size();
+ sStorage.add(typeface);
+ sTypefaceMap.put(typeface, id);
+ }
+ parcel.writeInt(id);
+ }
+ }
+
+ /**
+ * Read typeface from parcel.
+ *
+ * If the {@link Typeface} was created in another process, this method returns null.
+ *
+ * @param parcel A {@link Parcel} object
+ * @return A {@link Typeface} object.
+ */
+ public static @Nullable Typeface readTypefaceFromParcel(@NonNull Parcel parcel) {
+ final int pid = parcel.readInt();
+ final int typefaceId = parcel.readInt();
+ if (pid != Process.myPid()) {
+ return null; // The Typeface was created and written in another process.
+ }
+ synchronized (sLock) {
+ return sStorage.get(typefaceId);
+ }
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index b951c4c..589f1c1 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -99,12 +99,12 @@
<string name="keyguard_sim_unlock_progress_dialog_message">Unlocking SIM card\u2026</string>
<!-- Time format strings for fall-back clock widget -->
- <string name="keyguard_widget_12_hours_format" translatable="false">h\uee01mm</string>
+ <string name="keyguard_widget_12_hours_format" translatable="false">h:mm</string>
<!-- Time format strings for fall-back clock widget -->
- <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string>
+ <string name="keyguard_widget_24_hours_format" translatable="false">kk:mm</string>
<!-- The character used in keyguard_widget_12_hours_format and keyguard_widget_24_hours_format
to represent a ":". -->
- <string name="keyguard_fancy_colon" translatable="false">\uee01</string>
+ <string name="keyguard_fancy_colon" translatable="false"></string>
<!-- Accessibility description of the PIN password view. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_pin_area">PIN area</string>
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index 91dc617..38627b6 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -51,8 +51,7 @@
android:clickable="true"
android:contentDescription="@string/accessibility_desc_close"
android:scaleType="center"
- android:src="@drawable/ic_close"
- android:tint="@android:color/white" />
+ android:src="@drawable/ic_close_white" />
<TextView
android:id="@+id/zen_introduction_message"
@@ -128,4 +127,4 @@
android:textColor="?android:attr/colorAccent"
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-</com.android.systemui.volume.ZenFooter>
\ No newline at end of file
+</com.android.systemui.volume.ZenFooter>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 200eabf..4261641 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -59,8 +59,7 @@
android:clickable="true"
android:contentDescription="@string/accessibility_desc_close"
android:scaleType="center"
- android:src="@drawable/ic_close"
- android:tint="@android:color/white" />
+ android:src="@drawable/ic_close_white" />
<TextView
android:id="@+id/zen_introduction_message"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0ab44ed..054d520 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -146,4 +146,6 @@
<color name="instant_apps_color">#ff4d5a64</color>
+ <color name="zen_introduction">#ffffffff</color>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 07f11a4..aee0ef8 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -220,6 +220,7 @@
<style name="TextAppearance.QS.Introduction">
<item name="android:textSize">14sp</item>
+ <item name="android:textColor">@color/zen_introduction</item>
</style>
<style name="TextAppearance.QS.Warning">
@@ -236,7 +237,7 @@
</style>
<style name="TextAppearance.QS.DetailButton.White">
- <item name="android:textColor">@color/qs_detail_button_white</item>
+ <item name="android:textColor">@color/zen_introduction</item>
</style>
<style name="TextAppearance.QS.DetailEmpty">
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java
index 80509a6..6a83c71 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockAccessibilityDelegate.java
@@ -36,6 +36,9 @@
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
+ if (TextUtils.isEmpty(mFancyColon)) {
+ return;
+ }
CharSequence text = event.getContentDescription();
if (!TextUtils.isEmpty(text)) {
event.setContentDescription(replaceFancyColon(text));
@@ -44,15 +47,22 @@
@Override
public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
- CharSequence text = ((TextView) host).getText();
- if (!TextUtils.isEmpty(text)) {
- event.getText().add(replaceFancyColon(text));
+ if (TextUtils.isEmpty(mFancyColon)) {
+ super.onPopulateAccessibilityEvent(host, event);
+ } else {
+ CharSequence text = ((TextView) host).getText();
+ if (!TextUtils.isEmpty(text)) {
+ event.getText().add(replaceFancyColon(text));
+ }
}
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
+ if (TextUtils.isEmpty(mFancyColon)) {
+ return;
+ }
if (!TextUtils.isEmpty(info.getText())) {
info.setText(replaceFancyColon(info.getText()));
}
@@ -62,6 +72,13 @@
}
private CharSequence replaceFancyColon(CharSequence text) {
+ if (TextUtils.isEmpty(mFancyColon)) {
+ return text;
+ }
return text.toString().replace(mFancyColon, ":");
}
+
+ public static boolean isNeeded(Context context) {
+ return !TextUtils.isEmpty(context.getString(R.string.keyguard_fancy_colon));
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a9d583f..bc2a59d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -153,7 +153,9 @@
mDateView = findViewById(R.id.date_view);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
- mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
+ if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
+ mClockView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
+ }
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
diff --git a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 810dd8c..01b4254 100644
--- a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -24,59 +24,50 @@
import android.view.View;
import android.widget.FrameLayout;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
import java.util.ArrayList;
import java.util.List;
/**
* Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
- * Currently supports changes to density and locale.
+ * Currently supports changes to density, asset path, and locale.
*/
-public class AutoReinflateContainer extends FrameLayout {
+public class AutoReinflateContainer extends FrameLayout implements
+ ConfigurationController.ConfigurationListener {
private final List<InflateListener> mInflateListeners = new ArrayList<>();
private final int mLayout;
- private int mDensity;
- private LocaleList mLocaleList;
public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
- mDensity = context.getResources().getConfiguration().densityDpi;
- mLocaleList = context.getResources().getConfiguration().getLocales();
-
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoReinflateContainer);
if (!a.hasValue(R.styleable.AutoReinflateContainer_android_layout)) {
throw new IllegalArgumentException("AutoReinflateContainer must contain a layout");
}
mLayout = a.getResourceId(R.styleable.AutoReinflateContainer_android_layout, 0);
+ a.recycle();
inflateLayout();
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- boolean shouldInflateLayout = false;
- final int density = newConfig.densityDpi;
- if (density != mDensity) {
- mDensity = density;
- shouldInflateLayout = true;
- }
- final LocaleList localeList = newConfig.getLocales();
- if (localeList != mLocaleList) {
- mLocaleList = localeList;
- shouldInflateLayout = true;
- }
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ Dependency.get(ConfigurationController.class).addCallback(this);
+ }
- if (shouldInflateLayout) {
- inflateLayout();
- }
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ Dependency.get(ConfigurationController.class).removeCallback(this);
}
protected void inflateLayoutImpl() {
LayoutInflater.from(getContext()).inflate(mLayout, this);
}
- protected void inflateLayout() {
+ public void inflateLayout() {
removeAllViews();
inflateLayoutImpl();
final int N = mInflateListeners.size();
@@ -90,6 +81,21 @@
listener.onInflated(getChildAt(0));
}
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ inflateLayout();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ inflateLayout();
+ }
+
+ @Override
+ public void onLocaleListChanged() {
+ inflateLayout();
+ }
+
public interface InflateListener {
/**
* Called whenever a new view is inflated.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java b/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java
new file mode 100644
index 0000000..dcb3882
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeReceiver.java
@@ -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 com.android.systemui.doze;
+
+/**
+ * Interface for class that cares about doze states.
+ */
+public interface DozeReceiver {
+ void setDozing(boolean dozing);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 0d5527c..bf1c060 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -184,6 +184,13 @@
pw.print("ProxSensor: "); pw.println(mProxSensor.toString());
}
+ /**
+ * @return true if prox is currently far, false if near or null if unknown.
+ */
+ public Boolean isProximityCurrentlyFar() {
+ return mProxSensor.mCurrentlyFar;
+ }
+
private class ProxSensor implements SensorEventListener {
static final long COOLDOWN_TRIGGER = 2 * 1000;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index d1f5337..ea06479 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -103,8 +103,11 @@
private void proximityCheckThenCall(IntConsumer callback,
boolean alreadyPerformedProxCheck,
int pulseReason) {
+ Boolean cachedProxFar = mDozeSensors.isProximityCurrentlyFar();
if (alreadyPerformedProxCheck) {
callback.accept(ProximityCheck.RESULT_NOT_CHECKED);
+ } else if (cachedProxFar != null) {
+ callback.accept(cachedProxFar ? ProximityCheck.RESULT_FAR : ProximityCheck.RESULT_NEAR);
} else {
final long start = SystemClock.uptimeMillis();
new ProximityCheck() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 25ef478..74737c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -280,13 +280,10 @@
if (mDozing) {
// If we're dozing, never show a persistent indication.
if (!TextUtils.isEmpty(mTransientIndication)) {
- // When dozing we ignore the initial text color and use white instead.
- // We don't wait to draw black text on a black background.
- int color = mTransientTextColor == mInitialTextColor ?
- Color.WHITE : mTransientTextColor;
+ // When dozing we ignore any text color and use white instead, because
+ // colors can be hard to read in low brightness.
+ mTextView.setTextColor(Color.WHITE);
mTextView.switchIndication(mTransientIndication);
- mTextView.setTextColor(color);
-
} else {
mTextView.switchIndication(null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
index a2bbb03..6f53844 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
@@ -18,6 +18,7 @@
import android.content.om.IOverlayManager;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.os.LocaleList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -38,6 +39,7 @@
private float mFontScale;
private boolean mInCarMode;
private int mUiMode;
+ private LocaleList mLocaleList;
public ConfigurationControllerImpl(Context context) {
Configuration currentConfig = context.getResources().getConfiguration();
@@ -46,6 +48,7 @@
mInCarMode = (currentConfig.uiMode & Configuration.UI_MODE_TYPE_MASK)
== Configuration.UI_MODE_TYPE_CAR;
mUiMode = currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+ mLocaleList = currentConfig.getLocales();
}
@Override
@@ -73,6 +76,16 @@
mUiMode = uiMode;
}
+ final LocaleList localeList = newConfig.getLocales();
+ if (!localeList.equals(mLocaleList)) {
+ mLocaleList = localeList;
+ listeners.forEach(l -> {
+ if (mListeners.contains(l)) {
+ l.onLocaleListChanged();
+ }
+ });
+ }
+
if ((mLastConfig.updateFrom(newConfig) & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
listeners.forEach(l -> {
if (mListeners.contains(l)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index df059e3..b4fe900 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -29,6 +29,7 @@
import com.android.keyguard.LatencyTracker;
import com.android.systemui.Dependency;
import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.keyguard.WakefulnessLifecycle;
/**
* Controller which coordinates all the fingerprint unlocking actions with the UI.
@@ -99,6 +100,7 @@
private final UnlockMethodCache mUnlockMethodCache;
private final Context mContext;
private int mPendingAuthenticatedUserId = -1;
+ private boolean mPendingShowBouncer;
public FingerprintUnlockController(Context context,
DozeScrimController dozeScrimController,
@@ -110,6 +112,7 @@
mPowerManager = context.getSystemService(PowerManager.class);
mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
mUpdateMonitor.registerCallback(this);
+ Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
mDozeScrimController = dozeScrimController;
mKeyguardViewMediator = keyguardViewMediator;
@@ -212,9 +215,10 @@
Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
if (!wasDeviceInteractive) {
mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+ mPendingShowBouncer = true;
+ } else {
+ showBouncer();
}
- mStatusBarKeyguardViewManager.animateCollapsePanels(
- FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
Trace.endSection();
break;
case MODE_WAKE_AND_UNLOCK_PULSING:
@@ -247,6 +251,12 @@
Trace.endSection();
}
+ private void showBouncer() {
+ mStatusBarKeyguardViewManager.animateCollapsePanels(
+ FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
+ mPendingShowBouncer = false;
+ }
+
@Override
public void onStartedGoingToSleep(int why) {
mPendingAuthenticatedUserId = -1;
@@ -338,4 +348,14 @@
}
mStatusBar.notifyFpAuthModeChanged();
}
+
+ private final WakefulnessLifecycle.Observer mWakefulnessObserver =
+ new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onFinishedWakingUp() {
+ if (mPendingShowBouncer) {
+ FingerprintUnlockController.this.showBouncer();
+ }
+ }
+ };
}
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 6b67dc4..5033c40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -156,6 +156,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.ActivityStarterDelegate;
+import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.DejankUtils;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
@@ -175,6 +176,7 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.fragments.ExtensionFragmentListener;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -1330,6 +1332,9 @@
if (mStatusBarKeyguardViewManager != null) {
mStatusBarKeyguardViewManager.onOverlayChanged();
}
+ if (mAmbientIndicationContainer instanceof AutoReinflateContainer) {
+ ((AutoReinflateContainer) mAmbientIndicationContainer).inflateLayout();
+ }
}
protected void reevaluateStyles() {
@@ -5161,6 +5166,7 @@
mStackScroller.setAnimationsEnabled(true);
mVisualStabilityManager.setScreenOn(true);
mNotificationPanel.setTouchDisabled(false);
+ mDozeServiceHost.stopDozing();
updateVisibleToUser();
updateIsKeyguard();
}
@@ -5339,6 +5345,9 @@
}
mStatusBarWindowManager.setDozing(mDozing);
mStatusBarKeyguardViewManager.setDozing(mDozing);
+ if (mAmbientIndicationContainer instanceof DozeReceiver) {
+ ((DozeReceiver) mAmbientIndicationContainer).setDozing(mDozing);
+ }
updateDozingState();
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 418c48e..3dca371 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -28,5 +28,6 @@
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
default void onOverlayChanged() {}
+ default void onLocaleListChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index 17d98b1..7464212 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -111,7 +111,9 @@
if (mZen == zen) return;
mZen = zen;
update();
- updateIntroduction();
+ post(() -> {
+ updateIntroduction();
+ });
}
private void setConfig(ZenModeConfig config) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
index 855adb4..e37ea95 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockAccessibilityDelegateTest.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -36,12 +37,17 @@
public class KeyguardClockAccessibilityDelegateTest extends SysuiTestCase {
private TextView mView;
+ private String m12HoursFormat;
+ private String m24HoursFormat;
@Before
public void setUp() throws Exception {
+ m12HoursFormat = mContext.getString(R.string.keyguard_widget_12_hours_format);
+ m24HoursFormat = mContext.getString(R.string.keyguard_widget_24_hours_format);
+
mView = new TextView(mContext);
- mView.setText(R.string.keyguard_widget_12_hours_format);
- mView.setContentDescription(mContext.getString(R.string.keyguard_widget_12_hours_format));
+ mView.setText(m12HoursFormat);
+ mView.setContentDescription(m12HoursFormat);
mView.setAccessibilityDelegate(new KeyguardClockAccessibilityDelegate(mContext));
}
@@ -77,6 +83,21 @@
assertTrue(isAscii(info.getContentDescription()));
}
+ @Test
+ public void isNeeded_returnsTrueIfDateFormatsContainNonAscii() {
+ if (!isAscii(m12HoursFormat) || !isAscii(m24HoursFormat)) {
+ assertTrue(KeyguardClockAccessibilityDelegate.isNeeded(mContext));
+ }
+ }
+
+ @Test
+ public void isNeeded_returnsWhetherFancyColonExists() {
+ boolean hasFancyColon = !TextUtils.isEmpty(mContext.getString(
+ R.string.keyguard_fancy_colon));
+
+ assertEquals(hasFancyColon, KeyguardClockAccessibilityDelegate.isNeeded(mContext));
+ }
+
private boolean isAscii(CharSequence text) {
return text.chars().allMatch((i) -> i < 128);
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index aceedf1..6a81d32 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -19,6 +19,7 @@
import android.app.IActivityController;
import android.os.Binder;
import android.os.RemoteException;
+import com.android.internal.os.ZygoteConnectionConstants;
import com.android.server.am.ActivityManagerService;
import android.content.BroadcastReceiver;
@@ -57,6 +58,11 @@
// Set this to true to have the watchdog record kernel thread stacks when it fires
static final boolean RECORD_KERNEL_THREADS = true;
+ // Note 1: Do not lower this value below thirty seconds without tightening the invoke-with
+ // timeout in com.android.internal.os.ZygoteConnection, or wrapped applications
+ // can trigger the watchdog.
+ // Note 2: The debug value is already below the wait time in ZygoteConnection. Wrapped
+ // applications may not work with a debug build. CTS will fail.
static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
@@ -262,6 +268,10 @@
// Initialize monitor for Binder threads.
addMonitor(new BinderThreadMonitor());
+
+ // See the notes on DEFAULT_TIMEOUT.
+ assert DB ||
+ DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
}
public void init(Context context, ActivityManagerService activity) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ce8aa5e..9925ba0 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1875,9 +1875,11 @@
} else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task
+ " returning to non-application type=" + task.getTaskToReturnTo());
- // Once we reach a fullscreen task that should return to another task, then no
- // other activities behind that one should be visible.
- if (task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
+ // Once we reach a fullscreen stack task that has a running activity and should
+ // return to another stack task, then no other activities behind that one should
+ // be visible.
+ if (task.topRunningActivityLocked() != null &&
+ task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
behindFullscreenActivity = true;
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
index 914f034..8fdbcf6c 100644
--- a/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java
@@ -64,8 +64,8 @@
private class ServiceImpl extends IRadioService.Stub {
private void enforcePolicyAccess() {
if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission(
- Manifest.permission.ACCESS_FM_RADIO)) {
- throw new SecurityException("ACCESS_FM_RADIO permission not granted");
+ Manifest.permission.ACCESS_BROADCAST_RADIO)) {
+ throw new SecurityException("ACCESS_BROADCAST_RADIO permission not granted");
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 4df566f..25fab9e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -40,7 +40,7 @@
// Change this value to control whether tether offload is enabled or
// disabled by default in the absence of an explicit Settings value.
// See accompanying unittest to distinguish 0 from non-0 values.
- private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 0;
+ private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 1;
private static final String NO_INTERFACE_NAME = "";
private static final String NO_IPV4_ADDRESS = "";
private static final String NO_IPV4_GATEWAY = "";
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index bf64f64..bab7011 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -615,6 +615,10 @@
params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
+ && !mPm.isCallerVerifier(callingUid)) {
+ params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
+ }
}
// Only system components can circumvent runtime permissions when installing.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 98b6949..9e61d13 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1670,12 +1670,14 @@
& PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
final boolean killApp = (args.installFlags
& PackageManager.INSTALL_DONT_KILL_APP) == 0;
+ final boolean virtualPreload = ((args.installFlags
+ & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
final String[] grantedPermissions = args.installGrantPermissions;
// Handle the parent package
handlePackagePostInstall(parentRes, grantPermissions, killApp,
- grantedPermissions, didRestore, args.installerPackageName,
- args.observer);
+ virtualPreload, grantedPermissions, didRestore,
+ args.installerPackageName, args.observer);
// Handle the child packages
final int childCount = (parentRes.addedChildPackages != null)
@@ -1683,8 +1685,8 @@
for (int i = 0; i < childCount; i++) {
PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
handlePackagePostInstall(childRes, grantPermissions, killApp,
- grantedPermissions, false, args.installerPackageName,
- args.observer);
+ virtualPreload, grantedPermissions, false /*didRestore*/,
+ args.installerPackageName, args.observer);
}
// Log tracing if needed
@@ -1895,7 +1897,7 @@
}
private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
- boolean killApp, String[] grantedPermissions,
+ boolean killApp, boolean virtualPreload, String[] grantedPermissions,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
@@ -1969,7 +1971,8 @@
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.uid);
boolean isSystem = res.pkg.applicationInfo.isSystemApp();
- sendPackageAddedForNewUsers(packageName, isSystem, appId, firstUsers);
+ sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
+ virtualPreload /*startReceiver*/, appId, firstUsers);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle(1);
@@ -7209,34 +7212,31 @@
String ephemeralPkgName) {
for (int i = resolveInfos.size() - 1; i >= 0; i--) {
final ResolveInfo info = resolveInfos.get(i);
- final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
// TODO: When adding on-demand split support for non-instant apps, remove this check
// and always apply post filtering
// allow activities that are defined in the provided package
- if (isEphemeralApp) {
- if (info.activityInfo.splitName != null
- && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
- info.activityInfo.splitName)) {
- // requested activity is defined in a split that hasn't been installed yet.
- // add the installer to the resolve list
- if (DEBUG_EPHEMERAL) {
- Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
- }
- final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
- installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
- info.activityInfo.packageName, info.activityInfo.splitName,
- info.activityInfo.applicationInfo.versionCode, null /*failureIntent*/);
- // make sure this resolver is the default
- installerInfo.isDefault = true;
- installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
- // add a non-generic filter
- installerInfo.filter = new IntentFilter();
- // load resources from the correct package
- installerInfo.resolvePackageName = info.getComponentInfo().packageName;
- resolveInfos.set(i, installerInfo);
- continue;
+ if (info.activityInfo.splitName != null
+ && !ArrayUtils.contains(info.activityInfo.applicationInfo.splitNames,
+ info.activityInfo.splitName)) {
+ // requested activity is defined in a split that hasn't been installed yet.
+ // add the installer to the resolve list
+ if (DEBUG_INSTALL) {
+ Slog.v(TAG, "Adding installer to the ResolveInfo list");
}
+ final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
+ installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
+ info.activityInfo.packageName, info.activityInfo.splitName,
+ info.activityInfo.applicationInfo.versionCode, null /*failureIntent*/);
+ // make sure this resolver is the default
+ installerInfo.isDefault = true;
+ installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+ | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ // add a non-generic filter
+ installerInfo.filter = new IntentFilter();
+ // load resources from the correct package
+ installerInfo.resolvePackageName = info.getComponentInfo().packageName;
+ resolveInfos.set(i, installerInfo);
+ continue;
}
// caller is a full app, don't need to apply any other filtering
if (ephemeralPkgName == null) {
@@ -7246,6 +7246,7 @@
continue;
}
// allow activities that have been explicitly exposed to ephemeral apps
+ final boolean isEphemeralApp = info.activityInfo.applicationInfo.isInstantApp();
if (!isEphemeralApp
&& ((info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0)) {
continue;
@@ -14350,7 +14351,8 @@
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
- sendPackageAddedForNewUsers(packageName, isSystem, pkgSetting.appId, userId);
+ sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
+ false /*startReceiver*/, pkgSetting.appId, userId);
// Send a session commit broadcast
final PackageInstaller.SessionInfo info = new PackageInstaller.SessionInfo();
@@ -14359,7 +14361,8 @@
sendSessionCommitBroadcast(info, userId);
}
- public void sendPackageAddedForNewUsers(String packageName, boolean isSystem, int appId, int... userIds) {
+ public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
+ boolean includeStopped, int appId, int... userIds) {
if (ArrayUtils.isEmpty(userIds)) {
return;
}
@@ -14369,10 +14372,11 @@
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
packageName, extras, 0, null, null, userIds);
- if (isSystem) {
+ if (sendBootCompleted) {
mHandler.post(() -> {
for (int userId : userIds) {
- sendBootCompletedBroadcastToSystemApp(packageName, userId);
+ sendBootCompletedBroadcastToSystemApp(
+ packageName, includeStopped, userId);
}
}
);
@@ -14384,7 +14388,8 @@
* automatically without needing an explicit launch.
* Send it a LOCKED_BOOT_COMPLETED/BOOT_COMPLETED if it would ordinarily have gotten ones.
*/
- private void sendBootCompletedBroadcastToSystemApp(String packageName, int userId) {
+ private void sendBootCompletedBroadcastToSystemApp(String packageName, boolean includeStopped,
+ int userId) {
// If user is not running, the app didn't miss any broadcast
if (!mUserManagerInternal.isUserRunning(userId)) {
return;
@@ -14394,6 +14399,9 @@
// Deliver LOCKED_BOOT_COMPLETED first
Intent lockedBcIntent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
.setPackage(packageName);
+ if (includeStopped) {
+ lockedBcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ }
final String[] requiredPermissions = {Manifest.permission.RECEIVE_BOOT_COMPLETED};
am.broadcastIntent(null, lockedBcIntent, null, null, 0, null, null, requiredPermissions,
android.app.AppOpsManager.OP_NONE, null, false, false, userId);
@@ -14401,6 +14409,9 @@
// Deliver BOOT_COMPLETED only if user is unlocked
if (mUserManagerInternal.isUserUnlockingOrUnlocked(userId)) {
Intent bcIntent = new Intent(Intent.ACTION_BOOT_COMPLETED).setPackage(packageName);
+ if (includeStopped) {
+ bcIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+ }
am.broadcastIntent(null, bcIntent, null, null, 0, null, null, requiredPermissions,
android.app.AppOpsManager.OP_NONE, null, false, false, userId);
}
@@ -18724,6 +18735,12 @@
return packageName;
}
+ boolean isCallerVerifier(int callingUid) {
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ return mRequiredVerifierPackage != null &&
+ callingUid == getPackageUid(mRequiredVerifierPackage, 0, callingUserId);
+ }
+
private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
@@ -18997,8 +19014,8 @@
for (int i = 0; i < packageCount; i++) {
PackageInstalledInfo installedInfo = appearedChildPackages.valueAt(i);
packageSender.sendPackageAddedForNewUsers(installedInfo.name,
- true, UserHandle.getAppId(installedInfo.uid),
- installedInfo.newUsers);
+ true /*sendBootCompleted*/, false /*startReceiver*/,
+ UserHandle.getAppId(installedInfo.uid), installedInfo.newUsers);
}
}
@@ -25086,6 +25103,6 @@
void sendPackageBroadcast(final String action, final String pkg,
final Bundle extras, final int flags, final String targetPkg,
final IIntentReceiver finishedReceiver, final int[] userIds);
- void sendPackageAddedForNewUsers(String packageName, boolean isSystem,
- int appId, int... userIds);
+ void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
+ boolean includeStopped, int appId, int... userIds);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 6d6611f..faeb05b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1221,6 +1221,9 @@
case "--full":
sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
break;
+ case "--preload":
+ sessionParams.setInstallAsVirtualPreload();
+ break;
case "--user":
params.userId = UserHandle.parseUserArg(getNextArgRequired());
break;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7a41e8a..e89ab1d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3164,7 +3164,7 @@
@Override
public void selectRotationAnimationLw(int anim[]) {
// If the screen is off or non-interactive, force a jumpcut.
- final boolean forceJumpcut = !mScreenOnFully || !mAwake;
+ final boolean forceJumpcut = !mScreenOnFully || !okToAnimate();
if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
+ mTopFullscreenOpaqueWindowState + " rotationAnimation="
+ (mTopFullscreenOpaqueWindowState == null ?
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index a6b8d94..74c1b24 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -785,7 +785,8 @@
}
if ((calling != null || mPersistentVrModeEnabled)
- && !Objects.equals(calling, mCurrentVrModeComponent)) {
+ && !Objects.equals(calling, mCurrentVrModeComponent)
+ || mRunning2dInVr != running2dInVr) {
sendUpdatedCaller = true;
}
mCurrentVrModeComponent = calling;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 8f2f34e..beffcee 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -47,7 +47,7 @@
}
public void sendPackageAddedForNewUsers(String packageName,
- boolean isSystem, int appId, int... userIds) {
+ boolean sendBootComplete, boolean includeStopped, int appId, int... userIds) {
}
}