Merge "Fix getPackageInfo for the "android" package in the system server." into lmp-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index ae2f3ad..c7cf940 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -218,6 +218,9 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services.core_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services.core_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 861e789..d9ea671 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1807,9 +1807,9 @@
}
}
- public void installSystemApplicationInfo(ApplicationInfo info) {
+ public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
synchronized (this) {
- getSystemContext().installSystemApplicationInfo(info);
+ getSystemContext().installSystemApplicationInfo(info, classLoader);
// The code package for "android" in the system server needs
// to be the system context's package.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4cf8cb4..da343ac 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2301,8 +2301,8 @@
}
}
- void installSystemApplicationInfo(ApplicationInfo info) {
- mPackageInfo.installSystemApplicationInfo(info);
+ void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
+ mPackageInfo.installSystemApplicationInfo(info, classLoader);
}
final void scheduleFinalCleanup(String who, String what) {
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 4b65934..e8f6818 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -66,7 +66,7 @@
boolean setZenModeConfig(in ZenModeConfig config);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
- oneway void setZenModeCondition(in Uri conditionId);
+ oneway void setZenModeCondition(in Condition condition);
oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
Condition[] getAutomaticZenModeConditions();
}
\ No newline at end of file
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index aa1f021..fcfc1c49 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -199,9 +199,10 @@
/**
* Sets application info about the system package.
*/
- void installSystemApplicationInfo(ApplicationInfo info) {
+ void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {
assert info.packageName.equals("android");
mApplicationInfo = info;
+ mClassLoader = classLoader;
}
public String getPackageName() {
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index ee4d45e..5815fa6 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -59,5 +59,5 @@
void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList);
void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
- void removeNfcUnlockHandler(IBinder b);
+ void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index dde2cf1..6bd5a32 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -311,7 +311,7 @@
final NfcActivityManager mNfcActivityManager;
final Context mContext;
- final HashMap<NfcUnlockHandler, IBinder> mNfcUnlockHandlers;
+ final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
final Object mLock;
/**
@@ -542,7 +542,7 @@
NfcAdapter(Context context) {
mContext = context;
mNfcActivityManager = new NfcActivityManager(this);
- mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, IBinder>();
+ mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
mLock = new Object();
}
@@ -1498,27 +1498,37 @@
* <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
* at the lockscreen. Polling for less tag technologies reduces latency, and so it is
* strongly recommended to only provide the Tag technologies that the handler is expected to
- * receive.
+ * receive. There must be at least one tag technology provided, otherwise the unlock handler
+ * is ignored.
*
* @hide
*/
@SystemApi
public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
String[] tagTechnologies) {
- try {
- INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
- @Override
- public boolean onUnlockAttempted(Tag tag) throws RemoteException {
- return unlockHandler.onUnlockAttempted(tag);
- }
- };
+ // If there are no tag technologies, don't bother adding unlock handler
+ if (tagTechnologies.length == 0) {
+ return false;
+ }
+ try {
synchronized (mLock) {
if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- return true;
+ // update the tag technologies
+ sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
+ mNfcUnlockHandlers.remove(unlockHandler);
}
- sService.addNfcUnlockHandler(iHandler, Tag.getTechCodesFromStrings(tagTechnologies));
- mNfcUnlockHandlers.put(unlockHandler, iHandler.asBinder());
+
+ INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
+ @Override
+ public boolean onUnlockAttempted(Tag tag) throws RemoteException {
+ return unlockHandler.onUnlockAttempted(tag);
+ }
+ };
+
+ sService.addNfcUnlockHandler(iHandler,
+ Tag.getTechCodesFromStrings(tagTechnologies));
+ mNfcUnlockHandlers.put(unlockHandler, iHandler);
}
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
@@ -1542,8 +1552,7 @@
try {
synchronized (mLock) {
if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
- mNfcUnlockHandlers.remove(unlockHandler);
+ sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
}
return true;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index cc09653..872f911 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -73,9 +73,14 @@
private static final String CONDITION_TAG = "condition";
private static final String CONDITION_ATT_COMPONENT = "component";
private static final String CONDITION_ATT_ID = "id";
+ private static final String CONDITION_ATT_SUMMARY = "summary";
+ private static final String CONDITION_ATT_LINE1 = "line1";
+ private static final String CONDITION_ATT_LINE2 = "line2";
+ private static final String CONDITION_ATT_ICON = "icon";
+ private static final String CONDITION_ATT_STATE = "state";
+ private static final String CONDITION_ATT_FLAGS = "flags";
private static final String EXIT_CONDITION_TAG = "exitCondition";
- private static final String EXIT_CONDITION_ATT_ID = "id";
private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
public boolean allowCalls;
@@ -83,13 +88,13 @@
public int allowFrom = SOURCE_ANYONE;
public String sleepMode;
- public int sleepStartHour;
- public int sleepStartMinute;
+ public int sleepStartHour; // 0-23
+ public int sleepStartMinute; // 0-59
public int sleepEndHour;
public int sleepEndMinute;
public ComponentName[] conditionComponents;
public Uri[] conditionIds;
- public Uri exitConditionId;
+ public Condition exitCondition;
public ComponentName exitConditionComponent;
public ZenModeConfig() { }
@@ -115,7 +120,7 @@
source.readTypedArray(conditionIds, Uri.CREATOR);
}
allowFrom = source.readInt();
- exitConditionId = source.readParcelable(null);
+ exitCondition = source.readParcelable(null);
exitConditionComponent = source.readParcelable(null);
}
@@ -146,7 +151,7 @@
dest.writeInt(0);
}
dest.writeInt(allowFrom);
- dest.writeParcelable(exitConditionId, 0);
+ dest.writeParcelable(exitCondition, 0);
dest.writeParcelable(exitConditionComponent, 0);
}
@@ -163,7 +168,7 @@
.append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
.append(",conditionIds=")
.append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
- .append(",exitConditionId=").append(exitConditionId)
+ .append(",exitCondition=").append(exitCondition)
.append(",exitConditionComponent=").append(exitConditionComponent)
.append(']').toString();
}
@@ -196,7 +201,7 @@
&& other.sleepEndMinute == sleepEndMinute
&& Objects.deepEquals(other.conditionComponents, conditionComponents)
&& Objects.deepEquals(other.conditionIds, conditionIds)
- && Objects.equals(other.exitConditionId, exitConditionId)
+ && Objects.equals(other.exitCondition, exitCondition)
&& Objects.equals(other.exitConditionComponent, exitConditionComponent);
}
@@ -205,7 +210,7 @@
return Objects.hash(allowCalls, allowMessages, allowFrom, sleepMode,
sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
- exitConditionId, exitConditionComponent);
+ exitCondition, exitConditionComponent);
}
public boolean isValid() {
@@ -294,9 +299,11 @@
conditionIds.add(conditionId);
}
} else if (EXIT_CONDITION_TAG.equals(tag)) {
- rt.exitConditionId = safeUri(parser, EXIT_CONDITION_ATT_ID);
- rt.exitConditionComponent =
- safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ rt.exitCondition = readConditionXml(parser);
+ if (rt.exitCondition != null) {
+ rt.exitConditionComponent =
+ safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ }
}
}
}
@@ -333,16 +340,42 @@
out.endTag(null, CONDITION_TAG);
}
}
- if (exitConditionId != null && exitConditionComponent != null) {
+ if (exitCondition != null && exitConditionComponent != null) {
out.startTag(null, EXIT_CONDITION_TAG);
- out.attribute(null, EXIT_CONDITION_ATT_ID, exitConditionId.toString());
out.attribute(null, EXIT_CONDITION_ATT_COMPONENT,
exitConditionComponent.flattenToString());
+ writeConditionXml(exitCondition, out);
out.endTag(null, EXIT_CONDITION_TAG);
}
out.endTag(null, ZEN_TAG);
}
+ public static Condition readConditionXml(XmlPullParser parser) {
+ final Uri id = safeUri(parser, CONDITION_ATT_ID);
+ final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
+ final String line1 = parser.getAttributeValue(null, CONDITION_ATT_LINE1);
+ final String line2 = parser.getAttributeValue(null, CONDITION_ATT_LINE2);
+ final int icon = safeInt(parser, CONDITION_ATT_ICON, -1);
+ final int state = safeInt(parser, CONDITION_ATT_STATE, -1);
+ final int flags = safeInt(parser, CONDITION_ATT_FLAGS, -1);
+ try {
+ return new Condition(id, summary, line1, line2, icon, state, flags);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Unable to read condition xml", e);
+ return null;
+ }
+ }
+
+ public static void writeConditionXml(Condition c, XmlSerializer out) throws IOException {
+ out.attribute(null, CONDITION_ATT_ID, c.id.toString());
+ out.attribute(null, CONDITION_ATT_SUMMARY, c.summary);
+ out.attribute(null, CONDITION_ATT_LINE1, c.line1);
+ out.attribute(null, CONDITION_ATT_LINE2, c.line2);
+ out.attribute(null, CONDITION_ATT_ICON, Integer.toString(c.icon));
+ out.attribute(null, CONDITION_ATT_STATE, Integer.toString(c.state));
+ out.attribute(null, CONDITION_ATT_FLAGS, Integer.toString(c.flags));
+ }
+
public static boolean isValidHour(int val) {
return val >= 0 && val < 24;
}
@@ -403,21 +436,31 @@
}
};
- // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
+ public DowntimeInfo toDowntimeInfo() {
+ final DowntimeInfo downtime = new DowntimeInfo();
+ downtime.startHour = sleepStartHour;
+ downtime.startMinute = sleepStartMinute;
+ downtime.endHour = sleepEndHour;
+ downtime.endMinute = sleepEndMinute;
+ return downtime;
+ }
- private static final String COUNTDOWN_AUTHORITY = "android";
+ // For built-in conditions
+ private static final String SYSTEM_AUTHORITY = "android";
+
+ // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
private static final String COUNTDOWN_PATH = "countdown";
public static Uri toCountdownConditionId(long time) {
return new Uri.Builder().scheme(Condition.SCHEME)
- .authority(COUNTDOWN_AUTHORITY)
+ .authority(SYSTEM_AUTHORITY)
.appendPath(COUNTDOWN_PATH)
.appendPath(Long.toString(time))
.build();
}
public static long tryParseCountdownConditionId(Uri conditionId) {
- if (!Condition.isValidId(conditionId, COUNTDOWN_AUTHORITY)) return 0;
+ if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)) return 0;
if (conditionId.getPathSegments().size() != 2
|| !COUNTDOWN_PATH.equals(conditionId.getPathSegments().get(0))) return 0;
try {
@@ -431,4 +474,68 @@
public static boolean isValidCountdownConditionId(Uri conditionId) {
return tryParseCountdownConditionId(conditionId) != 0;
}
+
+ // Built-in downtime conditions, e.g. condition://android/downtime?start=10.00&end=7.00
+ private static final String DOWNTIME_PATH = "downtime";
+
+ public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
+ return new Uri.Builder().scheme(Condition.SCHEME)
+ .authority(SYSTEM_AUTHORITY)
+ .appendPath(DOWNTIME_PATH)
+ .appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
+ .appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
+ .build();
+ }
+
+ public static DowntimeInfo tryParseDowntimeConditionId(Uri conditionId) {
+ if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)
+ || conditionId.getPathSegments().size() != 1
+ || !DOWNTIME_PATH.equals(conditionId.getPathSegments().get(0))) {
+ return null;
+ }
+ final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
+ final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
+ if (start == null || end == null) return null;
+ final DowntimeInfo downtime = new DowntimeInfo();
+ downtime.startHour = start[0];
+ downtime.startMinute = start[1];
+ downtime.endHour = end[0];
+ downtime.endMinute = end[1];
+ return downtime;
+ }
+
+ private static int[] tryParseHourAndMinute(String value) {
+ if (TextUtils.isEmpty(value)) return null;
+ final int i = value.indexOf('.');
+ if (i < 1 || i >= value.length() - 1) return null;
+ final int hour = tryParseInt(value.substring(0, i), -1);
+ final int minute = tryParseInt(value.substring(i + 1), -1);
+ return isValidHour(hour) && isValidMinute(minute) ? new int[] { hour, minute } : null;
+ }
+
+ public static boolean isValidDowntimeConditionId(Uri conditionId) {
+ return tryParseDowntimeConditionId(conditionId) != null;
+ }
+
+ public static class DowntimeInfo {
+ public int startHour; // 0-23
+ public int startMinute; // 0-59
+ public int endHour;
+ public int endMinute;
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof DowntimeInfo)) return false;
+ final DowntimeInfo other = (DowntimeInfo) o;
+ return startHour == other.startHour
+ && startMinute == other.startMinute
+ && endHour == other.endHour
+ && endMinute == other.endMinute;
+ }
+ }
}
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 51f07ec..5fe9194 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -69,12 +69,6 @@
"[" + getClass().getSimpleName() + "]";
private static final boolean DEBUG = false;
- // Temporary workaround to allow current trust agent implementations to continue working.
- // This and the code guarded by this should be removed before shipping.
- // If true, calls setManagingTrust(true) after onCreate, if it wasn't already set.
- // TODO: Remove this once all agents are updated.
- private static final boolean SET_MANAGED_FOR_LEGACY_AGENTS = true;
-
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -130,11 +124,6 @@
@Override
public void onCreate() {
- // TODO: Remove this once all agents are updated.
- if (SET_MANAGED_FOR_LEGACY_AGENTS) {
- setManagingTrust(true);
- }
-
super.onCreate();
ComponentName component = new ComponentName(this, getClass());
try {
@@ -175,7 +164,7 @@
* set.
*
* @param options Option feature bundle.
- * @return true if the {@link #TrustAgentService()} supports this feature.
+ * @return true if the {@link TrustAgentService} supports this feature.
*/
public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
return false;
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
new file mode 100644
index 0000000..e3f229f
--- /dev/null
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.os;
+
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.util.Slog;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents a connection to {@code installd}. Allows multiple connect and
+ * disconnect cycles.
+ *
+ * @hide for internal use only
+ */
+public class InstallerConnection {
+ private static final String TAG = "InstallerConnection";
+ private static final boolean LOCAL_DEBUG = false;
+
+ private InputStream mIn;
+ private OutputStream mOut;
+ private LocalSocket mSocket;
+
+ private final byte buf[] = new byte[1024];
+
+ public InstallerConnection() {
+ }
+
+ public synchronized String transact(String cmd) {
+ if (!connect()) {
+ Slog.e(TAG, "connection failed");
+ return "-1";
+ }
+
+ if (!writeCommand(cmd)) {
+ /*
+ * If installd died and restarted in the background (unlikely but
+ * possible) we'll fail on the next write (this one). Try to
+ * reconnect and write the command one more time before giving up.
+ */
+ Slog.e(TAG, "write command failed? reconnect!");
+ if (!connect() || !writeCommand(cmd)) {
+ return "-1";
+ }
+ }
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "send: '" + cmd + "'");
+ }
+
+ final int replyLength = readReply();
+ if (replyLength > 0) {
+ String s = new String(buf, 0, replyLength);
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "recv: '" + s + "'");
+ }
+ return s;
+ } else {
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "fail");
+ }
+ return "-1";
+ }
+ }
+
+ public int execute(String cmd) {
+ String res = transact(cmd);
+ try {
+ return Integer.parseInt(res);
+ } catch (NumberFormatException ex) {
+ return -1;
+ }
+ }
+
+ public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("dexopt");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ private boolean connect() {
+ if (mSocket != null) {
+ return true;
+ }
+ Slog.i(TAG, "connecting...");
+ try {
+ mSocket = new LocalSocket();
+
+ LocalSocketAddress address = new LocalSocketAddress("installd",
+ LocalSocketAddress.Namespace.RESERVED);
+
+ mSocket.connect(address);
+
+ mIn = mSocket.getInputStream();
+ mOut = mSocket.getOutputStream();
+ } catch (IOException ex) {
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+
+ public void disconnect() {
+ Slog.i(TAG, "disconnecting...");
+ IoUtils.closeQuietly(mSocket);
+ IoUtils.closeQuietly(mIn);
+ IoUtils.closeQuietly(mOut);
+
+ mSocket = null;
+ mIn = null;
+ mOut = null;
+ }
+
+
+ private boolean readFully(byte[] buffer, int len) {
+ try {
+ Streams.readFully(mIn, buffer, 0, len);
+ } catch (IOException ioe) {
+ Slog.e(TAG, "read exception");
+ disconnect();
+ return false;
+ }
+
+ if (LOCAL_DEBUG) {
+ Slog.i(TAG, "read " + len + " bytes");
+ }
+
+ return true;
+ }
+
+ private int readReply() {
+ if (!readFully(buf, 2)) {
+ return -1;
+ }
+
+ final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
+ if ((len < 1) || (len > buf.length)) {
+ Slog.e(TAG, "invalid reply length (" + len + ")");
+ disconnect();
+ return -1;
+ }
+
+ if (!readFully(buf, len)) {
+ return -1;
+ }
+
+ return len;
+ }
+
+ private boolean writeCommand(String cmdString) {
+ final byte[] cmd = cmdString.getBytes();
+ final int len = cmd.length;
+ if ((len < 1) || (len > buf.length)) {
+ return false;
+ }
+
+ buf[0] = (byte) (len & 0xff);
+ buf[1] = (byte) ((len >> 8) & 0xff);
+ try {
+ mOut.write(buf, 0, 2);
+ mOut.write(cmd, 0, len);
+ } catch (IOException ex) {
+ Slog.e(TAG, "write error");
+ disconnect();
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 4a26b4b..d35fce4 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -192,13 +192,14 @@
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
+ * @param classLoader the classLoader to load {@className} with
*/
- private static void invokeStaticMain(String className, String[] argv)
+ private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
- cl = Class.forName(className);
+ cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
@@ -263,7 +264,7 @@
* @param targetSdkVersion target SDK version
* @param argv arg strings
*/
- public static final void zygoteInit(int targetSdkVersion, String[] argv)
+ public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
@@ -272,7 +273,7 @@
commonInit();
nativeZygoteInit();
- applicationInit(targetSdkVersion, argv);
+ applicationInit(targetSdkVersion, argv, classLoader);
}
/**
@@ -290,10 +291,10 @@
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
- applicationInit(targetSdkVersion, argv);
+ applicationInit(targetSdkVersion, argv, null);
}
- private static void applicationInit(int targetSdkVersion, String[] argv)
+ private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
@@ -317,7 +318,7 @@
}
// Remaining arguments are passed to the start class's static main
- invokeStaticMain(args.startClass, args.startArgs);
+ invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
/**
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 0c48368..43ebb3d 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -863,7 +863,7 @@
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
- parsedArgs.remainingArgs);
+ parsedArgs.remainingArgs, null /* classLoader */);
}
} else {
String className;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eea4201..051de6e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -34,8 +34,11 @@
import android.system.OsConstants;
import android.util.EventLog;
import android.util.Log;
+import android.util.Slog;
import android.webkit.WebViewFactory;
+import dalvik.system.DexFile;
+import dalvik.system.PathClassLoader;
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -493,21 +496,69 @@
Process.setArgV0(parsedArgs.niceName);
}
+ final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
+ if (systemServerClasspath != null) {
+ performSystemServerDexOpt(systemServerClasspath);
+ }
+
if (parsedArgs.invokeWith != null) {
+ String[] args = parsedArgs.remainingArgs;
+ // If we have a non-null system server class path, we'll have to duplicate the
+ // existing arguments and append the classpath to it. ART will handle the classpath
+ // correctly when we exec a new process.
+ if (systemServerClasspath != null) {
+ String[] amendedArgs = new String[args.length + 2];
+ amendedArgs[0] = "-cp";
+ amendedArgs[1] = systemServerClasspath;
+ System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
+ }
+
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
- null, parsedArgs.remainingArgs);
+ null, args);
} else {
+ ClassLoader cl = null;
+ if (systemServerClasspath != null) {
+ cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
/*
* Pass the remaining arguments to SystemServer.
*/
- RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
+ RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
/**
+ * Performs dex-opt on the elements of {@code classPath}, if needed. We
+ * choose the instruction set of the current runtime.
+ */
+ private static void performSystemServerDexOpt(String classPath) {
+ final String[] classPathElements = classPath.split(":");
+ final InstallerConnection installer = new InstallerConnection();
+ final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
+
+ try {
+ for (String classPathElement : classPathElements) {
+ final byte dexopt = DexFile.isDexOptNeededInternal(classPathElement, "*", instructionSet,
+ false /* defer */);
+ if (dexopt == DexFile.DEXOPT_NEEDED) {
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+ } else if (dexopt == DexFile.PATCHOAT_NEEDED) {
+ installer.patchoat(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+ }
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException("Error starting system_server", ioe);
+ } finally {
+ installer.disconnect();
+ }
+ }
+
+ /**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer(String abiList, String socketName)
diff --git a/services/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
similarity index 100%
rename from services/core/java/com/android/server/BootReceiver.java
rename to core/java/com/android/server/BootReceiver.java
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 480383b..2106d38 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -246,6 +246,7 @@
libminikin \
libstlport \
libprocessgroup \
+ libnativebridge \
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 90c66d7..79b8542 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -161,10 +161,8 @@
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
-extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
-extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
-extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
+extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env);
extern int register_android_backup_BackupDataInput(JNIEnv *env);
extern int register_android_backup_BackupDataOutput(JNIEnv *env);
@@ -804,7 +802,7 @@
"-Xmx", "-Xcompiler-option");
if (skip_compilation) {
addOption("-Xcompiler-option");
- addOption("--compiler-filter=interpret-only");
+ addOption("--compiler-filter=verify-none");
} else {
parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
"--compiler-filter=", "-Xcompiler-option");
@@ -1338,9 +1336,7 @@
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
- REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),
REG_JNI(register_android_backup_BackupDataInput),
REG_JNI(register_android_backup_BackupDataOutput),
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9c44093..633a207 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -38,6 +38,8 @@
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+#include "nativebridge/native_bridge.h"
+
#define LOG_TRACE(...)
//#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -251,17 +253,29 @@
const char* pathStr = env->GetStringUTFChars(path, NULL);
NativeCode* code = NULL;
-
+ bool needNativeBridge = false;
+
void* handle = dlopen(pathStr, RTLD_LAZY);
-
+ if (handle == NULL) {
+ if (NativeBridgeIsSupported(pathStr)) {
+ handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
+ needNativeBridge = true;
+ }
+ }
env->ReleaseStringUTFChars(path, pathStr);
-
+
if (handle != NULL) {
+ void* funcPtr = NULL;
const char* funcStr = env->GetStringUTFChars(funcName, NULL);
- code = new NativeCode(handle, (ANativeActivity_createFunc*)
- dlsym(handle, funcStr));
+ if (needNativeBridge) {
+ funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
+ } else {
+ funcPtr = dlsym(handle, funcStr);
+ }
+
+ code = new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr);
env->ReleaseStringUTFChars(funcName, funcStr);
-
+
if (code->createActivityFunc == NULL) {
ALOGW("ANativeActivity_onCreate not found");
delete code;
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 74992ed..8065a9c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5523,4 +5523,7 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging</string>
+
+ <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
+ <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10.00 PM">%1$s</xliff:g></string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a4bec17..2cd0948 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1903,6 +1903,7 @@
<java-symbol type="string" name="timepicker_transition_mid_radius_multiplier" />
<java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
<java-symbol type="string" name="battery_saver_description" />
+ <java-symbol type="string" name="downtime_condition_summary" />
<java-symbol type="string" name="item_is_selected" />
<java-symbol type="string" name="day_of_week_label_typeface" />
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1316cb8..f963a4e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2860,16 +2860,17 @@
struct ResTable::Package
{
Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
- : owner(_owner), header(_header), typeIdOffset(0) {
- if (_package != NULL && dtohs(_package->header.headerSize) == sizeof(_package)) {
+ : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
+ if (dtohs(package->header.headerSize) == sizeof(package)) {
// The package structure is the same size as the definition.
// This means it contains the typeIdOffset field.
- typeIdOffset = _package->typeIdOffset;
+ typeIdOffset = package->typeIdOffset;
}
}
const ResTable* const owner;
const Header* const header;
+ const ResTable_package* const package;
ResStringPool typeStrings;
ResStringPool keyStrings;
@@ -3368,10 +3369,6 @@
header->header = (const ResTable_header*) resHeader;
mHeaders.add(header);
-
- PackageGroup* pg = new PackageGroup(this, String16(), 0);
- pg->packages.add(new Package(this, header, NULL));
- mPackageGroups.add(pg);
return (mError=NO_ERROR);
}
@@ -5940,7 +5937,7 @@
*outSize += 2 * sizeof(uint16_t);
// overlay packages are assumed to contain only one package group
- const String16 overlayPackage(overlay.mPackageGroups[0]->name);
+ const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
const TypeList& typeList = pg->types[typeIndex];
@@ -6215,6 +6212,11 @@
if (mError != 0) {
printf("mError=0x%x (%s)\n", mError, strerror(mError));
}
+#if 0
+ char localeStr[RESTABLE_MAX_LOCALE_LEN];
+ mParams.getBcp47Locale(localeStr);
+ printf("mParams=%s,\n" localeStr);
+#endif
size_t pgCount = mPackageGroups.size();
printf("Package Groups (%d)\n", (int)pgCount);
for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
@@ -6223,6 +6225,13 @@
(int)pgIndex, pg->id, (int)pg->packages.size(),
String8(pg->name).string());
+ size_t pkgCount = pg->packages.size();
+ for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
+ const Package* pkg = pg->packages[pkgIndex];
+ printf(" Package %d id=%d name=%s\n", (int)pkgIndex,
+ pkg->package->id, String8(String16(pkg->package->name)).string());
+ }
+
for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
const TypeList& typeList = pg->types[typeIndex];
if (typeList.isEmpty()) {
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 68c228e..8016a82 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -195,21 +195,4 @@
ASSERT_EQ(uint32_t(400), val.data);
}
-TEST(ResTableTest, emptyTableHasSensibleDefaults) {
- const int32_t expectedCookie = 1;
-
- ResTable table;
- ASSERT_EQ(NO_ERROR, table.addEmpty(expectedCookie));
-
- ASSERT_EQ(uint32_t(1), table.getTableCount());
- ASSERT_EQ(uint32_t(1), table.getBasePackageCount());
- ASSERT_EQ(expectedCookie, table.getTableCookie(0));
-
- const DynamicRefTable* dynamicRefTable = table.getDynamicRefTableForCookie(expectedCookie);
- ASSERT_TRUE(dynamicRefTable != NULL);
-
- Res_value val;
- ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
-}
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 99487ff..ca290e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -662,7 +662,6 @@
}
public void reset() {
- super.reset();
setTintColor(0);
setShowingLegacyBackground(false);
setBelowSpeedBump(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8c5151b..947d70d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1735,6 +1735,9 @@
: null;
// Reapply the RemoteViews
+ if (entry.row != null) {
+ entry.row.resetHeight();
+ }
contentView.reapply(mContext, entry.expanded, mOnClickHandler);
if (bigContentView != null && entry.getBigContentView() != null) {
bigContentView.reapply(mContext, entry.getBigContentView(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 43b7707..9ac20a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -88,9 +88,14 @@
mExpansionDisabled = false;
mPublicLayout.reset();
mPrivateLayout.reset();
+ resetHeight();
+ logExpansionEvent(false, wasExpanded);
+ }
+
+ public void resetHeight() {
mMaxExpandHeight = 0;
mWasReset = true;
- logExpansionEvent(false, wasExpanded);
+ onHeightReset();
}
@Override
@@ -178,20 +183,26 @@
* @param expand whether the system wants this notification to be expanded.
*/
public void setSystemExpanded(boolean expand) {
- final boolean wasExpanded = isExpanded();
- mIsSystemExpanded = expand;
- notifyHeightChanged();
- logExpansionEvent(false, wasExpanded);
+ if (expand != mIsSystemExpanded) {
+ final boolean wasExpanded = isExpanded();
+ mIsSystemExpanded = expand;
+ notifyHeightChanged();
+ logExpansionEvent(false, wasExpanded);
+ }
}
/**
* @param expansionDisabled whether to prevent notification expansion
*/
public void setExpansionDisabled(boolean expansionDisabled) {
- final boolean wasExpanded = isExpanded();
- mExpansionDisabled = expansionDisabled;
- logExpansionEvent(false, wasExpanded);
- notifyHeightChanged();
+ if (expansionDisabled != mExpansionDisabled) {
+ final boolean wasExpanded = isExpanded();
+ mExpansionDisabled = expansionDisabled;
+ logExpansionEvent(false, wasExpanded);
+ if (wasExpanded != isExpanded()) {
+ notifyHeightChanged();
+ }
+ }
}
/**
@@ -368,9 +379,8 @@
mPrivateLayout.notifyContentUpdated();
}
- public boolean isShowingLayoutLayouted() {
- NotificationContentView showingLayout = getShowingLayout();
- return showingLayout.getWidth() != 0;
+ public boolean isMaxExpandHeightInitialized() {
+ return mMaxExpandHeight != 0;
}
private NotificationContentView getShowingLayout() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 5b0bf03..127ff6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -255,7 +255,7 @@
public void setBelowSpeedBump(boolean below) {
}
- public void reset() {
+ public void onHeightReset() {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onReset(this);
}
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 c8e943e..decaeb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -54,6 +54,11 @@
private float mInitialOffsetOnTouch;
private float mExpandedFraction = 0;
protected float mExpandedHeight = 0;
+ private boolean mPanelClosedOnDown;
+ private boolean mHasLayoutedSinceDown;
+ private float mUpdateFlingVelocity;
+ private boolean mUpdateFlingOnLayout;
+ private boolean mTouching;
private boolean mJustPeeked;
private boolean mClosing;
protected boolean mTracking;
@@ -76,7 +81,6 @@
PanelBar mBar;
- protected int mMaxPanelHeight = -1;
private String mViewName;
private float mInitialTouchY;
private float mInitialTouchX;
@@ -226,6 +230,10 @@
mInitialOffsetOnTouch = mExpandedHeight;
mTouchSlopExceeded = false;
mJustPeeked = false;
+ mPanelClosedOnDown = mExpandedHeight == 0.0f;
+ mHasLayoutedSinceDown = false;
+ mUpdateFlingOnLayout = false;
+ mTouching = true;
if (mVelocityTracker == null) {
initVelocityTracker();
}
@@ -316,6 +324,10 @@
boolean expand = flingExpands(vel, vectorVel);
onTrackingStopped(expand);
fling(vel, expand);
+ mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
+ if (mUpdateFlingOnLayout) {
+ mUpdateFlingVelocity = vel;
+ }
} else {
boolean expands = onEmptySpaceClick(mInitialTouchX);
onTrackingStopped(expands);
@@ -325,6 +337,7 @@
mVelocityTracker.recycle();
mVelocityTracker = null;
}
+ mTouching = false;
break;
}
return !waitForTouchSlop || mTracking;
@@ -383,6 +396,10 @@
mInitialTouchX = x;
mTouchSlopExceeded = false;
mJustPeeked = false;
+ mPanelClosedOnDown = mExpandedHeight == 0.0f;
+ mHasLayoutedSinceDown = false;
+ mUpdateFlingOnLayout = false;
+ mTouching = true;
initVelocityTracker();
trackMovement(event);
break;
@@ -415,6 +432,10 @@
}
}
break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ mTouching = false;
+ break;
}
return false;
}
@@ -444,7 +465,6 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
loadDimens();
- mMaxPanelHeight = -1;
}
/**
@@ -524,27 +544,6 @@
return mViewName;
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- if (DEBUG) logf("onMeasure(%d, %d) -> (%d, %d)",
- widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
-
- // Did one of our children change size?
- int newHeight = getMeasuredHeight();
- if (newHeight > mMaxPanelHeight) {
- // we only adapt the max height if it's bigger
- mMaxPanelHeight = newHeight;
- // If the user isn't actively poking us, let's rubberband to the content
- if (!mTracking && mHeightAnimator == null
- && mExpandedHeight > 0 && mExpandedHeight != mMaxPanelHeight
- && mMaxPanelHeight > 0 && mPeekAnimator == null) {
- mExpandedHeight = mMaxPanelHeight;
- }
- }
- }
-
public void setExpandedHeight(float height) {
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
setExpandedHeightInternal(height + getOverExpansionPixels());
@@ -552,10 +551,14 @@
@Override
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
- if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom,
- (int)mExpandedHeight, mMaxPanelHeight);
super.onLayout(changed, left, top, right, bottom);
requestPanelHeightUpdate();
+ mHasLayoutedSinceDown = true;
+ if (mUpdateFlingOnLayout) {
+ abortAnimations();
+ fling(mUpdateFlingVelocity, true);
+ mUpdateFlingOnLayout = false;
+ }
}
protected void requestPanelHeightUpdate() {
@@ -567,7 +570,8 @@
&& mExpandedHeight > 0
&& currentMaxPanelHeight != mExpandedHeight
&& !mPeekPending
- && mPeekAnimator == null) {
+ && mPeekAnimator == null
+ && !mTouching) {
setExpandedHeight(currentMaxPanelHeight);
}
}
@@ -615,10 +619,7 @@
*
* @return the default implementation simply returns the maximum height.
*/
- protected int getMaxPanelHeight() {
- mMaxPanelHeight = Math.max(mMaxPanelHeight, getHeight());
- return mMaxPanelHeight;
- }
+ protected abstract int getMaxPanelHeight();
public void setExpandedFraction(float frac) {
setExpandedHeight(getMaxPanelHeight() * frac);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 04ee294..e1fd779 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -121,6 +121,7 @@
MotionEvent cancellation = MotionEvent.obtain(ev);
cancellation.setAction(MotionEvent.ACTION_CANCEL);
mStackScrollLayout.onInterceptTouchEvent(cancellation);
+ mNotificationPanel.onInterceptTouchEvent(cancellation);
cancellation.recycle();
}
return intercept;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 6c4fb7a..7d102ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.policy;
-import android.net.Uri;
import android.service.notification.Condition;
public interface ZenModeController {
@@ -25,15 +24,15 @@
void setZen(int zen);
int getZen();
void requestConditions(boolean request);
- void setExitConditionId(Uri exitConditionId);
- Uri getExitConditionId();
+ void setExitCondition(Condition exitCondition);
+ Condition getExitCondition();
long getNextAlarm();
void setUserId(int userId);
boolean isZenAvailable();
public static class Callback {
public void onZenChanged(int zen) {}
- public void onExitConditionChanged(Uri exitConditionId) {}
+ public void onExitConditionChanged(Condition exitCondition) {}
public void onConditionsChanged(Condition[] conditions) {}
public void onNextAlarmChanged() {}
public void onZenAvailableChanged(boolean available) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index b33e502..b0c8f26 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -122,20 +122,20 @@
}
@Override
- public void setExitConditionId(Uri exitConditionId) {
+ public void setExitCondition(Condition exitCondition) {
try {
- mNoMan.setZenModeCondition(exitConditionId);
+ mNoMan.setZenModeCondition(exitCondition);
} catch (RemoteException e) {
// noop
}
}
@Override
- public Uri getExitConditionId() {
+ public Condition getExitCondition() {
try {
final ZenModeConfig config = mNoMan.getZenModeConfig();
if (config != null) {
- return config.exitConditionId;
+ return config.exitCondition;
}
} catch (RemoteException e) {
// noop
@@ -186,10 +186,10 @@
}
private void fireExitConditionChanged() {
- final Uri exitConditionId = getExitConditionId();
- if (DEBUG) Slog.d(TAG, "exitConditionId changed: " + exitConditionId);
+ final Condition exitCondition = getExitCondition();
+ if (DEBUG) Slog.d(TAG, "exitCondition changed: " + exitCondition);
for (Callback cb : mCallbacks) {
- cb.onExitConditionChanged(exitConditionId);
+ cb.onExitConditionChanged(exitCondition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 8e5077c..1469d73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1914,6 +1914,7 @@
@Override
public void onReset(ExpandableView view) {
mRequestViewResizeAnimationOnLayout = true;
+ mStackScrollAlgorithm.onReset(view);
}
private void updateScrollPositionOnExpandInBottom(ExpandableView view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index fc2be1a..fe855d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -758,39 +758,42 @@
// current height.
mFirstChildMaxHeight = mFirstChildWhileExpanding.getActualHeight();
} else {
-
- // We are expanding the shade, expand it to its full height.
- if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
- // This child was not layouted yet, wait for a layout pass
- mFirstChildWhileExpanding
- .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight,
- int oldBottom) {
- if (mFirstChildWhileExpanding != null) {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
- } else {
- mFirstChildMaxHeight = 0;
- }
- v.removeOnLayoutChangeListener(this);
- }
- });
- } else {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
- }
+ updateFirstChildMaxSizeToMaxHeight();
}
} else {
mFirstChildMaxHeight = 0;
}
}
+ private void updateFirstChildMaxSizeToMaxHeight() {
+ // We are expanding the shade, expand it to its full height.
+ if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
+
+ // This child was not layouted yet, wait for a layout pass
+ mFirstChildWhileExpanding
+ .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right,
+ int bottom, int oldLeft, int oldTop, int oldRight,
+ int oldBottom) {
+ if (mFirstChildWhileExpanding != null) {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(
+ mFirstChildWhileExpanding);
+ } else {
+ mFirstChildMaxHeight = 0;
+ }
+ v.removeOnLayoutChangeListener(this);
+ }
+ });
+ } else {
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+ }
+ }
+
private boolean isMaxSizeInitialized(ExpandableView child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- return row.isShowingLayoutLayouted();
+ return row.isMaxExpandHeightInitialized();
}
return child == null || child.getWidth() != 0;
}
@@ -825,6 +828,12 @@
updatePadding(dimmed);
}
+ public void onReset(ExpandableView view) {
+ if (view.equals(mFirstChildWhileExpanding)) {
+ updateFirstChildMaxSizeToMaxHeight();
+ }
+ }
+
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 0d837c7..c99e1fd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -97,14 +97,16 @@
private Callback mCallback;
private ZenModeController mController;
private boolean mRequestingConditions;
- private Uri mExitConditionId;
+ private Condition mExitCondition;
+ private String mExitConditionText;
private int mBucketIndex = -1;
private boolean mExpanded;
private boolean mHidden = false;
private int mSessionZen;
- private Uri mSessionExitConditionId;
- private String mExitConditionText;
+ private Condition mSessionExitCondition;
private long mNextAlarm;
+ private Condition[] mConditions;
+ private Condition mTimeCondition;
public ZenModePanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -161,7 +163,7 @@
super.onAttachedToWindow();
if (DEBUG) Log.d(mTag, "onAttachedToWindow");
mSessionZen = getSelectedZen(-1);
- mSessionExitConditionId = mExitConditionId;
+ mSessionExitCondition = copy(mExitCondition);
refreshExitConditionText();
refreshNextAlarm();
updateWidgets();
@@ -172,7 +174,7 @@
super.onDetachedFromWindow();
if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
mSessionZen = -1;
- mSessionExitConditionId = null;
+ mSessionExitCondition = null;
setExpanded(false);
}
@@ -199,17 +201,16 @@
mController.requestConditions(mRequestingConditions);
}
if (mRequestingConditions) {
- Condition timeCondition = parseExistingTimeCondition(mExitConditionId);
- if (timeCondition != null) {
+ mTimeCondition = parseExistingTimeCondition(mExitCondition);
+ if (mTimeCondition != null) {
mBucketIndex = -1;
} else {
mBucketIndex = DEFAULT_BUCKET_INDEX;
- timeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+ mTimeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
- handleUpdateConditions(new Condition[0]); // ensures forever exists
- bind(timeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
- checkForDefault();
+ mConditions = null; // reset conditions
+ handleUpdateConditions();
} else {
mZenConditions.removeAllViews();
}
@@ -217,31 +218,47 @@
public void init(ZenModeController controller) {
mController = controller;
- setExitConditionId(mController.getExitConditionId());
+ setExitCondition(mController.getExitCondition());
refreshExitConditionText();
mSessionZen = getSelectedZen(-1);
handleUpdateZen(mController.getZen());
- if (DEBUG) Log.d(mTag, "init mExitConditionId=" + mExitConditionId);
+ if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
mZenConditions.removeAllViews();
mController.addCallback(mZenCallback);
}
- private void setExitConditionId(Uri exitConditionId) {
- if (Objects.equals(mExitConditionId, exitConditionId)) return;
- mExitConditionId = exitConditionId;
+ private void setExitCondition(Condition exitCondition) {
+ if (sameConditionId(mExitCondition, exitCondition)) return;
+ mExitCondition = exitCondition;
refreshExitConditionText();
updateWidgets();
}
+ private Uri getExitConditionId() {
+ return getConditionId(mExitCondition);
+ }
+
+ private static Uri getConditionId(Condition condition) {
+ return condition != null ? condition.id : null;
+ }
+
+ private static boolean sameConditionId(Condition lhs, Condition rhs) {
+ return lhs == null ? rhs == null : rhs != null && lhs.id.equals(rhs.id);
+ }
+
+ private static Condition copy(Condition condition) {
+ return condition == null ? null : condition.copy();
+ }
+
private void refreshExitConditionText() {
final String forever = mContext.getString(R.string.zen_mode_forever);
- if (mExitConditionId == null) {
+ if (mExitCondition == null) {
mExitConditionText = forever;
- } else if (ZenModeConfig.isValidCountdownConditionId(mExitConditionId)) {
- final Condition condition = parseExistingTimeCondition(mExitConditionId);
+ } else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
+ final Condition condition = parseExistingTimeCondition(mExitCondition);
mExitConditionText = condition != null ? condition.summary : forever;
} else {
- mExitConditionText = "(until condition ends)"; // TODO persist current description
+ mExitConditionText = mExitCondition.summary;
}
}
@@ -296,7 +313,7 @@
mZenConditions.setVisibility(!zenOff && expanded ? VISIBLE : GONE);
mAlarmWarning.setVisibility(zenNone && expanded && hasNextAlarm ? VISIBLE : GONE);
if (showAlarmWarning) {
- final long exitTime = ZenModeConfig.tryParseCountdownConditionId(mExitConditionId);
+ final long exitTime = ZenModeConfig.tryParseCountdownConditionId(getExitConditionId());
final long now = System.currentTimeMillis();
final boolean alarmToday = time(mNextAlarm).yearDay == time(now).yearDay;
final String skeleton = (alarmToday ? "" : "E")
@@ -330,8 +347,9 @@
return t;
}
- private Condition parseExistingTimeCondition(Uri conditionId) {
- final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
+ private Condition parseExistingTimeCondition(Condition condition) {
+ if (condition == null) return null;
+ final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
if (time == 0) return null;
final long span = time - System.currentTimeMillis();
if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
@@ -365,15 +383,36 @@
}
private void handleUpdateConditions(Condition[] conditions) {
- final int newCount = conditions == null ? 0 : conditions.length;
- if (DEBUG) Log.d(mTag, "handleUpdateConditions newCount=" + newCount);
- for (int i = mZenConditions.getChildCount(); i >= newCount + FIRST_CONDITION_INDEX; i--) {
+ mConditions = conditions;
+ handleUpdateConditions();
+ }
+
+ private void handleUpdateConditions() {
+ final int conditionCount = mConditions == null ? 0 : mConditions.length;
+ if (DEBUG) Log.d(mTag, "handleUpdateConditions conditionCount=" + conditionCount);
+ for (int i = mZenConditions.getChildCount() - 1; i >= FIRST_CONDITION_INDEX; i--) {
mZenConditions.removeViewAt(i);
}
+ // forever
bind(null, mZenConditions.getChildAt(FOREVER_CONDITION_INDEX));
- for (int i = 0; i < newCount; i++) {
- bind(conditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
+ // countdown
+ bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ // provider conditions
+ boolean foundDowntime = false;
+ for (int i = 0; i < conditionCount; i++) {
+ bind(mConditions[i], mZenConditions.getChildAt(FIRST_CONDITION_INDEX + i));
+ foundDowntime |= isDowntime(mConditions[i]);
}
+ // ensure downtime exists, if active
+ if (isDowntime(mSessionExitCondition) && !foundDowntime) {
+ bind(mSessionExitCondition, null);
+ }
+ // ensure something is selected
+ checkForDefault();
+ }
+
+ private static boolean isDowntime(Condition c) {
+ return ZenModeConfig.isValidDowntimeConditionId(getConditionId(c));
}
private ConditionTag getConditionTagAt(int index) {
@@ -385,7 +424,7 @@
for (int i = 0; i < mZenConditions.getChildCount(); i++) {
if (getConditionTagAt(i).rb.isChecked()) {
if (DEBUG) Log.d(mTag, "Not selecting a default, checked="
- + getConditionTagAt(i).conditionId);
+ + getConditionTagAt(i).condition);
return;
}
}
@@ -394,20 +433,20 @@
if (favoriteIndex == -1) {
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
} else {
- final Condition c = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
+ mTimeCondition = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
mBucketIndex = favoriteIndex;
- bind(c, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
+ bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
}
}
- private void handleExitConditionChanged(Uri exitCondition) {
- setExitConditionId(exitCondition);
- if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitConditionId);
+ private void handleExitConditionChanged(Condition exitCondition) {
+ setExitCondition(exitCondition);
+ if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
final ConditionTag tag = getConditionTagAt(i);
- tag.rb.setChecked(Objects.equals(tag.conditionId, exitCondition));
+ tag.rb.setChecked(sameConditionId(tag.condition, mExitCondition));
}
}
@@ -427,23 +466,23 @@
if (tag.rb == null) {
tag.rb = (RadioButton) row.findViewById(android.R.id.checkbox);
}
- tag.conditionId = condition != null ? condition.id : null;
+ tag.condition = condition;
tag.rb.setEnabled(enabled);
- if (mSessionExitConditionId != null && mSessionExitConditionId.equals(tag.conditionId)) {
+ if (sameConditionId(mSessionExitCondition, tag.condition)) {
tag.rb.setChecked(true);
}
tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mExpanded && isChecked) {
- if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.conditionId);
+ if (DEBUG) Log.d(mTag, "onCheckedChanged " + tag.condition);
final int N = mZenConditions.getChildCount();
for (int i = 0; i < N; i++) {
ConditionTag childTag = getConditionTagAt(i);
if (childTag == tag) continue;
childTag.rb.setChecked(false);
}
- select(tag.conditionId);
+ select(tag.condition);
fireInteraction();
}
}
@@ -479,7 +518,7 @@
}
});
- final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId);
+ final long time = ZenModeConfig.tryParseCountdownConditionId(getConditionId(tag.condition));
if (time > 0) {
if (mBucketIndex > -1) {
button1.setEnabled(mBucketIndex > 0);
@@ -504,7 +543,8 @@
final int N = MINUTE_BUCKETS.length;
if (mBucketIndex == -1) {
// not on a known index, search for the next or prev bucket by time
- final long time = ZenModeConfig.tryParseCountdownConditionId(tag.conditionId);
+ final Uri conditionId = getConditionId(tag.condition);
+ final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
final long now = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
int j = up ? i : N - 1 - i;
@@ -525,24 +565,25 @@
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
- bind(newCondition, row);
+ mTimeCondition = newCondition;
+ bind(mTimeCondition, row);
tag.rb.setChecked(true);
- select(newCondition.id);
+ select(mTimeCondition);
fireInteraction();
}
- private void select(Uri conditionId) {
- if (DEBUG) Log.d(mTag, "select " + conditionId);
+ private void select(Condition condition) {
+ if (DEBUG) Log.d(mTag, "select " + condition);
if (mController != null) {
- mController.setExitConditionId(conditionId);
+ mController.setExitCondition(condition);
}
- setExitConditionId(conditionId);
- if (conditionId == null) {
+ setExitCondition(condition);
+ if (condition == null) {
mFavorites.setMinuteIndex(-1);
- } else if (ZenModeConfig.isValidCountdownConditionId(conditionId) && mBucketIndex != -1) {
+ } else if (ZenModeConfig.isValidCountdownConditionId(condition.id) && mBucketIndex != -1) {
mFavorites.setMinuteIndex(mBucketIndex);
}
- mSessionExitConditionId = conditionId;
+ mSessionExitCondition = copy(condition);
}
private void fireMoreSettings() {
@@ -574,8 +615,8 @@
}
@Override
- public void onExitConditionChanged(Uri exitConditionId) {
- mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitConditionId).sendToTarget();
+ public void onExitConditionChanged(Condition exitCondition) {
+ mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitCondition).sendToTarget();
}
@Override
@@ -598,9 +639,8 @@
public void handleMessage(Message msg) {
if (msg.what == UPDATE_CONDITIONS) {
handleUpdateConditions((Condition[]) msg.obj);
- checkForDefault();
} else if (msg.what == EXIT_CONDITION_CHANGED) {
- handleExitConditionChanged((Uri) msg.obj);
+ handleExitConditionChanged((Condition) msg.obj);
} else if (msg.what == UPDATE_ZEN) {
handleUpdateZen(msg.arg1);
} else if (msg.what == NEXT_ALARM_CHANGED) {
@@ -618,7 +658,7 @@
// used as the view tag on condition rows
private static class ConditionTag {
RadioButton rb;
- Uri conditionId;
+ Condition condition;
}
private final class Favorites implements OnSharedPreferenceChangeListener {
diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk
index ca38f2f..e9bab4a 100644
--- a/services/appwidget/Android.mk
+++ b/services/appwidget/Android.mk
@@ -7,4 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
similarity index 100%
rename from core/java/com/android/server/SystemService.java
rename to services/core/java/com/android/server/SystemService.java
diff --git a/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
similarity index 100%
rename from core/java/com/android/server/SystemServiceManager.java
rename to services/core/java/com/android/server/SystemServiceManager.java
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ad2704a..ecd8f11 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2031,7 +2031,7 @@
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
- mSystemThread.installSystemApplicationInfo(info);
+ mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index a06daf6..189131c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -51,8 +51,9 @@
= new ArrayMap<IBinder, IConditionListener>();
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
private final CountdownConditionProvider mCountdown = new CountdownConditionProvider();
+ private final DowntimeConditionProvider mDowntime = new DowntimeConditionProvider();
- private Uri mExitConditionId;
+ private Condition mExitCondition;
private ComponentName mExitConditionComponent;
public ConditionProviders(Context context, Handler handler,
@@ -97,6 +98,7 @@
}
}
mCountdown.dump(pw, filter);
+ mDowntime.dump(pw, filter);
}
@Override
@@ -110,6 +112,10 @@
mCountdown.attachBase(mContext);
registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
UserHandle.USER_OWNER);
+ mDowntime.attachBase(mContext);
+ registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
+ UserHandle.USER_OWNER);
+ mDowntime.setCallback(new DowntimeCallback());
}
@Override
@@ -125,7 +131,7 @@
if (info.component.equals(mExitConditionComponent)) {
// ensure record exists, we'll wire it up and subscribe below
final ConditionRecord manualRecord =
- getRecordLocked(mExitConditionId, mExitConditionComponent);
+ getRecordLocked(mExitCondition.id, mExitConditionComponent);
manualRecord.isManual = true;
}
final int N = mRecords.size();
@@ -149,11 +155,11 @@
if (!r.component.equals(removed.component)) continue;
if (r.isManual) {
// removing the current manual condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
}
if (r.isAutomatic) {
// removing an automatic condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "automaticServiceRemoved");
}
mRecords.remove(i);
}
@@ -249,7 +255,8 @@
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: manual condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "manualConditionExit");
unsubscribeLocked(r);
r.isManual = false;
}
@@ -263,33 +270,46 @@
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: automatic condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "automaticConditionExit");
} else if (c.state == Condition.STATE_TRUE) {
Slog.d(TAG, "Enter zen: automatic condition true: " + c);
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ "automaticConditionEnter");
}
}
}
}
}
- public void setZenModeCondition(Uri conditionId, String reason) {
- if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ public void setZenModeCondition(Condition condition, String reason) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition);
synchronized(mMutex) {
ComponentName conditionComponent = null;
- if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
- // constructed by the client, make sure the record exists...
- final ConditionRecord r = getRecordLocked(conditionId,
- CountdownConditionProvider.COMPONENT);
- if (r.info == null) {
- // ... and is associated with the in-process service
- r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ if (condition != null) {
+ if (ZenModeConfig.isValidCountdownConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ CountdownConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ }
+ }
+ if (ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ DowntimeConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mDowntime.asInterface());
+ }
}
}
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final ConditionRecord r = mRecords.get(i);
- final boolean idEqual = r.id.equals(conditionId);
+ final boolean idEqual = condition != null && r.id.equals(condition.id);
if (r.isManual && !idEqual) {
// was previous manual condition, unsubscribe
unsubscribeLocked(r);
@@ -303,10 +323,10 @@
conditionComponent = r.component;
}
}
- if (!Objects.equals(mExitConditionId, conditionId)) {
- mExitConditionId = conditionId;
+ if (!Objects.equals(mExitCondition, condition)) {
+ mExitCondition = condition;
mExitConditionComponent = conditionComponent;
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, reason);
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, reason);
saveZenConfigLocked();
}
}
@@ -318,6 +338,7 @@
RemoteException re = null;
if (provider != null) {
try {
+ Slog.d(TAG, "Subscribing to " + r.id + " with " + provider);
provider.onSubscribe(r.id);
} catch (RemoteException e) {
Slog.w(TAG, "Error subscribing to " + r, e);
@@ -436,12 +457,13 @@
return;
}
synchronized (mMutex) {
- final boolean changingExit = !Objects.equals(mExitConditionId, config.exitConditionId);
- mExitConditionId = config.exitConditionId;
+ final boolean changingExit = !Objects.equals(mExitCondition, config.exitCondition);
+ mExitCondition = config.exitCondition;
mExitConditionComponent = config.exitConditionComponent;
if (changingExit) {
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, "config");
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
}
+ mDowntime.setConfig(config);
if (config.conditionComponents == null || config.conditionIds == null
|| config.conditionComponents.length != config.conditionIds.length) {
if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
@@ -488,7 +510,7 @@
config.conditionIds[i] = r.id;
}
}
- config.exitConditionId = mExitConditionId;
+ config.exitCondition = mExitCondition;
config.exitConditionComponent = mExitConditionComponent;
if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
mZenModeHelper.setConfig(config);
@@ -510,6 +532,26 @@
}
}
+ private class DowntimeCallback implements DowntimeConditionProvider.Callback {
+ @Override
+ public void onDowntimeChanged(boolean inDowntime) {
+ final int mode = mZenModeHelper.getZenMode();
+ final ZenModeConfig config = mZenModeHelper.getConfig();
+ // enter downtime
+ if (inDowntime && mode == Global.ZEN_MODE_OFF && config != null) {
+ final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
+ Condition.STATE_TRUE);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtimeEnter");
+ setZenModeCondition(condition, "downtime");
+ }
+ // exit downtime
+ if (!inDowntime && mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && mDowntime.isDowntimeCondition(mExitCondition)) {
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit");
+ }
+ }
+ }
+
private static class ConditionRecord {
public final Uri id;
public final ComponentName component;
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index aaf7cfc..37aacaa 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -29,6 +29,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
+import android.util.Log;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -38,8 +39,8 @@
/** Built-in zen condition provider for simple time-based conditions */
public class CountdownConditionProvider extends ConditionProviderService {
- private static final String TAG = "CountdownConditionProvider";
- private static final boolean DEBUG = false;
+ private static final String TAG = "CountdownConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
new ComponentName("android", CountdownConditionProvider.class.getName());
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
new file mode 100644
index 0000000..317ebef
--- /dev/null
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -0,0 +1,289 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.DowntimeInfo;
+import android.text.format.DateFormat;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Objects;
+
+/** Built-in zen condition provider for managing downtime */
+public class DowntimeConditionProvider extends ConditionProviderService {
+ private static final String TAG = "DowntimeConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final ComponentName COMPONENT =
+ new ComponentName("android", DowntimeConditionProvider.class.getName());
+
+ private static final String ENTER_ACTION = TAG + ".enter";
+ private static final int ENTER_CODE = 100;
+ private static final String EXIT_ACTION = TAG + ".exit";
+ private static final int EXIT_CODE = 101;
+ private static final String EXTRA_TIME = "time";
+
+ private final Calendar mCalendar = Calendar.getInstance();
+ private final Context mContext = this;
+ private final ArraySet<Integer> mDays = new ArraySet<Integer>();
+
+ private boolean mConnected;
+ private boolean mInDowntime;
+ private ZenModeConfig mConfig;
+ private Callback mCallback;
+
+ public DowntimeConditionProvider() {
+ if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
+ }
+
+ public void dump(PrintWriter pw, DumpFilter filter) {
+ pw.println(" DowntimeConditionProvider:");
+ pw.print(" mConnected="); pw.println(mConnected);
+ pw.print(" mInDowntime="); pw.println(mInDowntime);
+ }
+
+ public void attachBase(Context base) {
+ attachBaseContext(base);
+ }
+
+ public IConditionProvider asInterface() {
+ return (IConditionProvider) onBind(null);
+ }
+
+ public void setCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onConnected() {
+ if (DEBUG) Slog.d(TAG, "onConnected");
+ mConnected = true;
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ENTER_ACTION);
+ filter.addAction(EXIT_ACTION);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.d(TAG, "onDestroy");
+ mConnected = false;
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+ if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
+ if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
+ if (mInDowntime && mConfig != null) {
+ notifyCondition(createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE));
+ }
+ }
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
+ final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
+ if (downtime != null && mConfig != null) {
+ final int state = mConfig.toDowntimeInfo().equals(downtime) && mInDowntime
+ ? Condition.STATE_TRUE : Condition.STATE_FALSE;
+ if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
+ notifyCondition(createCondition(downtime, state));
+ }
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId);
+ }
+
+ public void setConfig(ZenModeConfig config) {
+ if (Objects.equals(mConfig, config)) return;
+ if (DEBUG) Slog.d(TAG, "setConfig");
+ mConfig = config;
+ if (mConnected) {
+ init();
+ }
+ }
+
+ public boolean isInDowntime() {
+ return mInDowntime;
+ }
+
+ public Condition createCondition(DowntimeInfo downtime, int state) {
+ if (downtime == null) return null;
+ final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
+ final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
+ final Locale locale = Locale.getDefault();
+ final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
+ final long time = getTime(System.currentTimeMillis(), downtime.endHour, downtime.endMinute);
+ final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(time));
+ final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
+ return new Condition(id, summary, "", "", 0, state, Condition.FLAG_RELEVANT_NOW);
+ }
+
+ public boolean isDowntimeCondition(Condition condition) {
+ return condition != null && ZenModeConfig.isValidDowntimeConditionId(condition.id);
+ }
+
+ private void init() {
+ updateDays();
+ reevaluateDowntime();
+ updateAlarms();
+ }
+
+ private void updateDays() {
+ mDays.clear();
+ if (mConfig != null) {
+ final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
+ for (int i = 0; days != null && i < days.length; i++) {
+ mDays.add(days[i]);
+ }
+ }
+ }
+
+ private boolean isInDowntime(long time) {
+ if (mConfig == null || mDays.size() == 0) return false;
+ final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ if (start == end) return false;
+ if (end < start) {
+ end = addDays(end, 1);
+ }
+ return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
+ }
+
+ private boolean isInDowntime(int daysOffset, long time, long start, long end) {
+ final int day = ((getDayOfWeek(time) + daysOffset - 1) % Calendar.SATURDAY) + 1;
+ start = addDays(start, daysOffset);
+ end = addDays(end, daysOffset);
+ return mDays.contains(day) && time >= start && time < end;
+ }
+
+ private void reevaluateDowntime() {
+ final boolean inDowntime = isInDowntime(System.currentTimeMillis());
+ if (DEBUG) Slog.d(TAG, "inDowntime=" + inDowntime);
+ if (inDowntime == mInDowntime) return;
+ Slog.i(TAG, (inDowntime ? "Entering" : "Exiting" ) + " downtime");
+ mInDowntime = inDowntime;
+ ZenLog.traceDowntime(mInDowntime, getDayOfWeek(System.currentTimeMillis()), mDays);
+ fireDowntimeChanged();
+ }
+
+ private void fireDowntimeChanged() {
+ if (mCallback != null) {
+ mCallback.onDowntimeChanged(mInDowntime);
+ }
+ }
+
+ private void updateAlarms() {
+ if (mConfig == null) return;
+ updateAlarm(ENTER_ACTION, ENTER_CODE, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ }
+
+ private int getDayOfWeek(long time) {
+ mCalendar.setTimeInMillis(time);
+ return mCalendar.get(Calendar.DAY_OF_WEEK);
+ }
+
+ private long getTime(long millis, int hour, int min) {
+ mCalendar.setTimeInMillis(millis);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hour);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private long addDays(long time, int days) {
+ mCalendar.setTimeInMillis(time);
+ mCalendar.add(Calendar.DATE, days);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private void updateAlarm(String action, int requestCode, int hr, int min) {
+ final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ final long now = System.currentTimeMillis();
+ mCalendar.setTimeInMillis(now);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hr);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ long time = mCalendar.getTimeInMillis();
+ if (time <= now) {
+ time = addDays(time, 1);
+ }
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
+ new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ if (mConfig.sleepMode != null) {
+ if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
+ action, ts(time), time - now, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final long now = System.currentTimeMillis();
+ if (ENTER_ACTION.equals(action) || EXIT_ACTION.equals(action)) {
+ final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
+ if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
+ action, ts(schTime), ts(now), now - schTime));
+ } else {
+ if (DEBUG) Slog.d(TAG, action + " fired at " + now);
+ }
+ reevaluateDowntime();
+ updateAlarms();
+ }
+ };
+
+ public interface Callback {
+ void onDowntimeChanged(boolean inDowntime);
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 36be21f..f647037 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -41,6 +41,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -64,7 +65,7 @@
*/
abstract public class ManagedServices {
protected final String TAG = getClass().getSimpleName();
- protected static final boolean DEBUG = true;
+ protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String ENABLED_SERVICES_SEPARATOR = ":";
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d6afe68..f2ac963 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1351,11 +1351,11 @@
}
@Override
- public void setZenModeCondition(Uri conditionId) {
+ public void setZenModeCondition(Condition condition) {
enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
final long identity = Binder.clearCallingIdentity();
try {
- mConditionProviders.setZenModeCondition(conditionId, "binderCall");
+ mConditionProviders.setZenModeCondition(condition, "binderCall");
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index b22ed2d..525f5f8 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -22,8 +22,10 @@
import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings.Global;
+import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
import android.util.Slog;
import java.io.PrintWriter;
@@ -52,13 +54,14 @@
private static final int TYPE_ALLOW_DISABLE = 2;
private static final int TYPE_SET_RINGER_MODE = 3;
private static final int TYPE_DOWNTIME = 4;
- private static final int TYPE_ZEN_MODE = 5;
- private static final int TYPE_EXIT_CONDITION = 6;
- private static final int TYPE_SUBSCRIBE = 7;
- private static final int TYPE_UNSUBSCRIBE = 8;
- private static final int TYPE_CONFIG = 9;
- private static final int TYPE_FOLLOW_RINGER_MODE = 10;
- private static final int TYPE_NOT_INTERCEPTED = 11;
+ private static final int TYPE_SET_ZEN_MODE = 5;
+ private static final int TYPE_UPDATE_ZEN_MODE = 6;
+ private static final int TYPE_EXIT_CONDITION = 7;
+ private static final int TYPE_SUBSCRIBE = 8;
+ private static final int TYPE_UNSUBSCRIBE = 9;
+ private static final int TYPE_CONFIG = 10;
+ private static final int TYPE_FOLLOW_RINGER_MODE = 11;
+ private static final int TYPE_NOT_INTERCEPTED = 12;
private static int sNext;
private static int sSize;
@@ -82,17 +85,20 @@
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
}
- public static void traceDowntime(boolean enter, int day, int[] days) {
- append(TYPE_DOWNTIME, enter + ",day=" + day + ",days=" + (days != null ? Arrays.asList(days)
- : null));
+ public static void traceDowntime(boolean inDowntime, int day, ArraySet<Integer> days) {
+ append(TYPE_DOWNTIME, inDowntime + ",day=" + day + ",days=" + days);
+ }
+
+ public static void traceSetZenMode(int mode, String reason) {
+ append(TYPE_SET_ZEN_MODE, zenModeToString(mode) + "," + reason);
}
public static void traceUpdateZenMode(int fromMode, int toMode) {
- append(TYPE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
+ append(TYPE_UPDATE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
}
- public static void traceExitCondition(Uri id, ComponentName component, String reason) {
- append(TYPE_EXIT_CONDITION, id + "," + componentToString(component) + "," + reason);
+ public static void traceExitCondition(Condition c, ComponentName component, String reason) {
+ append(TYPE_EXIT_CONDITION, c + "," + componentToString(component) + "," + reason);
}
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
@@ -122,7 +128,8 @@
case TYPE_ALLOW_DISABLE: return "allow_disable";
case TYPE_SET_RINGER_MODE: return "set_ringer_mode";
case TYPE_DOWNTIME: return "downtime";
- case TYPE_ZEN_MODE: return "zen_mode";
+ case TYPE_SET_ZEN_MODE: return "set_zen_mode";
+ case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode";
case TYPE_EXIT_CONDITION: return "exit_condition";
case TYPE_SUBSCRIBE: return "subscribe";
case TYPE_UNSUBSCRIBE: return "unsubscribe";
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9282283..b7b5f98 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -20,10 +20,8 @@
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.AudioAttributes.USAGE_UNKNOWN;
-import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -44,6 +42,7 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
import android.telecomm.TelecommManager;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.R;
@@ -57,8 +56,6 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
import java.util.Objects;
/**
@@ -66,12 +63,7 @@
*/
public class ZenModeHelper {
private static final String TAG = "ZenModeHelper";
-
- private static final String ACTION_ENTER_ZEN = "enter_zen";
- private static final int REQUEST_CODE_ENTER = 100;
- private static final String ACTION_EXIT_ZEN = "exit_zen";
- private static final int REQUEST_CODE_EXIT = 101;
- private static final String EXTRA_TIME = "time";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final Handler mHandler;
@@ -96,10 +88,8 @@
mSettingsObserver.observe();
final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_ENTER_ZEN);
- filter.addAction(ACTION_EXIT_ZEN);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(new ZenBroadcastReceiver(), filter);
+ mContext.registerReceiver(mReceiver, filter);
}
public static ZenModeConfig readDefaultConfig(Resources resources) {
@@ -156,7 +146,7 @@
public void requestFromListener(int hints) {
final int newZen = zenFromListenerHint(hints, -1);
if (newZen != -1) {
- setZenMode(newZen);
+ setZenMode(newZen, "listener");
}
}
@@ -208,7 +198,8 @@
return mZenMode;
}
- public void setZenMode(int zenModeValue) {
+ public void setZenMode(int zenModeValue, String reason) {
+ ZenLog.traceSetZenMode(zenModeValue, reason);
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
}
@@ -216,9 +207,6 @@
final int mode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF);
if (mode != mZenMode) {
- Slog.d(TAG, String.format("updateZenMode: %s -> %s",
- Global.zenModeToString(mZenMode),
- Global.zenModeToString(mode)));
ZenLog.traceUpdateZenMode(mZenMode, mode);
}
mZenMode = mode;
@@ -255,12 +243,12 @@
if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
mPreviousRingerMode = ringerMode;
- Slog.d(TAG, "Silencing ringer");
+ if (DEBUG) Slog.d(TAG, "Silencing ringer");
forcedRingerMode = AudioManager.RINGER_MODE_SILENT;
}
} else {
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- Slog.d(TAG, "Unsilencing ringer");
+ if (DEBUG) Slog.d(TAG, "Unsilencing ringer");
forcedRingerMode = mPreviousRingerMode != -1 ? mPreviousRingerMode
: AudioManager.RINGER_MODE_NORMAL;
mPreviousRingerMode = -1;
@@ -318,7 +306,6 @@
dispatchOnConfigChanged();
final String val = Integer.toString(mConfig.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- updateAlarms();
updateZenMode();
return true;
}
@@ -339,7 +326,7 @@
}
if (newZen != -1) {
ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen);
- setZenMode(newZen);
+ setZenMode(newZen, "ringerMode");
}
}
}
@@ -377,7 +364,7 @@
final TelecommManager telecomm =
(TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
- Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+ if (DEBUG) Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
}
return pkg != null && mDefaultPhoneApp != null
&& pkg.equals(mDefaultPhoneApp.getPackageName());
@@ -409,40 +396,6 @@
}
}
- private void updateAlarms() {
- updateAlarm(ACTION_ENTER_ZEN, REQUEST_CODE_ENTER,
- mConfig.sleepStartHour, mConfig.sleepStartMinute);
- updateAlarm(ACTION_EXIT_ZEN, REQUEST_CODE_EXIT,
- mConfig.sleepEndHour, mConfig.sleepEndMinute);
- }
-
- private void updateAlarm(String action, int requestCode, int hr, int min) {
- final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- final long now = System.currentTimeMillis();
- final Calendar c = Calendar.getInstance();
- c.setTimeInMillis(now);
- c.set(Calendar.HOUR_OF_DAY, hr);
- c.set(Calendar.MINUTE, min);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
- if (c.getTimeInMillis() <= now) {
- c.add(Calendar.DATE, 1);
- }
- final long time = c.getTimeInMillis();
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
- new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
- alarms.cancel(pendingIntent);
- if (mConfig.sleepMode != null) {
- Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
- action, ts(time), time - now, ts(now)));
- alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
- }
- }
-
- private static String ts(long time) {
- return new Date(time) + " (" + time + ")";
- }
-
private final Runnable mRingerModeChanged = new Runnable() {
@Override
public void run() {
@@ -475,47 +428,12 @@
}
}
- private class ZenBroadcastReceiver extends BroadcastReceiver {
- private final Calendar mCalendar = Calendar.getInstance();
-
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_ENTER_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- } else if (ACTION_EXIT_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_OFF);
- } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
- mHandler.post(mRingerModeChanged);
- }
+ mHandler.post(mRingerModeChanged);
}
-
- private void setZenMode(Intent intent, int zenModeValue) {
- final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
- final long now = System.currentTimeMillis();
- Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
- intent.getAction(), ts(schTime), ts(now), now - schTime));
-
- final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
- boolean enter = false;
- final int day = getDayOfWeek(schTime);
- if (days != null) {
- for (int i = 0; i < days.length; i++) {
- if (days[i] == day) {
- enter = true;
- ZenModeHelper.this.setZenMode(zenModeValue);
- break;
- }
- }
- }
- ZenLog.traceDowntime(enter, day, days);
- updateAlarms();
- }
-
- private int getDayOfWeek(long time) {
- mCalendar.setTimeInMillis(time);
- return mCalendar.get(Calendar.DAY_OF_WEEK);
- }
- }
+ };
public static class Callback {
void onConfigChanged() {}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 3e40d3f..d1e03ec 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,35 +16,23 @@
package com.android.server.pm;
-import android.os.Build;
-import com.android.server.SystemService;
-
import android.content.Context;
import android.content.pm.PackageStats;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
+import android.os.Build;
import android.util.Slog;
import dalvik.system.VMRuntime;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
+import com.android.internal.os.InstallerConnection;
+import com.android.server.SystemService;
public final class Installer extends SystemService {
private static final String TAG = "Installer";
- private static final boolean LOCAL_DEBUG = false;
-
- InputStream mIn;
- OutputStream mOut;
- LocalSocket mSocket;
-
- byte buf[] = new byte[1024];
- int buflen = 0;
+ private final InstallerConnection mInstaller;
public Installer(Context context) {
super(context);
+ mInstaller = new InstallerConnection();
}
@Override
@@ -53,154 +41,6 @@
ping();
}
- private boolean connect() {
- if (mSocket != null) {
- return true;
- }
- Slog.i(TAG, "connecting...");
- try {
- mSocket = new LocalSocket();
-
- LocalSocketAddress address = new LocalSocketAddress("installd",
- LocalSocketAddress.Namespace.RESERVED);
-
- mSocket.connect(address);
-
- mIn = mSocket.getInputStream();
- mOut = mSocket.getOutputStream();
- } catch (IOException ex) {
- disconnect();
- return false;
- }
- return true;
- }
-
- private void disconnect() {
- Slog.i(TAG, "disconnecting...");
- try {
- if (mSocket != null)
- mSocket.close();
- } catch (IOException ex) {
- }
- try {
- if (mIn != null)
- mIn.close();
- } catch (IOException ex) {
- }
- try {
- if (mOut != null)
- mOut.close();
- } catch (IOException ex) {
- }
- mSocket = null;
- mIn = null;
- mOut = null;
- }
-
- private boolean readBytes(byte buffer[], int len) {
- int off = 0, count;
- if (len < 0)
- return false;
- while (off != len) {
- try {
- count = mIn.read(buffer, off, len - off);
- if (count <= 0) {
- Slog.e(TAG, "read error " + count);
- break;
- }
- off += count;
- } catch (IOException ex) {
- Slog.e(TAG, "read exception");
- break;
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "read " + len + " bytes");
- }
- if (off == len)
- return true;
- disconnect();
- return false;
- }
-
- private boolean readReply() {
- int len;
- buflen = 0;
- if (!readBytes(buf, 2))
- return false;
- len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
- if ((len < 1) || (len > 1024)) {
- Slog.e(TAG, "invalid reply length (" + len + ")");
- disconnect();
- return false;
- }
- if (!readBytes(buf, len))
- return false;
- buflen = len;
- return true;
- }
-
- private boolean writeCommand(String _cmd) {
- byte[] cmd = _cmd.getBytes();
- int len = cmd.length;
- if ((len < 1) || (len > 1024))
- return false;
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- try {
- mOut.write(buf, 0, 2);
- mOut.write(cmd, 0, len);
- } catch (IOException ex) {
- Slog.e(TAG, "write error");
- disconnect();
- return false;
- }
- return true;
- }
-
- private synchronized String transaction(String cmd) {
- if (!connect()) {
- Slog.e(TAG, "connection failed");
- return "-1";
- }
-
- if (!writeCommand(cmd)) {
- /*
- * If installd died and restarted in the background (unlikely but
- * possible) we'll fail on the next write (this one). Try to
- * reconnect and write the command one more time before giving up.
- */
- Slog.e(TAG, "write command failed? reconnect!");
- if (!connect() || !writeCommand(cmd)) {
- return "-1";
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "send: '" + cmd + "'");
- }
- if (readReply()) {
- String s = new String(buf, 0, buflen);
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "recv: '" + s + "'");
- }
- return s;
- } else {
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "fail");
- }
- return "-1";
- }
- }
-
- private int execute(String cmd) {
- String res = transaction(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
-
public int install(String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
@@ -211,7 +51,7 @@
builder.append(gid);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
@@ -231,7 +71,7 @@
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
@@ -240,16 +80,7 @@
return -1;
}
- StringBuilder builder = new StringBuilder("patchoat");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
@@ -258,16 +89,7 @@
return -1;
}
- StringBuilder builder = new StringBuilder("dexopt");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
@@ -287,7 +109,7 @@
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
@@ -298,7 +120,7 @@
builder.append(overlayApkPath);
builder.append(' ');
builder.append(uid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int movedex(String srcPath, String dstPath, String instructionSet) {
@@ -314,7 +136,7 @@
builder.append(dstPath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rmdex(String codePath, String instructionSet) {
@@ -328,7 +150,7 @@
builder.append(codePath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int remove(String name, int userId) {
@@ -337,7 +159,7 @@
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rename(String oldname, String newname) {
@@ -346,7 +168,7 @@
builder.append(oldname);
builder.append(' ');
builder.append(newname);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int fixUid(String name, int uid, int gid) {
@@ -357,7 +179,7 @@
builder.append(uid);
builder.append(' ');
builder.append(gid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCacheFiles(String name, int userId) {
@@ -366,7 +188,7 @@
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCodeCacheFiles(String name, int userId) {
@@ -375,7 +197,7 @@
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserData(String name, int uid, int userId, String seinfo) {
@@ -388,21 +210,21 @@
builder.append(userId);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserConfig(int userId) {
StringBuilder builder = new StringBuilder("mkuserconfig");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int removeUserDataDirs(int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int clearUserData(String name, int userId) {
@@ -411,11 +233,11 @@
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean ping() {
- if (execute("ping") < 0) {
+ if (mInstaller.execute("ping") < 0) {
return false;
} else {
return true;
@@ -423,14 +245,14 @@
}
public int pruneDexCache(String cacheSubDir) {
- return execute("prunedexcache " + cacheSubDir);
+ return mInstaller.execute("prunedexcache " + cacheSubDir);
}
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
builder.append(String.valueOf(freeStorageSize));
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
@@ -462,7 +284,7 @@
// just the primary.
builder.append(instructionSets[0]);
- String s = transaction(builder.toString());
+ String s = mInstaller.transact(builder.toString());
String res[] = s.split(" ");
if ((res == null) || (res.length != 5)) {
@@ -480,7 +302,7 @@
}
public int moveFiles() {
- return execute("movefiles");
+ return mInstaller.execute("movefiles");
}
/**
@@ -506,7 +328,7 @@
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean restoreconData(String pkgName, String seinfo, int uid) {
@@ -517,7 +339,7 @@
builder.append(seinfo != null ? seinfo : "!");
builder.append(' ');
builder.append(uid);
- return (execute(builder.toString()) == 0);
+ return (mInstaller.execute(builder.toString()) == 0);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89bd1d4..304441c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1394,16 +1394,27 @@
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
- String bootClassPath = System.getProperty("java.boot.class.path");
+ final String bootClassPath = System.getenv("BOOTCLASSPATH");
+ final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
+
if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- alreadyDexOpted.add(paths[i]);
+ String[] bootClassPathElements = splitString(bootClassPath, ':');
+ for (String element : bootClassPathElements) {
+ alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
+ if (systemServerClassPath != null) {
+ String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
+ for (String element : systemServerClassPathElements) {
+ alreadyDexOpted.add(element);
+ }
+ } else {
+ Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
+ }
+
boolean didDexOptLibraryOrTool = false;
final List<String> allInstructionSets = getAllInstructionSets();
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ce2ca9b..39b70a8 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,8 @@
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
+int register_android_server_Watchdog(JNIEnv* env);
};
using namespace android;
@@ -77,6 +79,8 @@
register_android_server_hdmi_HdmiMhlController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
+ register_android_server_fingerprint_FingerprintService(env);
+ register_android_server_Watchdog(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk
index a55d138..7020f17 100644
--- a/services/devicepolicy/Android.mk
+++ b/services/devicepolicy/Android.mk
@@ -7,6 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
-LOCAL_JAVA_LIBRARIES := conscrypt
+LOCAL_JAVA_LIBRARIES := conscrypt services.core
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/print/Android.mk b/services/print/Android.mk
index 33604b7..00eb2e4 100644
--- a/services/print/Android.mk
+++ b/services/print/Android.mk
@@ -7,4 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/restrictions/Android.mk b/services/restrictions/Android.mk
index fcf8626..57d1c46 100644
--- a/services/restrictions/Android.mk
+++ b/services/restrictions/Android.mk
@@ -7,4 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usage/Android.mk b/services/usage/Android.mk
index d4b7fa8..f1cbe98 100644
--- a/services/usage/Android.mk
+++ b/services/usage/Android.mk
@@ -7,4 +7,6 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
+LOCAL_JAVA_LIBRARIES := services.core
+
include $(BUILD_STATIC_JAVA_LIBRARY)