resolved conflicts for merge of 08579921 to klp-modular-dev
Change-Id: I08e9f9a2d2185ccf0c41a87c8527ea7e02ac3117
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 0344d26..f3432a0 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,7 +19,7 @@
package com.android.commands.am;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
import android.app.IActivityController;
import android.app.IActivityManager;
@@ -31,6 +31,7 @@
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -106,11 +107,11 @@
" am to-intent-uri [INTENT]\n" +
" am switch-user <USER_ID>\n" +
" am stop-user <USER_ID>\n" +
- " am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
+ " am stack create <TASK_ID>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
- " am stack resize <STACK_ID> <WEIGHT>\n" +
- " am stack boxes\n" +
- " am stack box <STACK_BOX_ID>\n" +
+ " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack list\n" +
+ " am stack info <STACK_ID>\n" +
"\n" +
"am start: start an Activity. Options are:\n" +
" -D: enable debugging\n" +
@@ -204,24 +205,16 @@
"am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
" code until a later explicit switch to it.\n" +
"\n" +
- "am stack create: create a new stack relative to an existing one.\n" +
- " <TASK_ID>: the task to populate the new stack with. Must exist.\n" +
- " <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" +
- " <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
- " 1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
- " 2: to left of <RELATIVE_STACK_BOX_ID>,\n" +
- " 3: to right of <RELATIVE_STACK_BOX_ID>," +
- " 4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" +
- " <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +
+ "am stack create: create a new stack containing <TASK_ID> which must exist\n" +
"\n" +
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
"\n" +
- "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
+ "am stack list: list all of the activity stacks and their sizes.\n" +
"\n" +
- "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" +
+ "am stack info: display the information about activity stack <STACK_ID>.\n" +
"\n" +
"<INTENT> specifications include these flags and arguments:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -1551,11 +1544,11 @@
} else if (op.equals("movetask")) {
runStackMoveTask();
} else if (op.equals("resize")) {
- runStackBoxResize();
- } else if (op.equals("boxes")) {
- runStackBoxes();
- } else if (op.equals("box")) {
- runStackBoxInfo();
+ runStackResize();
+ } else if (op.equals("list")) {
+ runStackList();
+ } else if (op.equals("info")) {
+ runStackInfo();
} else {
showError("Error: unknown command '" + op + "'");
return;
@@ -1565,15 +1558,9 @@
private void runStackCreate() throws Exception {
String taskIdStr = nextArgRequired();
int taskId = Integer.valueOf(taskIdStr);
- String relativeToStr = nextArgRequired();
- int relativeTo = Integer.valueOf(relativeToStr);
- String positionStr = nextArgRequired();
- int position = Integer.valueOf(positionStr);
- String weightStr = nextArgRequired();
- float weight = Float.valueOf(weightStr);
try {
- int stackId = mAm.createStack(taskId, relativeTo, position, weight);
+ int stackId = mAm.createStack(taskId);
System.out.println("createStack returned new stackId=" + stackId + "\n\n");
} catch (RemoteException e) {
}
@@ -1601,34 +1588,40 @@
}
}
- private void runStackBoxResize() throws Exception {
- String stackBoxIdStr = nextArgRequired();
- int stackBoxId = Integer.valueOf(stackBoxIdStr);
- String weightStr = nextArgRequired();
- float weight = Float.valueOf(weightStr);
+ private void runStackResize() throws Exception {
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ String leftStr = nextArgRequired();
+ int left = Integer.valueOf(leftStr);
+ String topStr = nextArgRequired();
+ int top = Integer.valueOf(topStr);
+ String rightStr = nextArgRequired();
+ int right = Integer.valueOf(rightStr);
+ String bottomStr = nextArgRequired();
+ int bottom = Integer.valueOf(bottomStr);
try {
- mAm.resizeStackBox(stackBoxId, weight);
+ mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
} catch (RemoteException e) {
}
}
- private void runStackBoxes() throws Exception {
+ private void runStackList() throws Exception {
try {
- List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
- for (StackBoxInfo info : stackBoxes) {
+ List<StackInfo> stacks = mAm.getAllStackInfos();
+ for (StackInfo info : stacks) {
System.out.println(info);
}
} catch (RemoteException e) {
}
}
- private void runStackBoxInfo() throws Exception {
+ private void runStackInfo() throws Exception {
try {
- String stackBoxIdStr = nextArgRequired();
- int stackBoxId = Integer.valueOf(stackBoxIdStr);
- StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId);
- System.out.println(stackBoxInfo);
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ StackInfo info = mAm.getStackInfo(stackId);
+ System.out.println(info);
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7ca3459..c877cd3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1289,106 +1289,15 @@
}
/**
- * Information you can retrieve about the WindowManager StackBox hierarchy.
- * @hide
- */
- public static class StackBoxInfo implements Parcelable {
- public int stackBoxId;
- public float weight;
- public boolean vertical;
- public Rect bounds;
- public StackBoxInfo[] children;
- public int stackId;
- public StackInfo stack;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(stackBoxId);
- dest.writeFloat(weight);
- dest.writeInt(vertical ? 1 : 0);
- bounds.writeToParcel(dest, flags);
- dest.writeInt(stackId);
- if (children != null) {
- children[0].writeToParcel(dest, flags);
- children[1].writeToParcel(dest, flags);
- } else {
- stack.writeToParcel(dest, flags);
- }
- }
-
- public void readFromParcel(Parcel source) {
- stackBoxId = source.readInt();
- weight = source.readFloat();
- vertical = source.readInt() == 1;
- bounds = Rect.CREATOR.createFromParcel(source);
- stackId = source.readInt();
- if (stackId == -1) {
- children = new StackBoxInfo[2];
- children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
- children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
- } else {
- stack = StackInfo.CREATOR.createFromParcel(source);
- }
- }
-
- public static final Creator<StackBoxInfo> CREATOR =
- new Creator<ActivityManager.StackBoxInfo>() {
-
- @Override
- public StackBoxInfo createFromParcel(Parcel source) {
- return new StackBoxInfo(source);
- }
-
- @Override
- public StackBoxInfo[] newArray(int size) {
- return new StackBoxInfo[size];
- }
- };
-
- public StackBoxInfo() {
- }
-
- public StackBoxInfo(Parcel source) {
- readFromParcel(source);
- }
-
- public String toString(String prefix) {
- StringBuilder sb = new StringBuilder(256);
- sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
- sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
- sb.append("\n");
- if (children != null) {
- sb.append(prefix); sb.append("First child=\n");
- sb.append(children[0].toString(prefix + " "));
- sb.append(prefix); sb.append("Second child=\n");
- sb.append(children[1].toString(prefix + " "));
- } else {
- sb.append(prefix); sb.append("Stack=\n");
- sb.append(stack.toString(prefix + " "));
- }
- return sb.toString();
- }
-
- @Override
- public String toString() {
- return toString("");
- }
- }
-
- /**
* Information you can retrieve about an ActivityStack in the system.
* @hide
*/
public static class StackInfo implements Parcelable {
public int stackId;
- public Rect bounds;
+ public Rect bounds = new Rect();
public int[] taskIds;
public String[] taskNames;
+ public int displayId;
@Override
public int describeContents() {
@@ -1404,6 +1313,7 @@
dest.writeInt(bounds.bottom);
dest.writeIntArray(taskIds);
dest.writeStringArray(taskNames);
+ dest.writeInt(displayId);
}
public void readFromParcel(Parcel source) {
@@ -1412,6 +1322,7 @@
source.readInt(), source.readInt(), source.readInt(), source.readInt());
taskIds = source.createIntArray();
taskNames = source.createStringArray();
+ displayId = source.readInt();
}
public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
@@ -1435,7 +1346,9 @@
public String toString(String prefix) {
StringBuilder sb = new StringBuilder(256);
sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
- sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
+ sb.append(" bounds="); sb.append(bounds.toShortString());
+ sb.append(" displayId="); sb.append(displayId);
+ sb.append("\n");
prefix = prefix + " ";
for (int i = 0; i < taskIds.length; ++i) {
sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 74266cc..f0c4c93 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,7 +16,7 @@
package android.app;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -31,6 +31,7 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -614,10 +615,7 @@
case CREATE_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
- int relativeStackId = data.readInt();
- int position = data.readInt();
- float weight = data.readFloat();
- int res = createStack(taskId, relativeStackId, position, weight);
+ int res = createStack(taskId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -635,25 +633,26 @@
case RESIZE_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- int stackBoxId = data.readInt();
+ int stackId = data.readInt();
float weight = data.readFloat();
- resizeStackBox(stackBoxId, weight);
+ Rect r = Rect.CREATOR.createFromParcel(data);
+ resizeStack(stackId, r);
reply.writeNoException();
return true;
}
- case GET_STACK_BOXES_TRANSACTION: {
+ case GET_ALL_STACK_INFOS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- List<StackBoxInfo> list = getStackBoxes();
+ List<StackInfo> list = getAllStackInfos();
reply.writeNoException();
reply.writeTypedList(list);
return true;
}
- case GET_STACK_BOX_INFO_TRANSACTION: {
+ case GET_STACK_INFO_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
- int stackBoxId = data.readInt();
- StackBoxInfo info = getStackBoxInfo(stackBoxId);
+ int stackId = data.readInt();
+ StackInfo info = getStackInfo(stackId);
reply.writeNoException();
if (info != null) {
reply.writeInt(1);
@@ -2715,16 +2714,12 @@
reply.recycle();
}
@Override
- public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
- throws RemoteException
+ public int createStack(int taskId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(relativeStackBoxId);
- data.writeInt(position);
- data.writeFloat(weight);
mRemote.transact(CREATE_STACK_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
@@ -2747,44 +2742,44 @@
reply.recycle();
}
@Override
- public void resizeStackBox(int stackBoxId, float weight) throws RemoteException
+ public void resizeStack(int stackBoxId, Rect r) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(stackBoxId);
- data.writeFloat(weight);
+ r.writeToParcel(data, 0);
mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
}
@Override
- public List<StackBoxInfo> getStackBoxes() throws RemoteException
+ public List<StackInfo> getAllStackInfos() throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0);
+ mRemote.transact(GET_ALL_STACK_INFOS_TRANSACTION, data, reply, 0);
reply.readException();
- ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR);
+ ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR);
data.recycle();
reply.recycle();
return list;
}
@Override
- public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException
+ public StackInfo getStackInfo(int stackId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeInt(stackBoxId);
- mRemote.transact(GET_STACK_BOX_INFO_TRANSACTION, data, reply, 0);
+ data.writeInt(stackId);
+ mRemote.transact(GET_STACK_INFO_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
- StackBoxInfo info = null;
+ StackInfo info = null;
if (res != 0) {
- info = StackBoxInfo.CREATOR.createFromParcel(reply);
+ info = StackInfo.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 77c2ea0..631d9b1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -18,7 +18,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.RunningServiceInfo;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
import android.content.ComponentName;
import android.content.ContentProviderNative;
import android.content.IContentProvider;
@@ -36,6 +36,7 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Debug;
@@ -117,12 +118,11 @@
public void moveTaskToBack(int task) throws RemoteException;
public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
public void moveTaskBackwards(int task) throws RemoteException;
- public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
- throws RemoteException;
+ public int createStack(int taskId) throws RemoteException;
public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
- public void resizeStackBox(int stackBoxId, float weight) throws RemoteException;
- public List<StackBoxInfo> getStackBoxes() throws RemoteException;
- public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException;
+ public void resizeStack(int stackId, Rect bounds) throws RemoteException;
+ public List<StackInfo> getAllStackInfos() throws RemoteException;
+ public StackInfo getStackInfo(int stackId) throws RemoteException;
public void setFocusedStack(int stackId) throws RemoteException;
public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
/* oneway */
@@ -681,9 +681,9 @@
int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
- int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
+ int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
- int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
+ int GET_STACK_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3efd3c0..181eb63 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -71,4 +71,14 @@
* Returns the desired minimum height for the wallpaper.
*/
int getHeightHint();
+
+ /**
+ * Returns the name of the wallpaper. Private API.
+ */
+ String getName();
+
+ /**
+ * Informs the service that wallpaper settings have been restored. Private API.
+ */
+ void settingsRestored();
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b22d5cf..a06a20b 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -79,9 +79,6 @@
private final String mName;
int mNativeObject; // package visibility only for Surface.java access
- private static final boolean HEADLESS = "1".equals(
- SystemProperties.get("ro.config.headless", "0"));
-
/* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
/**
@@ -232,8 +229,6 @@
new Throwable());
}
- checkHeadless();
-
mName = name;
mNativeObject = nativeCreate(session, name, w, h, format, flags);
if (mNativeObject == 0) {
@@ -619,10 +614,4 @@
}
nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
}
-
- private static void checkHeadless() {
- if (HEADLESS) {
- throw new UnsupportedOperationException("Device is headless");
- }
- }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b198937..e546117 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2522,7 +2522,7 @@
android:hasCode="false"
android:label="@string/android_system_label"
android:allowClearUserData="false"
- android:backupAgent="com.android.server.SystemBackupAgent"
+ android:backupAgent="com.android.server.backup.SystemBackupAgent"
android:killAfterRestore="false"
android:icon="@drawable/ic_launcher_android"
android:supportsRtl="true">
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index c33bd35..f33ab40 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -231,7 +231,6 @@
/** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
boolean mEnableShiftMenuBugReports = false;
- boolean mHeadless;
boolean mSafeMode;
WindowState mStatusBar = null;
int mStatusBarHeight;
@@ -855,7 +854,6 @@
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
- mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
mHandler = new PolicyHandler();
mOrientationListener = new MyOrientationListener(mContext, mHandler);
try {
@@ -3602,9 +3600,6 @@
/** {@inheritDoc} */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
- // do nothing if headless
- if (mHeadless) return;
-
// lid changed state
final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
if (newLidState == mLidState) {
@@ -3837,7 +3832,7 @@
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
- if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
+ if (isScreenOn || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
@@ -4663,10 +4658,9 @@
/** {@inheritDoc} */
@Override
public void systemReady() {
- if (!mHeadless) {
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
- mKeyguardDelegate.onSystemReady();
- }
+ mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+ mKeyguardDelegate.onSystemReady();
+
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -4693,7 +4687,6 @@
/** {@inheritDoc} */
public void showBootMessage(final CharSequence msg, final boolean always) {
- if (mHeadless) return;
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
diff --git a/services/java/Android.mk b/services/java/Android.mk
index 8c3d0f0..9651239 100644
--- a/services/java/Android.mk
+++ b/services/java/Android.mk
@@ -1,18 +1,18 @@
LOCAL_PATH:= $(call my-dir)
-# the library
+# Build services.jar
# ============================================================
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
- com/android/server/EventLogTags.logtags \
- com/android/server/am/EventLogTags.logtags
-
LOCAL_MODULE:= services
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files) \
+ com/android/server/EventLogTags.logtags \
+ com/android/server/am/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
include $(BUILD_JAVA_LIBRARY)
-
include $(BUILD_DROIDDOC)
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 2e1b0af..3cdf170 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -31,6 +31,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -64,54 +65,51 @@
import com.android.internal.util.LocalLog;
-class AlarmManagerService extends IAlarmManager.Stub {
+class AlarmManagerService extends SystemService {
// The threshold for how long an alarm can be late before we print a
// warning message. The time duration is in milliseconds.
private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
- private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
+ private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
- private static final int TIME_CHANGED_MASK = 1 << 16;
- private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+ static final int TIME_CHANGED_MASK = 1 << 16;
+ static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
// Mask for testing whether a given alarm type is wakeup vs non-wakeup
- private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
+ static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
- private static final String TAG = "AlarmManager";
- private static final String ClockReceiver_TAG = "ClockReceiver";
- private static final boolean localLOGV = false;
- private static final boolean DEBUG_BATCH = localLOGV || false;
- private static final boolean DEBUG_VALIDATE = localLOGV || false;
- private static final int ALARM_EVENT = 1;
- private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+ static final String TAG = "AlarmManager";
+ static final String ClockReceiver_TAG = "ClockReceiver";
+ static final boolean localLOGV = false;
+ static final boolean DEBUG_BATCH = localLOGV || false;
+ static final boolean DEBUG_VALIDATE = localLOGV || false;
+ static final int ALARM_EVENT = 1;
+ static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
- private static final Intent mBackgroundIntent
+ static final Intent mBackgroundIntent
= new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
- private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
+ static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
- private static final boolean WAKEUP_STATS = false;
+ static final boolean WAKEUP_STATS = false;
- private final Context mContext;
+ final LocalLog mLog = new LocalLog(TAG);
- private final LocalLog mLog = new LocalLog(TAG);
+ final Object mLock = new Object();
- private Object mLock = new Object();
-
- private long mNativeData;
+ long mNativeData;
private long mNextWakeup;
private long mNextNonWakeup;
- private int mBroadcastRefCount = 0;
- private PowerManager.WakeLock mWakeLock;
- private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
- private final AlarmThread mWaitThread = new AlarmThread();
- private final AlarmHandler mHandler = new AlarmHandler();
- private ClockReceiver mClockReceiver;
+ int mBroadcastRefCount = 0;
+ PowerManager.WakeLock mWakeLock;
+ ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
+ final AlarmHandler mHandler = new AlarmHandler();
+ ClockReceiver mClockReceiver;
private UninstallReceiver mUninstallReceiver;
- private final ResultReceiver mResultReceiver = new ResultReceiver();
- private final PendingIntent mTimeTickSender;
- private final PendingIntent mDateChangeSender;
+ final ResultReceiver mResultReceiver = new ResultReceiver();
+ PendingIntent mTimeTickSender;
+ PendingIntent mDateChangeSender;
class WakeupEvent {
public long when;
@@ -125,8 +123,8 @@
}
}
- private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
- private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
+ final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
+ final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
static final class Batch {
long start; // These endpoints are always in ELAPSED
@@ -317,9 +315,9 @@
}
// minimum recurrence period or alarm futurity for us to be able to fuzz it
- private static final long MIN_FUZZABLE_INTERVAL = 10000;
- private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
- private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+ static final long MIN_FUZZABLE_INTERVAL = 10000;
+ static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
+ final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
static long convertToElapsed(long when, int type) {
final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
@@ -403,7 +401,7 @@
}
}
- private static final class InFlight extends Intent {
+ static final class InFlight extends Intent {
final PendingIntent mPendingIntent;
final WorkSource mWorkSource;
final Pair<String, ComponentName> mTarget;
@@ -427,7 +425,7 @@
}
}
- private static final class FilterStats {
+ static final class FilterStats {
final BroadcastStats mBroadcastStats;
final Pair<String, ComponentName> mTarget;
@@ -443,7 +441,7 @@
}
}
- private static final class BroadcastStats {
+ static final class BroadcastStats {
final String mPackageName;
long aggregateTime;
@@ -459,47 +457,48 @@
}
}
- private final HashMap<String, BroadcastStats> mBroadcastStats
+ final HashMap<String, BroadcastStats> mBroadcastStats
= new HashMap<String, BroadcastStats>();
- public AlarmManagerService(Context context) {
- mContext = context;
+ @Override
+ public void onStart() {
mNativeData = init();
mNextWakeup = mNextNonWakeup = 0;
// We have to set current TimeZone info to kernel
// because kernel doesn't keep this after reboot
- String tz = SystemProperties.get(TIMEZONE_PROPERTY);
- if (tz != null) {
- setTimeZone(tz);
- }
+ setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
+ mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND), 0,
UserHandle.ALL);
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
+ mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
// now that we have initied the driver schedule the alarm
- mClockReceiver= new ClockReceiver();
+ mClockReceiver = new ClockReceiver();
mClockReceiver.scheduleTimeTickEvent();
mClockReceiver.scheduleDateChangedEvent();
mUninstallReceiver = new UninstallReceiver();
if (mNativeData != 0) {
- mWaitThread.start();
+ AlarmThread waitThread = new AlarmThread();
+ waitThread.start();
} else {
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
+
+ publishBinderService(Context.ALARM_SERVICE, mService);
}
-
+
+ @Override
protected void finalize() throws Throwable {
try {
close(mNativeData);
@@ -508,19 +507,51 @@
}
}
- @Override
- public void set(int type, long triggerAtTime, long windowLength, long interval,
- PendingIntent operation, WorkSource workSource) {
- if (workSource != null) {
- mContext.enforceCallingPermission(
- android.Manifest.permission.UPDATE_DEVICE_STATS,
- "AlarmManager.set");
+ void setTimeZoneImpl(String tz) {
+ if (TextUtils.isEmpty(tz)) {
+ return;
}
- set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
+ TimeZone zone = TimeZone.getTimeZone(tz);
+ // Prevent reentrant calls from stepping on each other when writing
+ // the time zone property
+ boolean timeZoneWasChanged = false;
+ synchronized (this) {
+ String current = SystemProperties.get(TIMEZONE_PROPERTY);
+ if (current == null || !current.equals(zone.getID())) {
+ if (localLOGV) {
+ Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
+ }
+ timeZoneWasChanged = true;
+ SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+ }
+
+ // Update the kernel timezone information
+ // Kernel tracks time offsets as 'minutes west of GMT'
+ int gmtOffset = zone.getOffset(System.currentTimeMillis());
+ setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+ }
+
+ TimeZone.setDefault(null);
+
+ if (timeZoneWasChanged) {
+ Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("time-zone", zone.getID());
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
}
- public void set(int type, long triggerAtTime, long windowLength, long interval,
+ void removeImpl(PendingIntent operation) {
+ if (operation == null) {
+ return;
+ }
+ synchronized (mLock) {
+ removeLocked(operation);
+ }
+ }
+
+ void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, boolean isStandalone, WorkSource workSource) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
@@ -606,231 +637,64 @@
rescheduleKernelAlarmsLocked();
}
- private void logBatchesLocked() {
- ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
- PrintWriter pw = new PrintWriter(bs);
- final long nowRTC = System.currentTimeMillis();
- final long nowELAPSED = SystemClock.elapsedRealtime();
- final int NZ = mAlarmBatches.size();
- for (int iz = 0; iz < NZ; iz++) {
- Batch bz = mAlarmBatches.get(iz);
- pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
- dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC);
- pw.flush();
- Slog.v(TAG, bs.toString());
- bs.reset();
- }
- }
-
- private boolean validateConsistencyLocked() {
- if (DEBUG_VALIDATE) {
- long lastTime = Long.MIN_VALUE;
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.start >= lastTime) {
- // duplicate start times are okay because of standalone batches
- lastTime = b.start;
- } else {
- Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
- logBatchesLocked();
- return false;
- }
- }
- }
- return true;
- }
-
- private Batch findFirstWakeupBatchLocked() {
- final int N = mAlarmBatches.size();
- for (int i = 0; i < N; i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasWakeups()) {
- return b;
- }
- }
- return null;
- }
-
- private void rescheduleKernelAlarmsLocked() {
- // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
- // prior to that which contains no wakeups, we schedule that as well.
- if (mAlarmBatches.size() > 0) {
- final Batch firstWakeup = findFirstWakeupBatchLocked();
- final Batch firstBatch = mAlarmBatches.get(0);
- if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
- mNextWakeup = firstWakeup.start;
- setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
- }
- if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
- mNextNonWakeup = firstBatch.start;
- setLocked(ELAPSED_REALTIME, firstBatch.start);
- }
- }
- }
-
- public void setTime(long millis) {
- mContext.enforceCallingOrSelfPermission(
- "android.permission.SET_TIME",
- "setTime");
-
- SystemClock.setCurrentTimeMillis(millis);
- }
-
- public void setTimeZone(String tz) {
- mContext.enforceCallingOrSelfPermission(
- "android.permission.SET_TIME_ZONE",
- "setTimeZone");
-
- long oldId = Binder.clearCallingIdentity();
- try {
- if (TextUtils.isEmpty(tz)) return;
- TimeZone zone = TimeZone.getTimeZone(tz);
- // Prevent reentrant calls from stepping on each other when writing
- // the time zone property
- boolean timeZoneWasChanged = false;
- synchronized (this) {
- String current = SystemProperties.get(TIMEZONE_PROPERTY);
- if (current == null || !current.equals(zone.getID())) {
- if (localLOGV) {
- Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
- }
- timeZoneWasChanged = true;
- SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
- }
-
- // Update the kernel timezone information
- // Kernel tracks time offsets as 'minutes west of GMT'
- int gmtOffset = zone.getOffset(System.currentTimeMillis());
- setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+ private final IBinder mService = new IAlarmManager.Stub() {
+ @Override
+ public void set(int type, long triggerAtTime, long windowLength, long interval,
+ PendingIntent operation, WorkSource workSource) {
+ if (workSource != null) {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.UPDATE_DEVICE_STATS,
+ "AlarmManager.set");
}
- TimeZone.setDefault(null);
+ setImpl(type, triggerAtTime, windowLength, interval, operation,
+ false, workSource);
+ }
- if (timeZoneWasChanged) {
- Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra("time-zone", zone.getID());
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- }
- } finally {
- Binder.restoreCallingIdentity(oldId);
+ @Override
+ public void setTime(long millis) {
+ getContext().enforceCallingOrSelfPermission(
+ "android.permission.SET_TIME",
+ "setTime");
+
+ SystemClock.setCurrentTimeMillis(millis);
}
- }
-
- public void remove(PendingIntent operation) {
- if (operation == null) {
- return;
- }
- synchronized (mLock) {
- removeLocked(operation);
- }
- }
-
- public void removeLocked(PendingIntent operation) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(operation);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
+
+ @Override
+ public void setTimeZone(String tz) {
+ getContext().enforceCallingOrSelfPermission(
+ "android.permission.SET_TIME_ZONE",
+ "setTimeZone");
+
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ setTimeZoneImpl(tz);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
}
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(operation) changed bounds; rebatching");
- }
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
- }
- }
+ @Override
+ public void remove(PendingIntent operation) {
+ removeImpl(operation);
- public void removeLocked(String packageName) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(packageName);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
}
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(package) changed bounds; rebatching");
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump AlarmManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
}
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
- }
- }
- public void removeUserLocked(int userHandle) {
- boolean didRemove = false;
- for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
- Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(userHandle);
- if (b.size() == 0) {
- mAlarmBatches.remove(i);
- }
+ dumpImpl(pw);
}
+ };
- if (didRemove) {
- if (DEBUG_BATCH) {
- Slog.v(TAG, "remove(user) changed bounds; rebatching");
- }
- rebatchAllAlarmsLocked(true);
- rescheduleKernelAlarmsLocked();
- }
- }
-
- public boolean lookForPackageLocked(String packageName) {
- for (int i = 0; i < mAlarmBatches.size(); i++) {
- Batch b = mAlarmBatches.get(i);
- if (b.hasPackage(packageName)) {
- return true;
- }
- }
- return false;
- }
-
- private void setLocked(int type, long when)
- {
- if (mNativeData != 0)
- {
- // The kernel never triggers alarms with negative wakeup times
- // so we ensure they are positive.
- long alarmSeconds, alarmNanoseconds;
- if (when < 0) {
- alarmSeconds = 0;
- alarmNanoseconds = 0;
- } else {
- alarmSeconds = when / 1000;
- alarmNanoseconds = (when % 1000) * 1000 * 1000;
- }
-
- set(mNativeData, type, alarmSeconds, alarmNanoseconds);
- }
- else
- {
- Message msg = Message.obtain();
- msg.what = ALARM_EVENT;
-
- mHandler.removeMessages(ALARM_EVENT);
- mHandler.sendMessageAtTime(msg, when);
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump AlarmManager from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
+ void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
final long nowRTC = System.currentTimeMillis();
@@ -980,6 +844,159 @@
}
}
+ private void logBatchesLocked() {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+ PrintWriter pw = new PrintWriter(bs);
+ final long nowRTC = System.currentTimeMillis();
+ final long nowELAPSED = SystemClock.elapsedRealtime();
+ final int NZ = mAlarmBatches.size();
+ for (int iz = 0; iz < NZ; iz++) {
+ Batch bz = mAlarmBatches.get(iz);
+ pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
+ dumpAlarmList(pw, bz.alarms, " ", nowELAPSED, nowRTC);
+ pw.flush();
+ Slog.v(TAG, bs.toString());
+ bs.reset();
+ }
+ }
+
+ private boolean validateConsistencyLocked() {
+ if (DEBUG_VALIDATE) {
+ long lastTime = Long.MIN_VALUE;
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.start >= lastTime) {
+ // duplicate start times are okay because of standalone batches
+ lastTime = b.start;
+ } else {
+ Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
+ logBatchesLocked();
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private Batch findFirstWakeupBatchLocked() {
+ final int N = mAlarmBatches.size();
+ for (int i = 0; i < N; i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.hasWakeups()) {
+ return b;
+ }
+ }
+ return null;
+ }
+
+ void rescheduleKernelAlarmsLocked() {
+ // Schedule the next upcoming wakeup alarm. If there is a deliverable batch
+ // prior to that which contains no wakeups, we schedule that as well.
+ if (mAlarmBatches.size() > 0) {
+ final Batch firstWakeup = findFirstWakeupBatchLocked();
+ final Batch firstBatch = mAlarmBatches.get(0);
+ if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+ mNextWakeup = firstWakeup.start;
+ setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+ }
+ if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+ mNextNonWakeup = firstBatch.start;
+ setLocked(ELAPSED_REALTIME, firstBatch.start);
+ }
+ }
+ }
+
+ private void removeLocked(PendingIntent operation) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(operation);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(operation) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ void removeLocked(String packageName) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(packageName);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(package) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ void removeUserLocked(int userHandle) {
+ boolean didRemove = false;
+ for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+ Batch b = mAlarmBatches.get(i);
+ didRemove |= b.remove(userHandle);
+ if (b.size() == 0) {
+ mAlarmBatches.remove(i);
+ }
+ }
+
+ if (didRemove) {
+ if (DEBUG_BATCH) {
+ Slog.v(TAG, "remove(user) changed bounds; rebatching");
+ }
+ rebatchAllAlarmsLocked(true);
+ rescheduleKernelAlarmsLocked();
+ }
+ }
+
+ boolean lookForPackageLocked(String packageName) {
+ for (int i = 0; i < mAlarmBatches.size(); i++) {
+ Batch b = mAlarmBatches.get(i);
+ if (b.hasPackage(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void setLocked(int type, long when) {
+ if (mNativeData != 0) {
+ // The kernel never triggers alarms with negative wakeup times
+ // so we ensure they are positive.
+ long alarmSeconds, alarmNanoseconds;
+ if (when < 0) {
+ alarmSeconds = 0;
+ alarmNanoseconds = 0;
+ } else {
+ alarmSeconds = when / 1000;
+ alarmNanoseconds = (when % 1000) * 1000 * 1000;
+ }
+
+ set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+ } else {
+ Message msg = Message.obtain();
+ msg.what = ALARM_EVENT;
+
+ mHandler.removeMessages(ALARM_EVENT);
+ mHandler.sendMessageAtTime(msg, when);
+ }
+ }
+
private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
String prefix, String label, long now) {
for (int i=list.size()-1; i>=0; i--) {
@@ -1020,7 +1037,7 @@
private native int waitForAlarm(long nativeData);
private native int setKernelTimezone(long nativeData, int minuteswest);
- private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+ void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
// batches are temporally sorted, so we need only pull from the
// start of the list until we either empty it or hit a batch
// that is not yet deliverable
@@ -1166,13 +1183,13 @@
if (DEBUG_BATCH) {
Slog.v(TAG, "Time changed notification from kernel; rebatching");
}
- remove(mTimeTickSender);
+ removeImpl(mTimeTickSender);
rebatchAllAlarms();
mClockReceiver.scheduleTimeTickEvent();
Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
synchronized (mLock) {
@@ -1206,7 +1223,7 @@
Alarm alarm = triggerList.get(i);
try {
if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
- alarm.operation.send(mContext, 0,
+ alarm.operation.send(getContext(), 0,
mBackgroundIntent.putExtra(
Intent.EXTRA_ALARM_COUNT, alarm.count),
mResultReceiver, mHandler);
@@ -1248,7 +1265,7 @@
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hoser.
- remove(alarm.operation);
+ removeImpl(alarm.operation);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Failure sending alarm.", e);
@@ -1310,7 +1327,7 @@
if (alarm.repeatInterval > 0) {
// This IntentSender is no longer valid, but this
// is a repeating alarm, so toss the hoser.
- remove(alarm.operation);
+ removeImpl(alarm.operation);
}
}
}
@@ -1323,7 +1340,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_DATE_CHANGED);
- mContext.registerReceiver(this, filter);
+ getContext().registerReceiver(this, filter);
}
@Override
@@ -1354,7 +1371,7 @@
final long tickEventDelay = nextTime - currentTime;
final WorkSource workSource = null; // Let system take blame for time tick events.
- set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+ setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
0, mTimeTickSender, true, workSource);
}
@@ -1368,7 +1385,7 @@
calendar.add(Calendar.DAY_OF_MONTH, 1);
final WorkSource workSource = null; // Let system take blame for date change events.
- set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
+ setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
}
}
@@ -1379,12 +1396,12 @@
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
- mContext.registerReceiver(this, filter);
+ getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
- mContext.registerReceiver(this, sdFilter);
+ getContext().registerReceiver(this, sdFilter);
}
@Override
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 5f3f894ca..cc9055d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -19,6 +19,8 @@
import android.os.BatteryStats;
import com.android.internal.app.IBatteryStats;
import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
import android.app.ActivityManagerNative;
import android.content.ContentResolver;
@@ -134,13 +136,10 @@
private boolean mSentLowBatteryBroadcast = false;
- private BatteryListener mBatteryPropertiesListener;
- private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
-
- public BatteryService(Context context, LightsService lights) {
+ public BatteryService(Context context, LightsManager lightsManager) {
mContext = context;
mHandler = new Handler(true /*async*/);
- mLed = new Led(context, lights);
+ mLed = new Led(context, lightsManager);
mBatteryStats = BatteryStatsService.getService();
mCriticalBatteryLevel = mContext.getResources().getInteger(
@@ -158,13 +157,11 @@
"DEVPATH=/devices/virtual/switch/invalid_charger");
}
- mBatteryPropertiesListener = new BatteryListener();
-
IBinder b = ServiceManager.getService("batterypropreg");
- mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
+ final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
+ IBatteryPropertiesRegistrar.Stub.asInterface(b);
try {
- mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+ batteryPropertiesRegistrar.registerListener(new BatteryListener());
} catch (RemoteException e) {
// Should never happen.
}
@@ -688,7 +685,7 @@
};
private final class Led {
- private final LightsService.Light mBatteryLight;
+ private final Light mBatteryLight;
private final int mBatteryLowARGB;
private final int mBatteryMediumARGB;
@@ -696,8 +693,8 @@
private final int mBatteryLedOn;
private final int mBatteryLedOff;
- public Led(Context context, LightsService lights) {
- mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
+ public Led(Context context, LightsManager lights) {
+ mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
mBatteryLowARGB = context.getResources().getInteger(
com.android.internal.R.integer.config_notificationsBatteryLowARGB);
@@ -723,7 +720,7 @@
mBatteryLight.setColor(mBatteryLowARGB);
} else {
// Flash red when battery is low and not charging
- mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+ mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
mBatteryLedOn, mBatteryLedOff);
}
} else if (status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -743,8 +740,14 @@
}
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+ @Override
public void batteryPropertiesChanged(BatteryProperties props) {
- BatteryService.this.update(props);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ BatteryService.this.update(props);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index a996dbd..26424a5 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -28,7 +28,7 @@
import com.android.internal.view.IInputMethodManager;
import com.android.internal.view.IInputMethodSession;
import com.android.internal.view.InputBindResult;
-import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.wm.WindowManagerService;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/java/com/android/server/LocalServices.java b/services/java/com/android/server/LocalServices.java
new file mode 100644
index 0000000..deff79dc
--- /dev/null
+++ b/services/java/com/android/server/LocalServices.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.util.ArrayMap;
+
+/**
+ * This class is used in a similar way as ServiceManager, except the services registered here
+ * are not Binder objects and are only available in the same process.
+ *
+ * Once all services are converted to the SystemService interface, this class can be absorbed
+ * into SystemServiceManager.
+ */
+public final class LocalServices {
+ private LocalServices() {}
+
+ private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
+ new ArrayMap<Class<?>, Object>();
+
+ /**
+ * Returns a local service instance that implements the specified interface.
+ *
+ * @param type The type of service.
+ * @return The service object.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getService(Class<T> type) {
+ synchronized (sLocalServiceObjects) {
+ return (T) sLocalServiceObjects.get(type);
+ }
+ }
+
+ /**
+ * Adds a service instance of the specified interface to the global registry of local services.
+ */
+ public static <T> void addService(Class<T> type, T service) {
+ synchronized (sLocalServiceObjects) {
+ if (sLocalServiceObjects.containsKey(type)) {
+ throw new IllegalStateException("Overriding service registration");
+ }
+ sLocalServiceObjects.put(type, service);
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a42cbcf..662df92 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,8 @@
package com.android.server;
import android.app.ActivityManagerNative;
+import android.app.IAlarmManager;
+import android.app.INotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -51,13 +53,20 @@
import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.BatteryStatsService;
+import com.android.server.appwidget.AppWidgetService;
+import com.android.server.backup.BackupManagerService;
+import com.android.server.clipboard.ClipboardService;
import com.android.server.content.ContentService;
+import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.input.InputManagerService;
+import com.android.server.lights.LightsManager;
+import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
+import com.android.server.notification.NotificationManagerService;
import com.android.server.os.SchedulingPolicyService;
import com.android.server.pm.Installer;
import com.android.server.pm.PackageManagerService;
@@ -66,7 +75,12 @@
import com.android.server.power.ShutdownThread;
import com.android.server.print.PrintManagerService;
import com.android.server.search.SearchManagerService;
+import com.android.server.statusbar.StatusBarManagerService;
+import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightService;
import com.android.server.usb.UsbService;
+import com.android.server.wallpaper.WallpaperManagerService;
import com.android.server.wifi.WifiService;
import com.android.server.wm.WindowManagerService;
@@ -122,17 +136,16 @@
String factoryTestStr = SystemProperties.get("ro.factorytest");
int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
: Integer.parseInt(factoryTestStr);
- final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
Installer installer = null;
AccountManagerService accountManager = null;
ContentService contentService = null;
- LightsService lights = null;
+ LightsManager lights = null;
PowerManagerService power = null;
DisplayManagerService display = null;
BatteryService battery = null;
VibratorService vibrator = null;
- AlarmManagerService alarm = null;
+ IAlarmManager alarm = null;
MountService mountService = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
@@ -148,8 +161,7 @@
DockObserver dock = null;
UsbService usb = null;
SerialService serial = null;
- TwilightService twilight = null;
- UiModeManagerService uiMode = null;
+ TwilightManager twilight = null;
RecognitionManagerService recognition = null;
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
@@ -199,6 +211,8 @@
Slog.e("System", "************ Failure starting bootstrap service", e);
}
+ final SystemServiceManager systemServiceManager = new SystemServiceManager(context);
+
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -274,8 +288,8 @@
Slog.i(TAG, "System Content Providers");
ActivityManagerService.installSystemProviders();
- Slog.i(TAG, "Lights Service");
- lights = new LightsService(context);
+ systemServiceManager.startService(LightsService.class);
+ lights = LocalServices.getService(LightsManager.class);
Slog.i(TAG, "Battery Service");
battery = new BatteryService(context, lights);
@@ -291,17 +305,16 @@
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
- power.init(context, lights, ActivityManagerService.self(), battery,
+ power.init(context, lights, battery,
BatteryStatsService.getService(),
ActivityManagerService.self().getAppOpsService(), display);
- Slog.i(TAG, "Alarm Manager");
- alarm = new AlarmManagerService(context);
- ServiceManager.addService(Context.ALARM_SERVICE, alarm);
+ systemServiceManager.startService(AlarmManagerService.class);
+ alarm = IAlarmManager.Stub.asInterface(
+ ServiceManager.getService(Context.ALARM_SERVICE));
Slog.i(TAG, "Init Watchdog");
- Watchdog.getInstance().init(context, battery, power, alarm,
- ActivityManagerService.self());
+ Watchdog.getInstance().init(context, ActivityManagerService.self());
Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
Slog.i(TAG, "Input Manager");
@@ -346,9 +359,9 @@
DevicePolicyManagerService devicePolicy = null;
StatusBarManagerService statusBar = null;
+ INotificationManager notification = null;
InputMethodManagerService imm = null;
AppWidgetService appWidget = null;
- NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
@@ -397,7 +410,7 @@
ActivityManagerNative.getDefault().showBootMessage(
context.getResources().getText(
com.android.internal.R.string.android_upgrading_starting_apps),
- false);
+ false);
} catch (RemoteException e) {
}
@@ -567,22 +580,12 @@
reportWtf("making Content Service ready", e);
}
- try {
- Slog.i(TAG, "Notification Manager");
- notification = new NotificationManagerService(context, statusBar, lights);
- ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
- networkPolicy.bindNotificationManager(notification);
- } catch (Throwable e) {
- reportWtf("starting Notification Manager", e);
- }
+ systemServiceManager.startService(NotificationManagerService.class);
+ notification = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ networkPolicy.bindNotificationManager(notification);
- try {
- Slog.i(TAG, "Device Storage Monitor");
- ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
- new DeviceStorageMonitorService(context));
- } catch (Throwable e) {
- reportWtf("starting DeviceStorageMonitor service", e);
- }
+ systemServiceManager.startService(DeviceStorageMonitorService.class);
if (!disableLocation) {
try {
@@ -624,10 +627,8 @@
R.bool.config_enableWallpaperService)) {
try {
Slog.i(TAG, "Wallpaper Service");
- if (!headless) {
- wallpaper = new WallpaperManagerService(context);
- ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
- }
+ wallpaper = new WallpaperManagerService(context);
+ ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
} catch (Throwable e) {
reportWtf("starting Wallpaper Service", e);
}
@@ -683,20 +684,10 @@
}
}
- try {
- Slog.i(TAG, "Twilight Service");
- twilight = new TwilightService(context);
- } catch (Throwable e) {
- reportWtf("starting TwilightService", e);
- }
+ systemServiceManager.startService(TwilightService.class);
+ twilight = LocalServices.getService(TwilightManager.class);
- try {
- Slog.i(TAG, "UI Mode Manager Service");
- // Listen for UI mode changes
- uiMode = new UiModeManagerService(context, twilight);
- } catch (Throwable e) {
- reportWtf("starting UiModeManagerService", e);
- }
+ systemServiceManager.startService(UiModeManagerService.class);
if (!disableNonCoreServices) {
try {
@@ -856,13 +847,7 @@
}
}
- if (notification != null) {
- try {
- notification.systemReady();
- } catch (Throwable e) {
- reportWtf("making Notification Service ready", e);
- }
- }
+ systemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
try {
wm.systemReady();
@@ -911,8 +896,6 @@
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
final UsbService usbF = usb;
- final TwilightService twilightF = twilight;
- final UiModeManagerService uiModeF = uiMode;
final AppWidgetService appWidgetF = appWidget;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
@@ -944,8 +927,10 @@
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
- if (!headless) {
+ try {
startSystemUi(contextF);
+ } catch (Throwable e) {
+ reportWtf("starting System UI", e);
}
try {
if (mountServiceF != null) mountServiceF.systemReady();
@@ -988,16 +973,6 @@
reportWtf("making USB Service ready", e);
}
try {
- if (twilightF != null) twilightF.systemReady();
- } catch (Throwable e) {
- reportWtf("makin Twilight Service ready", e);
- }
- try {
- if (uiModeF != null) uiModeF.systemReady();
- } catch (Throwable e) {
- reportWtf("making UI Mode Service ready", e);
- }
- try {
if (recognitionF != null) recognitionF.systemReady();
} catch (Throwable e) {
reportWtf("making Recognition Service ready", e);
@@ -1006,6 +981,7 @@
// It is now okay to let the various system services start their
// third party code...
+ systemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
try {
if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
@@ -1082,6 +1058,8 @@
} catch (Throwable e) {
reportWtf("Notifying MediaRouterService running", e);
}
+
+ systemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
}
});
diff --git a/services/java/com/android/server/SystemService.java b/services/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..37afb4f
--- /dev/null
+++ b/services/java/com/android/server/SystemService.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * System services respond to lifecycle events that help the services know what
+ */
+public abstract class SystemService {
+ /*
+ * Boot Phases
+ */
+ public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+ public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+ public static final int PHASE_BOOT_COMPLETE = 1000;
+
+ private SystemServiceManager mManager;
+ private Context mContext;
+
+ final void init(Context context, SystemServiceManager manager) {
+ mContext = context;
+ mManager = manager;
+ onCreate(context);
+ }
+
+ /**
+ * Services are not yet available. This is a good place to do setup work that does
+ * not require other services.
+ *
+ * @param context The system context.
+ */
+ public void onCreate(Context context) {}
+
+ /**
+ * Called when the dependencies listed in the @Service class-annotation are available
+ * and after the chosen start phase.
+ * When this method returns, the service should be published.
+ */
+ public abstract void onStart();
+
+ /**
+ * Called on each phase of the boot process. Phases before the service's start phase
+ * (as defined in the @Service annotation) are never received.
+ *
+ * @param phase The current boot phase.
+ */
+ public void onBootPhase(int phase) {}
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service) {
+ ServiceManager.addService(name, service);
+ }
+
+ /**
+ * Get a binder service by its name.
+ */
+ protected final IBinder getBinderService(String name) {
+ return ServiceManager.getService(name);
+ }
+
+ /**
+ * Publish the service so it is only accessible to the system process.
+ */
+ protected final <T> void publishLocalService(Class<T> type, T service) {
+ LocalServices.addService(type, service);
+ }
+
+ /**
+ * Get a local service by interface.
+ */
+ protected final <T> T getLocalService(Class<T> type) {
+ return LocalServices.getService(type);
+ }
+
+ public final Context getContext() {
+ return mContext;
+ }
+
+// /**
+// * Called when a new user has been created. If your service deals with multiple users, this
+// * method should be overridden.
+// *
+// * @param userHandle The user that was created.
+// */
+// public void onUserCreated(int userHandle) {
+// }
+//
+// /**
+// * Called when an existing user has started a new session. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who started a new session.
+// */
+// public void onUserStarted(int userHandle) {
+// }
+//
+// /**
+// * Called when a background user session has entered the foreground. If your service deals with
+// * multiple users, this method should be overridden.
+// *
+// * @param userHandle The user who's session entered the foreground.
+// */
+// public void onUserForeground(int userHandle) {
+// }
+//
+// /**
+// * Called when a foreground user session has entered the background. If your service deals with
+// * multiple users, this method should be overridden;
+// *
+// * @param userHandle The user who's session entered the background.
+// */
+// public void onUserBackground(int userHandle) {
+// }
+//
+// /**
+// * Called when a user's active session has stopped. If your service deals with multiple users,
+// * this method should be overridden.
+// *
+// * @param userHandle The user who's session has stopped.
+// */
+// public void onUserStopped(int userHandle) {
+// }
+//
+// /**
+// * Called when a user has been removed from the system. If your service deals with multiple
+// * users, this method should be overridden.
+// *
+// * @param userHandle The user who has been removed.
+// */
+// public void onUserRemoved(int userHandle) {
+// }
+}
diff --git a/services/java/com/android/server/SystemServiceManager.java b/services/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..648975a
--- /dev/null
+++ b/services/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of system services.
+ */
+public class SystemServiceManager {
+ private static final String TAG = "SystemServiceManager";
+
+ private final Context mContext;
+
+ // Services that should receive lifecycle events.
+ private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+ private int mCurrentPhase = -1;
+
+ public SystemServiceManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Creates and starts a system service. The class must be a subclass of
+ * {@link com.android.server.SystemService}.
+ *
+ * @param serviceClass A Java class that implements the SystemService interface.
+ * @throws RuntimeException if the service fails to start.
+ */
+ public void startService(Class<?> serviceClass) {
+ final SystemService serviceInstance = createInstance(serviceClass);
+ try {
+ Slog.i(TAG, "Creating " + serviceClass.getSimpleName());
+ serviceInstance.init(mContext, this);
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to create service " + serviceClass.getName(), e);
+ }
+
+ mServices.add(serviceInstance);
+
+ try {
+ Slog.i(TAG, "Starting " + serviceClass.getSimpleName());
+ serviceInstance.onStart();
+ } catch (Throwable e) {
+ throw new RuntimeException("Failed to start service " + serviceClass.getName(), e);
+ }
+ }
+
+ /**
+ * Starts the specified boot phase for all system services that have been started up to
+ * this point.
+ *
+ * @param phase The boot phase to start.
+ */
+ public void startBootPhase(final int phase) {
+ if (phase <= mCurrentPhase) {
+ throw new IllegalArgumentException("Next phase must be larger than previous");
+ }
+ mCurrentPhase = phase;
+
+ Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Throwable e) {
+ reportWtf("Service " + service.getClass().getName() +
+ " threw an Exception processing boot phase " + mCurrentPhase, e);
+ }
+ }
+ }
+
+ /**
+ * Outputs the state of this manager to the System log.
+ */
+ public void dump() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+ builder.append("Services:\n");
+ final int startedLen = mServices.size();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ builder.append("\t")
+ .append(service.getClass().getSimpleName())
+ .append("\n");
+ }
+
+ Slog.e(TAG, builder.toString());
+ }
+
+ private SystemService createInstance(Class<?> clazz) {
+ // Make sure it's a type we expect
+ if (!SystemService.class.isAssignableFrom(clazz)) {
+ reportWtf("Class " + clazz.getName() + " does not extend " +
+ SystemService.class.getName());
+ }
+
+ try {
+ return (SystemService) clazz.newInstance();
+ } catch (InstantiationException e) {
+ reportWtf("Class " + clazz.getName() + " is abstract", e);
+ } catch (IllegalAccessException e) {
+ reportWtf("Class " + clazz.getName() +
+ " must have a public no-arg constructor", e);
+ }
+ return null;
+ }
+
+ private static void reportWtf(String message) {
+ reportWtf(message, null);
+ }
+
+ private static void reportWtf(String message, Throwable e) {
+ Slog.i(TAG, "******************************");
+ Log.wtf(TAG, message, e);
+
+ // Make sure we die
+ throw new RuntimeException(message, e);
+ }
+}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 062be01..de912dc 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -34,9 +34,9 @@
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.Sandman;
@@ -47,9 +47,11 @@
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
-final class UiModeManagerService extends IUiModeManager.Stub {
+final class UiModeManagerService extends SystemService {
private static final String TAG = UiModeManager.class.getSimpleName();
private static final boolean LOG = false;
@@ -57,40 +59,36 @@
private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
- private final Context mContext;
- private final TwilightService mTwilightService;
- private final Handler mHandler = new Handler();
-
final Object mLock = new Object();
-
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
- private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
- private int mNightMode = UiModeManager.MODE_NIGHT_NO;
+ private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ int mNightMode = UiModeManager.MODE_NIGHT_NO;
+
private boolean mCarModeEnabled = false;
private boolean mCharging = false;
- private final int mDefaultUiModeType;
- private final boolean mCarModeKeepsScreenOn;
- private final boolean mDeskModeKeepsScreenOn;
- private final boolean mTelevision;
-
+ private int mDefaultUiModeType;
+ private boolean mCarModeKeepsScreenOn;
+ private boolean mDeskModeKeepsScreenOn;
+ private boolean mTelevision;
private boolean mComputedNightMode;
- private int mCurUiMode = 0;
+
+ int mCurUiMode = 0;
private int mSetUiMode = 0;
-
private boolean mHoldingConfiguration = false;
+
private Configuration mConfiguration = new Configuration();
+ boolean mSystemReady;
- private boolean mSystemReady;
+ private final Handler mHandler = new Handler();
+ private TwilightManager mTwilightManager;
private NotificationManager mNotificationManager;
-
private StatusBarManager mStatusBarManager;
- private final PowerManager mPowerManager;
- private final PowerManager.WakeLock mWakeLock;
+ private PowerManager.WakeLock mWakeLock;
- static Intent buildHomeIntent(String category) {
+ private static Intent buildHomeIntent(String category) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(category);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -142,28 +140,26 @@
}
};
- private final TwilightService.TwilightListener mTwilightListener =
- new TwilightService.TwilightListener() {
+ private final TwilightListener mTwilightListener = new TwilightListener() {
@Override
public void onTwilightStateChanged() {
updateTwilight();
}
};
- public UiModeManagerService(Context context, TwilightService twilight) {
- mContext = context;
- mTwilightService = twilight;
+ @Override
+ public void onStart() {
+ final Context context = getContext();
+ mTwilightManager = getLocalService(TwilightManager.class);
+ final PowerManager powerManager =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
- ServiceManager.addService(Context.UI_MODE_SERVICE, this);
-
- mContext.registerReceiver(mDockModeReceiver,
+ context.registerReceiver(mDockModeReceiver,
new IntentFilter(Intent.ACTION_DOCK_EVENT));
- mContext.registerReceiver(mBatteryReceiver,
+ context.registerReceiver(mBatteryReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
-
mConfiguration.setToDefaults();
mDefaultUiModeType = context.getResources().getInteger(
@@ -175,101 +171,139 @@
mTelevision = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEVISION);
- mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ mNightMode = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
- mTwilightService.registerListener(mTwilightListener, mHandler);
+ mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+ publishBinderService(Context.UI_MODE_SERVICE, mService);
}
- @Override // Binder call
- public void disableCarMode(int flags) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- setCarModeLocked(false);
- if (mSystemReady) {
- updateLocked(0, flags);
+ private final IBinder mService = new IUiModeManager.Stub() {
+ @Override
+ public void enableCarMode(int flags) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setCarModeLocked(true);
+ if (mSystemReady) {
+ updateLocked(flags, 0);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public void enableCarMode(int flags) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- setCarModeLocked(true);
- if (mSystemReady) {
- updateLocked(flags, 0);
+ @Override
+ public void disableCarMode(int flags) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ setCarModeLocked(false);
+ if (mSystemReady) {
+ updateLocked(0, flags);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public int getCurrentModeType() {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public void setNightMode(int mode) {
- switch (mode) {
- case UiModeManager.MODE_NIGHT_NO:
- case UiModeManager.MODE_NIGHT_YES:
- case UiModeManager.MODE_NIGHT_AUTO:
- break;
- default:
- throw new IllegalArgumentException("Unknown mode: " + mode);
}
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- if (isDoingNightModeLocked() && mNightMode != mode) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.UI_NIGHT_MODE, mode);
- mNightMode = mode;
- updateLocked(0, 0);
+ @Override
+ public int getCurrentModeType() {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
- }
- @Override // Binder call
- public int getNightMode() {
+ @Override
+ public void setNightMode(int mode) {
+ switch (mode) {
+ case UiModeManager.MODE_NIGHT_NO:
+ case UiModeManager.MODE_NIGHT_YES:
+ case UiModeManager.MODE_NIGHT_AUTO:
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown mode: " + mode);
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ if (isDoingNightModeLocked() && mNightMode != mode) {
+ Settings.Secure.putInt(getContext().getContentResolver(),
+ Settings.Secure.UI_NIGHT_MODE, mode);
+ mNightMode = mode;
+ updateLocked(0, 0);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public int getNightMode() {
+ synchronized (mLock) {
+ return mNightMode;
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump uimode service from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
+ }
+ };
+
+ void dumpImpl(PrintWriter pw) {
synchronized (mLock) {
- return mNightMode;
+ pw.println("Current UI Mode Service state:");
+ pw.print(" mDockState="); pw.print(mDockState);
+ pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+ pw.print(" mNightMode="); pw.print(mNightMode);
+ pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+ pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
+ pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+ pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+ pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
+ pw.print(" mSystemReady="); pw.println(mSystemReady);
+ pw.print(" mTwilightService.getCurrentState()=");
+ pw.println(mTwilightManager.getCurrentState());
}
}
- void systemReady() {
- synchronized (mLock) {
- mSystemReady = true;
- mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
- updateComputedNightModeLocked();
- updateLocked(0, 0);
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ synchronized (mLock) {
+ mSystemReady = true;
+ mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+ updateComputedNightModeLocked();
+ updateLocked(0, 0);
+ }
}
}
- private boolean isDoingNightModeLocked() {
+ boolean isDoingNightModeLocked() {
return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
}
- private void setCarModeLocked(boolean enabled) {
+ void setCarModeLocked(boolean enabled) {
if (mCarModeEnabled != enabled) {
mCarModeEnabled = enabled;
}
@@ -344,7 +378,7 @@
}
}
- private void updateLocked(int enableFlags, int disableFlags) {
+ void updateLocked(int enableFlags, int disableFlags) {
String action = null;
String oldAction = null;
if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
@@ -359,7 +393,7 @@
adjustStatusBarCarModeLocked();
if (oldAction != null) {
- mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+ getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
}
mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
action = UiModeManager.ACTION_ENTER_CAR_MODE;
@@ -367,7 +401,7 @@
} else if (isDeskDockState(mDockState)) {
if (!isDeskDockState(mLastBroadcastState)) {
if (oldAction != null) {
- mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+ getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
}
mLastBroadcastState = mDockState;
action = UiModeManager.ACTION_ENTER_DESK_MODE;
@@ -393,7 +427,7 @@
Intent intent = new Intent(action);
intent.putExtra("enableFlags", enableFlags);
intent.putExtra("disableFlags", disableFlags);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+ getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
mResultReceiver, null, Activity.RESULT_OK, null, null);
// Attempting to make this transition a little more clean, we are going
@@ -491,7 +525,7 @@
// activity manager take care of both the start and config
// change.
Intent homeIntent = buildHomeIntent(category);
- if (Sandman.shouldStartDockApp(mContext, homeIntent)) {
+ if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityManagerNative.getDefault().startActivityWithConfig(
null, null, homeIntent, null, null, null, 0, 0,
@@ -513,14 +547,15 @@
// If we did not start a dock app, then start dreaming if supported.
if (category != null && !dockAppStarted) {
- Sandman.startDreamWhenDockedIfAppropriate(mContext);
+ Sandman.startDreamWhenDockedIfAppropriate(getContext());
}
}
private void adjustStatusBarCarModeLocked() {
+ final Context context = getContext();
if (mStatusBarManager == null) {
mStatusBarManager = (StatusBarManager)
- mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+ context.getSystemService(Context.STATUS_BAR_SERVICE);
}
// Fear not: StatusBarManagerService manages a list of requests to disable
@@ -536,12 +571,12 @@
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ context.getSystemService(Context.NOTIFICATION_SERVICE);
}
if (mNotificationManager != null) {
if (mCarModeEnabled) {
- Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+ Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
Notification n = new Notification();
n.icon = R.drawable.stat_notify_car_mode;
@@ -549,10 +584,10 @@
n.flags = Notification.FLAG_ONGOING_EVENT;
n.when = 0;
n.setLatestEventInfo(
- mContext,
- mContext.getString(R.string.car_mode_disable_notification_title),
- mContext.getString(R.string.car_mode_disable_notification_message),
- PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
+ context,
+ context.getString(R.string.car_mode_disable_notification_title),
+ context.getString(R.string.car_mode_disable_notification_message),
+ PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
null, UserHandle.CURRENT));
mNotificationManager.notifyAsUser(null,
R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
@@ -563,7 +598,7 @@
}
}
- private void updateTwilight() {
+ void updateTwilight() {
synchronized (mLock) {
if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
updateComputedNightModeLocked();
@@ -573,36 +608,11 @@
}
private void updateComputedNightModeLocked() {
- TwilightState state = mTwilightService.getCurrentState();
+ TwilightState state = mTwilightManager.getCurrentState();
if (state != null) {
mComputedNightMode = state.isNight();
}
}
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump uimode service from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- synchronized (mLock) {
- pw.println("Current UI Mode Service state:");
- pw.print(" mDockState="); pw.print(mDockState);
- pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
- pw.print(" mNightMode="); pw.print(mNightMode);
- pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
- pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
- pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
- pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
- pw.print(" mHoldingConfiguration="); pw.print(mHoldingConfiguration);
- pw.print(" mSystemReady="); pw.println(mSystemReady);
- pw.print(" mTwilightService.getCurrentState()=");
- pw.println(mTwilightService.getCurrentState());
- }
- }
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index e17f42d..b249953 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -80,9 +80,6 @@
final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
final HandlerChecker mMonitorChecker;
ContentResolver mResolver;
- BatteryService mBattery;
- PowerManagerService mPower;
- AlarmManagerService mAlarm;
ActivityManagerService mActivity;
int mPhonePid;
@@ -234,13 +231,8 @@
"i/o thread", DEFAULT_TIMEOUT));
}
- public void init(Context context, BatteryService battery,
- PowerManagerService power, AlarmManagerService alarm,
- ActivityManagerService activity) {
+ public void init(Context context, ActivityManagerService activity) {
mResolver = context.getContentResolver();
- mBattery = battery;
- mPower = power;
- mAlarm = alarm;
mActivity = activity;
context.registerReceiver(new RebootRequestReceiver(),
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index fc66e45..05666b4 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -29,7 +29,9 @@
import android.app.AppOpsManager;
import android.appwidget.AppWidgetManager;
+import android.graphics.Rect;
import android.util.ArrayMap;
+import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
@@ -52,7 +54,6 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.UserManagerService;
import com.android.server.wm.AppTransition;
-import com.android.server.wm.StackBox;
import com.android.server.wm.WindowManagerService;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -68,7 +69,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackBoxInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
@@ -331,8 +331,6 @@
public IntentFirewall mIntentFirewall;
- private final boolean mHeadless;
-
// Whether we should show our dialogs (ANR, crash, etc) or just perform their
// default actuion automatically. Important for devices without direct input
// devices.
@@ -1772,7 +1770,7 @@
public void setWindowManager(WindowManagerService wm) {
mWindowManager = wm;
mStackSupervisor.setWindowManager(wm);
- wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f);
+ wm.createStack(HOME_STACK_ID, Display.DEFAULT_DISPLAY);
}
public void startObservingNativeCrashes() {
@@ -1984,8 +1982,6 @@
mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
- mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
// User 0 is the first and only user that runs at boot.
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
mUserLru.add(Integer.valueOf(0));
@@ -2853,13 +2849,6 @@
}
boolean startHomeActivityLocked(int userId) {
- if (mHeadless) {
- // Added because none of the other calls to ensureBootCompleted seem to fire
- // when running headless.
- ensureBootCompleted();
- return false;
- }
-
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopAction == null) {
// We are running in factory test mode, but unable to find
@@ -5000,7 +4989,7 @@
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
- if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
+ if (mStackSupervisor.attachApplicationLocked(app)) {
didSomething = true;
}
} catch (Exception e) {
@@ -7107,16 +7096,15 @@
}
@Override
- public int createStack(int taskId, int relativeStackBoxId, int position, float weight) {
+ public int createStack(int taskId) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"createStack()");
- if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" +
- relativeStackBoxId + " position=" + position + " weight=" + weight);
+ if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId);
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
int stackId = mStackSupervisor.createStack();
- mWindowManager.createStack(stackId, relativeStackBoxId, position, weight);
+ mWindowManager.createStack(stackId, Display.DEFAULT_DISPLAY);
if (taskId > 0) {
moveTaskToStack(taskId, stackId, true);
}
@@ -7148,99 +7136,40 @@
}
@Override
- public void resizeStackBox(int stackBoxId, float weight) {
+ public void resizeStack(int stackBoxId, Rect bounds) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"resizeStackBox()");
long ident = Binder.clearCallingIdentity();
try {
- mWindowManager.resizeStackBox(stackBoxId, weight);
+ mWindowManager.resizeStack(stackBoxId, bounds);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- private ArrayList<StackInfo> getStacks() {
- synchronized (this) {
- ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>();
- ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks();
- for (ActivityStack stack : stacks) {
- ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
- int stackId = stack.mStackId;
- stackInfo.stackId = stackId;
- stackInfo.bounds = mWindowManager.getStackBounds(stackId);
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
- final int numTasks = tasks.size();
- int[] taskIds = new int[numTasks];
- String[] taskNames = new String[numTasks];
- for (int i = 0; i < numTasks; ++i) {
- final TaskRecord task = tasks.get(i);
- taskIds[i] = task.taskId;
- taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
- : task.realActivity != null ? task.realActivity.flattenToString()
- : task.getTopActivity() != null ? task.getTopActivity().packageName
- : "unknown";
- }
- stackInfo.taskIds = taskIds;
- stackInfo.taskNames = taskNames;
- list.add(stackInfo);
- }
- return list;
- }
- }
-
- private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) {
- final int stackId = stackBoxInfo.stackId;
- if (stackId >= 0) {
- for (StackInfo stackInfo : stackInfos) {
- if (stackId == stackInfo.stackId) {
- stackBoxInfo.stack = stackInfo;
- stackInfos.remove(stackInfo);
- return;
- }
- }
- } else {
- addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos);
- addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos);
- }
- }
-
@Override
- public List<StackBoxInfo> getStackBoxes() {
+ public List<StackInfo> getAllStackInfos() {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"getStackBoxes()");
long ident = Binder.clearCallingIdentity();
try {
- List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
synchronized (this) {
- List<StackInfo> stackInfos = getStacks();
- for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
- addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
- }
+ return mStackSupervisor.getAllStackInfos();
}
- return stackBoxInfos;
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@Override
- public StackBoxInfo getStackBoxInfo(int stackBoxId) {
+ public StackInfo getStackInfo(int stackId) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getStackBoxInfo()");
+ "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
- List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
- StackBoxInfo info = null;
synchronized (this) {
- List<StackInfo> stackInfos = getStacks();
- for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
- addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
- if (stackBoxInfo.stackBoxId == stackBoxId) {
- info = stackBoxInfo;
- }
- }
+ return mStackSupervisor.getStackInfo(stackId);
}
- return info;
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -9496,10 +9425,6 @@
private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg,
String stackTrace) {
- if (mHeadless) {
- Log.e(TAG, "handleAppCrashLocked: " + app.processName);
- return false;
- }
long now = SystemClock.uptimeMillis();
Long crashTime;
@@ -14042,9 +13967,6 @@
*/
boolean updateConfigurationLocked(Configuration values,
ActivityRecord starting, boolean persistent, boolean initLocale) {
- // do nothing if we are headless
- if (mHeadless) return true;
-
int changes = 0;
if (values != null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 47593f2..82d29a9 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1287,17 +1287,7 @@
if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
- ArrayList<ActivityRecord> activities = prevTask.mActivities;
- final int numActivities = activities.size();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- // r is usually the same as next, but what if two activities were launched
- // before prev finished?
- if (!r.finishing) {
- r.frontOfTask = true;
- break;
- }
- }
+ prevTask.setFrontOfTask();
} else if (prevTask != topTask()) {
// This task is going away but it was supposed to return to the home task.
// Now the task above it has to return to the home task instead.
@@ -1749,9 +1739,9 @@
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
+ task.setFrontOfTask();
r.putInHistory();
- r.frontOfTask = newTask;
if (!isHomeStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
@@ -2412,15 +2402,12 @@
final ArrayList<ActivityRecord> activities = r.task.mActivities;
final int index = activities.indexOf(r);
if (index < (activities.size() - 1)) {
- ActivityRecord next = activities.get(index+1);
- if (r.frontOfTask) {
- // The next activity is now the front of the task.
- next.frontOfTask = true;
- }
+ r.task.setFrontOfTask();
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
// If the caller asked that this activity (and all above it)
// be cleared when the task is reset, don't lose that information,
// but propagate it up to the next activity.
+ ActivityRecord next = activities.get(index+1);
next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 483b4a0..4a46288 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -34,6 +34,7 @@
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
@@ -70,11 +71,11 @@
import android.util.Slog;
import android.util.SparseIntArray;
+import android.view.Display;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.os.TransferPipe;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.wm.StackBox;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -366,7 +367,7 @@
return resumedActivity;
}
- boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
+ boolean attachApplicationLocked(ProcessRecord app) throws Exception {
boolean didSomething = false;
final String processName = app.processName;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -379,10 +380,7 @@
if (hr.app == null && app.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
- if (headless) {
- Slog.e(TAG, "Starting activities not supported on headless device: "
- + hr);
- } else if (realStartActivityLocked(hr, app, true, true)) {
+ if (realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
@@ -1291,8 +1289,7 @@
}
// Time to create the first app stack for this user.
- int stackId =
- mService.createStack(-1, HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f);
+ int stackId = mService.createStack(-1);
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
" stackId=" + stackId);
mFocusedStack = getStack(stackId);
@@ -2647,4 +2644,43 @@
}
}
}
+
+ StackInfo getStackInfo(ActivityStack stack) {
+ StackInfo info = new StackInfo();
+ mWindowManager.getStackBounds(stack.mStackId, info.bounds);
+ info.displayId = Display.DEFAULT_DISPLAY;
+ info.stackId = stack.mStackId;
+
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final int numTasks = tasks.size();
+ int[] taskIds = new int[numTasks];
+ String[] taskNames = new String[numTasks];
+ for (int i = 0; i < numTasks; ++i) {
+ final TaskRecord task = tasks.get(i);
+ taskIds[i] = task.taskId;
+ taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+ : task.realActivity != null ? task.realActivity.flattenToString()
+ : task.getTopActivity() != null ? task.getTopActivity().packageName
+ : "unknown";
+ }
+ info.taskIds = taskIds;
+ info.taskNames = taskNames;
+ return info;
+ }
+
+ StackInfo getStackInfo(int stackId) {
+ ActivityStack stack = getStack(stackId);
+ if (stack != null) {
+ return getStackInfo(stack);
+ }
+ return null;
+ }
+
+ ArrayList<StackInfo> getAllStackInfos() {
+ ArrayList<StackInfo> list = new ArrayList<StackInfo>();
+ for (int ndx = mStacks.size() - 1; ndx >= 0; --ndx) {
+ list.add(getStackInfo(mStacks.get(ndx)));
+ }
+ return list;
+ }
}
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 80e6e94..cb04835 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -18,7 +18,8 @@
import com.android.internal.app.ProcessStats;
import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.NotificationManagerService;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
import android.app.INotificationManager;
import android.app.Notification;
@@ -427,8 +428,8 @@
final Notification localForegroundNoti = foregroundNoti;
ams.mHandler.post(new Runnable() {
public void run() {
- NotificationManagerService nm =
- (NotificationManagerService) NotificationManager.getService();
+ NotificationManagerInternal nm = LocalServices.getService(
+ NotificationManagerInternal.class);
if (nm == null) {
return;
}
@@ -479,7 +480,7 @@
throw new RuntimeException("icon must be non-zero");
}
int[] outId = new int[1];
- nm.enqueueNotificationInternal(localPackageName, localPackageName,
+ nm.enqueueNotification(localPackageName, localPackageName,
appUid, appPid, null, localForegroundId, localForegroundNoti,
outId, userId);
} catch (RuntimeException e) {
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 3d568ff..5f32dbb 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -159,18 +159,33 @@
return null;
}
+ /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
+ final void setFrontOfTask() {
+ boolean foundFront = false;
+ final int numActivities = mActivities.size();
+ for (int activityNdx = 0; numActivities < activityNdx; ++activityNdx) {
+ final ActivityRecord r = mActivities.get(activityNdx);
+ if (foundFront || r.finishing) {
+ r.frontOfTask = false;
+ } else {
+ r.frontOfTask = true;
+ // Set frontOfTask false for every following activity.
+ foundFront = true;
+ }
+ }
+ }
+
/**
- * Reorder the history stack so that the activity at the given index is
- * brought to the front.
+ * Reorder the history stack so that the passed activity is brought to the front.
*/
final void moveActivityToFrontLocked(ActivityRecord newTop) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
+ " to stack at top", new RuntimeException("here").fillInStackTrace());
- getTopActivity().frontOfTask = false;
mActivities.remove(newTop);
mActivities.add(newTop);
- newTop.frontOfTask = true;
+
+ setFrontOfTask();
}
void addActivityAtBottom(ActivityRecord r) {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/appwidget/AppWidgetService.java
similarity index 98%
rename from services/java/com/android/server/AppWidgetService.java
rename to services/java/com/android/server/appwidget/AppWidgetService.java
index 203cca6..6fd8871 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/appwidget/AppWidgetService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.appwidget;
import android.app.ActivityManager;
import android.appwidget.AppWidgetProviderInfo;
@@ -48,7 +48,7 @@
/**
* Redirects calls to this service to the instance of the service for the appropriate user.
*/
-class AppWidgetService extends IAppWidgetService.Stub
+public class AppWidgetService extends IAppWidgetService.Stub
{
private static final String TAG = "AppWidgetService";
@@ -60,7 +60,7 @@
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
- AppWidgetService(Context context) {
+ public AppWidgetService(Context context) {
mContext = context;
mSaveStateHandler = BackgroundThread.getHandler();
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
similarity index 99%
rename from services/java/com/android/server/AppWidgetServiceImpl.java
rename to services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 69ae846..98dead3 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.appwidget;
import android.app.AlarmManager;
import android.app.AppGlobals;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/backup/BackupManagerService.java
similarity index 99%
rename from services/java/com/android/server/BackupManagerService.java
rename to services/java/com/android/server/backup/BackupManagerService.java
index 00bfee7..c2b0d10c 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/backup/BackupManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.backup;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
@@ -83,7 +83,8 @@
import com.android.internal.backup.IBackupTransport;
import com.android.internal.backup.IObbBackupService;
import com.android.internal.backup.LocalTransport;
-import com.android.server.PackageManagerBackupAgent.Metadata;
+import com.android.server.EventLogTags;
+import com.android.server.backup.PackageManagerBackupAgent.Metadata;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -135,7 +136,7 @@
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
-class BackupManagerService extends IBackupManager.Stub {
+public class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
private static final boolean DEBUG = true;
private static final boolean MORE_DEBUG = false;
@@ -1178,7 +1179,8 @@
// First, on an encrypted device we require matching the device pw
final boolean isEncrypted;
try {
- isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+ isEncrypted = (mMountService.getEncryptionState() !=
+ IMountService.ENCRYPTION_STATE_NONE);
if (isEncrypted) {
if (DEBUG) {
Slog.i(TAG, "Device encrypted; verifying against device data pw");
@@ -5437,7 +5439,8 @@
boolean isEncrypted;
try {
- isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+ isEncrypted = (mMountService.getEncryptionState() !=
+ IMountService.ENCRYPTION_STATE_NONE);
if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
} catch (RemoteException e) {
// couldn't contact the mount service; fail "safe" and assume encryption
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/backup/PackageManagerBackupAgent.java
similarity index 99%
rename from services/java/com/android/server/PackageManagerBackupAgent.java
rename to services/java/com/android/server/backup/PackageManagerBackupAgent.java
index 77bddb0..495da88 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.backup;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/backup/SystemBackupAgent.java
similarity index 79%
rename from services/java/com/android/server/SystemBackupAgent.java
rename to services/java/com/android/server/backup/SystemBackupAgent.java
index 8cf273d..26e2e2a 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/backup/SystemBackupAgent.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.backup;
+import android.app.IWallpaperManager;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupAgentHelper;
@@ -26,11 +27,11 @@
import android.content.Context;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Slog;
-
import java.io.File;
import java.io.IOException;
@@ -63,16 +64,23 @@
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// We only back up the data under the current "wallpaper" schema with metadata
- WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+ IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
Context.WALLPAPER_SERVICE);
String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
- if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
- // When the wallpaper has a name, back up the info by itself.
- // TODO: Don't rely on the innards of the service object like this!
- // TODO: Send a delete for any stored wallpaper image in this case?
- files = new String[] { WALLPAPER_INFO };
- keys = new String[] { WALLPAPER_INFO_KEY };
+ if (wallpaper != null) {
+ try {
+ final String wallpaperName = wallpaper.getName();
+ if (wallpaperName != null && wallpaperName.length() > 0) {
+ // When the wallpaper has a name, back up the info by itself.
+ // TODO: Don't rely on the innards of the service object like this!
+ // TODO: Send a delete for any stored wallpaper image in this case?
+ files = new String[] { WALLPAPER_INFO };
+ keys = new String[] { WALLPAPER_INFO_KEY };
+ }
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
+ }
}
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
super.onBackup(oldState, data, newState);
@@ -109,9 +117,15 @@
try {
super.onRestore(data, appVersionCode, newState);
- WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+ IWallpaperManager wallpaper = (IWallpaperManager) ServiceManager.getService(
Context.WALLPAPER_SERVICE);
- wallpaper.settingsRestored();
+ if (wallpaper != null) {
+ try {
+ wallpaper.settingsRestored();
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Couldn't restore settings\n" + re);
+ }
+ }
} catch (IOException ex) {
// If there was a failure, delete everything for the wallpaper, this is too aggressive,
// but this is hopefully a rare failure.
@@ -149,10 +163,16 @@
FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
if (restoredWallpaper) {
- WallpaperManagerService wallpaper =
- (WallpaperManagerService)ServiceManager.getService(
+ IWallpaperManager wallpaper =
+ (IWallpaperManager)ServiceManager.getService(
Context.WALLPAPER_SERVICE);
- wallpaper.settingsRestored();
+ if (wallpaper != null) {
+ try {
+ wallpaper.settingsRestored();
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Couldn't restore settings\n" + re);
+ }
+ }
}
} catch (IOException e) {
if (restoredWallpaper) {
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/clipboard/ClipboardService.java
similarity index 99%
rename from services/java/com/android/server/ClipboardService.java
rename to services/java/com/android/server/clipboard/ClipboardService.java
index 069ae23..6aa596d 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/clipboard/ClipboardService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.clipboard;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
similarity index 89%
rename from services/java/com/android/server/DevicePolicyManagerService.java
rename to services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2bb99d6..af36246 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.devicepolicy;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
@@ -117,7 +117,7 @@
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
- private static final String TAG = "DevicePolicyManagerService";
+ private static final String LOG_TAG = "DevicePolicyManagerService";
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
@@ -186,7 +186,7 @@
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
- if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+ if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
@@ -218,6 +218,28 @@
};
static class ActiveAdmin {
+ private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
+ private static final String TAG_DISABLE_CAMERA = "disable-camera";
+ private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
+ private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
+ private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
+ private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list";
+ private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec";
+ private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy";
+ private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
+ private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
+ private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
+ private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
+ private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
+ private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters";
+ private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase";
+ private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase";
+ private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
+ private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
+ private static final String ATTR_VALUE = "value";
+ private static final String TAG_PASSWORD_QUALITY = "password-quality";
+ private static final String TAG_POLICIES = "policies";
+
final DeviceAdminInfo info;
int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -281,103 +303,103 @@
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
- out.startTag(null, "policies");
+ out.startTag(null, TAG_POLICIES);
info.writePoliciesToXml(out);
- out.endTag(null, "policies");
+ out.endTag(null, TAG_POLICIES);
if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
- out.startTag(null, "password-quality");
- out.attribute(null, "value", Integer.toString(passwordQuality));
- out.endTag(null, "password-quality");
+ out.startTag(null, TAG_PASSWORD_QUALITY);
+ out.attribute(null, ATTR_VALUE, Integer.toString(passwordQuality));
+ out.endTag(null, TAG_PASSWORD_QUALITY);
if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
- out.startTag(null, "min-password-length");
- out.attribute(null, "value", Integer.toString(minimumPasswordLength));
- out.endTag(null, "min-password-length");
+ out.startTag(null, TAG_MIN_PASSWORD_LENGTH);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLength));
+ out.endTag(null, TAG_MIN_PASSWORD_LENGTH);
}
if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
- out.startTag(null, "password-history-length");
- out.attribute(null, "value", Integer.toString(passwordHistoryLength));
- out.endTag(null, "password-history-length");
+ out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH);
+ out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength));
+ out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH);
}
if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
- out.startTag(null, "min-password-uppercase");
- out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
- out.endTag(null, "min-password-uppercase");
+ out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordUpperCase));
+ out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE);
}
if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
- out.startTag(null, "min-password-lowercase");
- out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
- out.endTag(null, "min-password-lowercase");
+ out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLowerCase));
+ out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE);
}
if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
- out.startTag(null, "min-password-letters");
- out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
- out.endTag(null, "min-password-letters");
+ out.startTag(null, TAG_MIN_PASSWORD_LETTERS);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLetters));
+ out.endTag(null, TAG_MIN_PASSWORD_LETTERS);
}
if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
- out.startTag(null, "min-password-numeric");
- out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
- out.endTag(null, "min-password-numeric");
+ out.startTag(null, TAG_MIN_PASSWORD_NUMERIC);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNumeric));
+ out.endTag(null, TAG_MIN_PASSWORD_NUMERIC);
}
if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
- out.startTag(null, "min-password-symbols");
- out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
- out.endTag(null, "min-password-symbols");
+ out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordSymbols));
+ out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS);
}
if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
- out.startTag(null, "min-password-nonletter");
- out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
- out.endTag(null, "min-password-nonletter");
+ out.startTag(null, TAG_MIN_PASSWORD_NONLETTER);
+ out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNonLetter));
+ out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
}
}
if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
- out.startTag(null, "max-time-to-unlock");
- out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
- out.endTag(null, "max-time-to-unlock");
+ out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
+ out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
+ out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
}
if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
- out.startTag(null, "max-failed-password-wipe");
- out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
- out.endTag(null, "max-failed-password-wipe");
+ out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
+ out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
+ out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
}
if (specifiesGlobalProxy) {
- out.startTag(null, "specifies-global-proxy");
- out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
- out.endTag(null, "specifies_global_proxy");
+ out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy));
+ out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
if (globalProxySpec != null) {
- out.startTag(null, "global-proxy-spec");
- out.attribute(null, "value", globalProxySpec);
- out.endTag(null, "global-proxy-spec");
+ out.startTag(null, TAG_GLOBAL_PROXY_SPEC);
+ out.attribute(null, ATTR_VALUE, globalProxySpec);
+ out.endTag(null, TAG_GLOBAL_PROXY_SPEC);
}
if (globalProxyExclusionList != null) {
- out.startTag(null, "global-proxy-exclusion-list");
- out.attribute(null, "value", globalProxyExclusionList);
- out.endTag(null, "global-proxy-exclusion-list");
+ out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
+ out.attribute(null, ATTR_VALUE, globalProxyExclusionList);
+ out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
}
}
if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
- out.startTag(null, "password-expiration-timeout");
- out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
- out.endTag(null, "password-expiration-timeout");
+ out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
+ out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout));
+ out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
}
if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
- out.startTag(null, "password-expiration-date");
- out.attribute(null, "value", Long.toString(passwordExpirationDate));
- out.endTag(null, "password-expiration-date");
+ out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE);
+ out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate));
+ out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE);
}
if (encryptionRequested) {
- out.startTag(null, "encryption-requested");
- out.attribute(null, "value", Boolean.toString(encryptionRequested));
- out.endTag(null, "encryption-requested");
+ out.startTag(null, TAG_ENCRYPTION_REQUESTED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
+ out.endTag(null, TAG_ENCRYPTION_REQUESTED);
}
if (disableCamera) {
- out.startTag(null, "disable-camera");
- out.attribute(null, "value", Boolean.toString(disableCamera));
- out.endTag(null, "disable-camera");
+ out.startTag(null, TAG_DISABLE_CAMERA);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
+ out.endTag(null, TAG_DISABLE_CAMERA);
}
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
- out.startTag(null, "disable-keyguard-features");
- out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
- out.endTag(null, "disable-keyguard-features");
+ out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
+ out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
+ out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
}
}
@@ -391,67 +413,67 @@
continue;
}
String tag = parser.getName();
- if ("policies".equals(tag)) {
+ if (TAG_POLICIES.equals(tag)) {
info.readPoliciesFromXml(parser);
- } else if ("password-quality".equals(tag)) {
+ } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
passwordQuality = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-length".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
minimumPasswordLength = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("password-history-length".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
passwordHistoryLength = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-uppercase".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
minimumPasswordUpperCase = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-lowercase".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
minimumPasswordLowerCase = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-letters".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
minimumPasswordLetters = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-numeric".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
minimumPasswordNumeric = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-symbols".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
minimumPasswordSymbols = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("min-password-nonletter".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
minimumPasswordNonLetter = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("max-time-to-unlock".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("max-failed-password-wipe".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
maximumFailedPasswordsForWipe = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
- } else if ("specifies-global-proxy".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
specifiesGlobalProxy = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("global-proxy-spec".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
globalProxySpec =
- parser.getAttributeValue(null, "value");
- } else if ("global-proxy-exclusion-list".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) {
globalProxyExclusionList =
- parser.getAttributeValue(null, "value");
- } else if ("password-expiration-timeout".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE);
+ } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
passwordExpirationTimeout = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("password-expiration-date".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
passwordExpirationDate = Long.parseLong(
- parser.getAttributeValue(null, "value"));
- } else if ("encryption-requested".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
encryptionRequested = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("disable-camera".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_CAMERA.equals(tag)) {
disableCamera = Boolean.parseBoolean(
- parser.getAttributeValue(null, "value"));
- } else if ("disable-keyguard-features".equals(tag)) {
+ parser.getAttributeValue(null, ATTR_VALUE));
+ } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
- parser.getAttributeValue(null, "value"));
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
- Slog.w(TAG, "Unknown admin tag: " + tag);
+ Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
}
XmlUtils.skipCurrentTag(parser);
}
@@ -513,7 +535,7 @@
private void handlePackagesChanged(int userHandle) {
boolean removed = false;
- if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
+ if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
IPackageManager pm = AppGlobals.getPackageManager();
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -585,7 +607,7 @@
void removeUserData(int userHandle) {
synchronized (this) {
if (userHandle == UserHandle.USER_OWNER) {
- Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+ Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
DevicePolicyData policy = mUserData.get(userHandle);
@@ -595,7 +617,7 @@
File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
- Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+ Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
}
}
@@ -792,10 +814,12 @@
try {
return new DeviceAdminInfo(mContext, infos.get(0));
} catch (XmlPullParserException e) {
- Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+ Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+ e);
return null;
} catch (IOException e) {
- Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+ Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+ e);
return null;
}
}
@@ -922,7 +946,7 @@
ComponentName.unflattenFromString(name), userHandle);
if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
!= userHandle)) {
- Slog.w(TAG, "findAdmin returned an incorrect uid "
+ Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
+ dai.getActivityInfo().applicationInfo.uid + " for user "
+ userHandle);
}
@@ -933,7 +957,7 @@
policy.mAdminList.add(ap);
}
} catch (RuntimeException e) {
- Slog.w(TAG, "Failed loading admin " + name, e);
+ Slog.w(LOG_TAG, "Failed loading admin " + name, e);
}
} else if ("failed-password-attempts".equals(tag)) {
policy.mFailedPasswordAttempts = Integer.parseInt(
@@ -962,22 +986,22 @@
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else {
- Slog.w(TAG, "Unknown tag: " + tag);
+ Slog.w(LOG_TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
}
}
} catch (NullPointerException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (XmlPullParserException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (FileNotFoundException e) {
// Don't be noisy, this is normal if we haven't defined any policies.
} catch (IOException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
} catch (IndexOutOfBoundsException e) {
- Slog.w(TAG, "failed parsing " + file + " " + e);
+ Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
}
try {
if (stream != null) {
@@ -993,7 +1017,7 @@
// never normally happen.
LockPatternUtils utils = new LockPatternUtils(mContext);
if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
- Slog.w(TAG, "Active password quality 0x"
+ Slog.w(LOG_TAG, "Active password quality 0x"
+ Integer.toHexString(policy.mActivePasswordQuality)
+ " does not match actual quality 0x"
+ Integer.toHexString(utils.getActivePasswordQuality()));
@@ -1037,7 +1061,7 @@
}
}
if (!haveOwner) {
- Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+ Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner
+ " no longer active; disabling");
policy.mPasswordOwner = -1;
}
@@ -1057,7 +1081,7 @@
long token = Binder.clearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
- if (DBG) Slog.v(TAG, "Change in camera state ["
+ if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
+ SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
} finally {
@@ -1173,7 +1197,8 @@
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
+ if (!refreshing
+ && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
ActiveAdmin newAdmin = new ActiveAdmin(info);
@@ -1443,7 +1468,7 @@
ap.passwordExpirationDate = expiration;
ap.passwordExpirationTimeout = timeout;
if (timeout > 0L) {
- Slog.w(TAG, "setPasswordExpiration(): password will expire on "
+ Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
.format(new Date(expiration)));
}
@@ -1789,11 +1814,11 @@
return true;
}
return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
- && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
- && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
- && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
- && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
- && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+ && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+ && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+ && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+ && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+ && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
}
}
@@ -1871,7 +1896,7 @@
int realQuality = LockPatternUtils.computePasswordQuality(password);
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
- Slog.w(TAG, "resetPassword: password quality 0x"
+ Slog.w(LOG_TAG, "resetPassword: password quality 0x"
+ Integer.toHexString(realQuality)
+ " does not meet required quality 0x"
+ Integer.toHexString(quality));
@@ -1881,7 +1906,7 @@
}
int length = getPasswordMinimumLength(null, userHandle);
if (password.length() < length) {
- Slog.w(TAG, "resetPassword: password length " + password.length()
+ Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
+ " does not meet required length " + length);
return false;
}
@@ -1910,40 +1935,40 @@
}
int neededLetters = getPasswordMinimumLetters(null, userHandle);
if(letters < neededLetters) {
- Slog.w(TAG, "resetPassword: number of letters " + letters
+ Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
+ " does not meet required number of letters " + neededLetters);
return false;
}
int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
- Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+ Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
+ " does not meet required number of numerical digits "
+ neededNumbers);
return false;
}
int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
if (lowercase < neededLowerCase) {
- Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+ Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
+ " does not meet required number of lowercase letters "
+ neededLowerCase);
return false;
}
int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
if (uppercase < neededUpperCase) {
- Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+ Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
+ " does not meet required number of uppercase letters "
+ neededUpperCase);
return false;
}
int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
if (symbols < neededSymbols) {
- Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+ Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
+ " does not meet required number of special symbols " + neededSymbols);
return false;
}
int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
if (nonletter < neededNonLetter) {
- Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+ Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
+ " does not meet required number of non-letter characters "
+ neededNonLetter);
return false;
@@ -1954,7 +1979,7 @@
int callingUid = Binder.getCallingUid();
DevicePolicyData policy = getUserData(userHandle);
if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
- Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
+ Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
@@ -2020,7 +2045,7 @@
try {
getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
} catch (RemoteException e) {
- Slog.w(TAG, "Failure talking with power manager", e);
+ Slog.w(LOG_TAG, "Failure talking with power manager", e);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -2095,10 +2120,10 @@
X509Certificate cert = parseCert(certBuffer);
pemCert = Credentials.convertToPem(cert);
} catch (CertificateException ce) {
- Log.e(TAG, "Problem converting cert", ce);
+ Log.e(LOG_TAG, "Problem converting cert", ce);
return false;
} catch (IOException ioe) {
- Log.e(TAG, "Problem reading cert", ioe);
+ Log.e(LOG_TAG, "Problem reading cert", ioe);
return false;
}
try {
@@ -2113,7 +2138,7 @@
}
}
} catch (InterruptedException e1) {
- Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
+ Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
}
return false;
@@ -2134,10 +2159,10 @@
X509Certificate cert = parseCert(certBuffer);
alias = certStore.getCertificateAlias(cert);
} catch (CertificateException ce) {
- Log.e(TAG, "Problem creating X509Certificate", ce);
+ Log.e(LOG_TAG, "Problem creating X509Certificate", ce);
return;
} catch (IOException ioe) {
- Log.e(TAG, "Problem reading certificate", ioe);
+ Log.e(LOG_TAG, "Problem reading certificate", ioe);
return;
}
try {
@@ -2146,13 +2171,13 @@
try {
service.deleteCaCertificate(alias);
} catch (RemoteException e) {
- Log.e(TAG, "from CaCertUninstaller: ", e);
+ Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
} finally {
keyChainConnection.close();
keyChainConnection = null;
}
} catch (InterruptedException ie) {
- Log.w(TAG, "CaCertUninstaller: ", ie);
+ Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
}
}
@@ -2173,7 +2198,7 @@
try {
RecoverySystem.rebootWipeUserData(mContext);
} catch (IOException e) {
- Slog.w(TAG, "Failed requesting data wipe", e);
+ Slog.w(LOG_TAG, "Failed requesting data wipe", e);
}
}
}
@@ -2264,8 +2289,10 @@
if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
|| p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
|| p.mActivePasswordUpperCase != uppercase
- || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
- || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
+ || p.mActivePasswordLowerCase != lowercase
+ || p.mActivePasswordNumeric != numbers
+ || p.mActivePasswordSymbols != symbols
+ || p.mActivePasswordNonLetter != nonletter) {
long ident = Binder.clearCallingIdentity();
try {
p.mActivePasswordQuality = quality;
@@ -2387,7 +2414,7 @@
// If the user is not the owner, don't set the global proxy. Fail silently.
if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+ Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
+ userHandle + " is not permitted.");
return null;
}
@@ -2468,7 +2495,7 @@
ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
if (!proxyProperties.isValid()) {
- Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+ Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
@@ -2494,7 +2521,7 @@
// Only owner can set storage encryption
if (userHandle != UserHandle.USER_OWNER
|| UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
- Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+ Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return 0;
}
@@ -2880,7 +2907,7 @@
}
}
} catch (NameNotFoundException nnfe) {
- Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+ Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
}
return false;
}
@@ -2905,9 +2932,9 @@
mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
input.close();
} catch (XmlPullParserException xppe) {
- Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+ Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
} catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+ Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
}
}
@@ -2935,7 +2962,7 @@
out.flush();
file.finishWrite(output);
} catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+ Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
}
}
}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index bcb677f..73040d5 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -102,7 +102,6 @@
// Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
- private static final String SYSTEM_HEADLESS = "ro.config.headless";
private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
@@ -116,7 +115,6 @@
private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
private final Context mContext;
- private final boolean mHeadless;
private final DisplayManagerHandler mHandler;
private final Handler mUiHandler;
private final DisplayAdapterListener mDisplayAdapterListener;
@@ -202,8 +200,6 @@
public DisplayManagerService(Context context, Handler mainHandler) {
mContext = context;
- mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
-
mHandler = new DisplayManagerHandler(mainHandler.getLooper());
mUiHandler = UiThread.getHandler();
mDisplayAdapterListener = new DisplayAdapterListener();
@@ -270,15 +266,6 @@
}
/**
- * Returns true if the device is headless.
- *
- * @return True if the device is headless.
- */
- public boolean isHeadless() {
- return mHeadless;
- }
-
- /**
* Registers a display transaction listener to provide the client a chance to
* update its surfaces within the same transaction as any display layout updates.
*
@@ -779,13 +766,8 @@
private void registerDefaultDisplayAdapter() {
// Register default display adapter.
synchronized (mSyncRoot) {
- if (mHeadless) {
- registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
- } else {
- registerDisplayAdapterLocked(new LocalDisplayAdapter(
- mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
- }
+ registerDisplayAdapterLocked(new LocalDisplayAdapter(
+ mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
}
}
@@ -1153,7 +1135,6 @@
pw.println("DISPLAY MANAGER (dumpsys display)");
synchronized (mSyncRoot) {
- pw.println(" mHeadless=" + mHeadless);
pw.println(" mOnlyCode=" + mOnlyCore);
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
deleted file mode 100644
index 7a104d7..0000000
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.display;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.DisplayMetrics;
-import android.view.Display;
-
-/**
- * Provides a fake default display for headless systems.
- * <p>
- * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
- * </p>
- */
-final class HeadlessDisplayAdapter extends DisplayAdapter {
- private static final String TAG = "HeadlessDisplayAdapter";
-
- // Called with SyncRoot lock held.
- public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
- Context context, Handler handler, Listener listener) {
- super(syncRoot, context, handler, listener, TAG);
- }
-
- @Override
- public void registerLocked() {
- super.registerLocked();
- sendDisplayDeviceEventLocked(new HeadlessDisplayDevice(), DISPLAY_DEVICE_EVENT_ADDED);
- }
-
- private final class HeadlessDisplayDevice extends DisplayDevice {
- private DisplayDeviceInfo mInfo;
-
- public HeadlessDisplayDevice() {
- super(HeadlessDisplayAdapter.this, null);
- }
-
- @Override
- public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
- if (mInfo == null) {
- mInfo = new DisplayDeviceInfo();
- mInfo.name = getContext().getResources().getString(
- com.android.internal.R.string.display_manager_built_in_display_name);
- mInfo.width = 640;
- mInfo.height = 480;
- mInfo.refreshRate = 60;
- mInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
- mInfo.xDpi = 160;
- mInfo.yDpi = 160;
- mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
- | DisplayDeviceInfo.FLAG_SECURE
- | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
- mInfo.type = Display.TYPE_BUILT_IN;
- mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
- }
- return mInfo;
- }
- }
-}
diff --git a/services/java/com/android/server/lights/Light.java b/services/java/com/android/server/lights/Light.java
new file mode 100644
index 0000000..b496b4c6
--- /dev/null
+++ b/services/java/com/android/server/lights/Light.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.lights;
+
+public abstract class Light {
+ public static final int LIGHT_FLASH_NONE = 0;
+ public static final int LIGHT_FLASH_TIMED = 1;
+ public static final int LIGHT_FLASH_HARDWARE = 2;
+
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ public static final int BRIGHTNESS_MODE_USER = 0;
+
+ /**
+ * Light brightness is managed by a light sensor.
+ */
+ public static final int BRIGHTNESS_MODE_SENSOR = 1;
+
+ public abstract void setBrightness(int brightness);
+ public abstract void setBrightness(int brightness, int brightnessMode);
+ public abstract void setColor(int color);
+ public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+ public abstract void pulse();
+ public abstract void pulse(int color, int onMS);
+ public abstract void turnOff();
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/lights/LightsManager.java b/services/java/com/android/server/lights/LightsManager.java
new file mode 100644
index 0000000..2f20509
--- /dev/null
+++ b/services/java/com/android/server/lights/LightsManager.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.lights;
+
+public abstract class LightsManager {
+ public static final int LIGHT_ID_BACKLIGHT = 0;
+ public static final int LIGHT_ID_KEYBOARD = 1;
+ public static final int LIGHT_ID_BUTTONS = 2;
+ public static final int LIGHT_ID_BATTERY = 3;
+ public static final int LIGHT_ID_NOTIFICATIONS = 4;
+ public static final int LIGHT_ID_ATTENTION = 5;
+ public static final int LIGHT_ID_BLUETOOTH = 6;
+ public static final int LIGHT_ID_WIFI = 7;
+ public static final int LIGHT_ID_COUNT = 8;
+
+ public abstract Light getLight(int id);
+}
diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/lights/LightsService.java
similarity index 73%
rename from services/java/com/android/server/LightsService.java
rename to services/java/com/android/server/lights/LightsService.java
index 89bfcac..d814785 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/java/com/android/server/lights/LightsService.java
@@ -14,59 +14,38 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.lights;
+
+import com.android.server.SystemService;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IHardwareService;
-import android.os.ServiceManager;
import android.os.Message;
import android.util.Slog;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-public class LightsService {
- private static final String TAG = "LightsService";
- private static final boolean DEBUG = false;
+public class LightsService extends SystemService {
+ static final String TAG = "LightsService";
+ static final boolean DEBUG = false;
- public static final int LIGHT_ID_BACKLIGHT = 0;
- public static final int LIGHT_ID_KEYBOARD = 1;
- public static final int LIGHT_ID_BUTTONS = 2;
- public static final int LIGHT_ID_BATTERY = 3;
- public static final int LIGHT_ID_NOTIFICATIONS = 4;
- public static final int LIGHT_ID_ATTENTION = 5;
- public static final int LIGHT_ID_BLUETOOTH = 6;
- public static final int LIGHT_ID_WIFI = 7;
- public static final int LIGHT_ID_COUNT = 8;
+ final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
- public static final int LIGHT_FLASH_NONE = 0;
- public static final int LIGHT_FLASH_TIMED = 1;
- public static final int LIGHT_FLASH_HARDWARE = 2;
+ private final class LightImpl extends Light {
- /**
- * Light brightness is managed by a user setting.
- */
- public static final int BRIGHTNESS_MODE_USER = 0;
-
- /**
- * Light brightness is managed by a light sensor.
- */
- public static final int BRIGHTNESS_MODE_SENSOR = 1;
-
- private final Light mLights[] = new Light[LIGHT_ID_COUNT];
-
- public final class Light {
-
- private Light(int id) {
+ private LightImpl(int id) {
mId = id;
}
+ @Override
public void setBrightness(int brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
+ @Override
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
int color = brightness & 0x000000ff;
@@ -75,23 +54,26 @@
}
}
+ @Override
public void setColor(int color) {
synchronized (this) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
+ @Override
public void setFlashing(int color, int mode, int onMS, int offMS) {
synchronized (this) {
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
}
-
+ @Override
public void pulse() {
pulse(0x00ffffff, 7);
}
+ @Override
public void pulse(int color, int onMS) {
synchronized (this) {
if (mColor == 0 && !mFlashing) {
@@ -101,6 +83,7 @@
}
}
+ @Override
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
@@ -153,9 +136,10 @@
}
public void setFlashlightEnabled(boolean on) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
+ final Context context = getContext();
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
!= PackageManager.PERMISSION_GRANTED &&
- mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+ context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
}
@@ -172,31 +156,41 @@
}
};
- LightsService(Context context) {
-
+ @Override
+ public void onCreate(Context context) {
mNativePointer = init_native();
- mContext = context;
- ServiceManager.addService("hardware", mLegacyFlashlightHack);
-
- for (int i = 0; i < LIGHT_ID_COUNT; i++) {
- mLights[i] = new Light(i);
+ for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
+ mLights[i] = new LightImpl(i);
}
}
+ @Override
+ public void onStart() {
+ publishBinderService("hardware", mLegacyFlashlightHack);
+ publishLocalService(LightsManager.class, mService);
+ }
+
+ private final LightsManager mService = new LightsManager() {
+ @Override
+ public com.android.server.lights.Light getLight(int id) {
+ if (id < LIGHT_ID_COUNT) {
+ return mLights[id];
+ } else {
+ return null;
+ }
+ }
+ };
+
protected void finalize() throws Throwable {
finalize_native(mNativePointer);
super.finalize();
}
- public Light getLight(int id) {
- return mLights[id];
- }
-
private Handler mH = new Handler() {
@Override
public void handleMessage(Message msg) {
- Light light = (Light)msg.obj;
+ LightImpl light = (LightImpl)msg.obj;
light.stopFlashing();
}
};
@@ -204,10 +198,8 @@
private static native int init_native();
private static native void finalize_native(int ptr);
- private static native void setLight_native(int ptr, int light, int color, int mode,
+ static native void setLight_native(int ptr, int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
- private final Context mContext;
-
- private int mNativePointer;
+ int mNativePointer;
}
diff --git a/services/java/com/android/server/notification/NotificationDelegate.java b/services/java/com/android/server/notification/NotificationDelegate.java
new file mode 100644
index 0000000..df2aaca
--- /dev/null
+++ b/services/java/com/android/server/notification/NotificationDelegate.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+public interface NotificationDelegate {
+ void onSetDisabled(int status);
+ void onClearAll();
+ void onNotificationClick(String pkg, String tag, int id);
+ void onNotificationClear(String pkg, String tag, int id);
+ void onNotificationError(String pkg, String tag, int id,
+ int uid, int initialPid, String message);
+ void onPanelRevealed();
+}
diff --git a/services/java/com/android/server/notification/NotificationManagerInternal.java b/services/java/com/android/server/notification/NotificationManagerInternal.java
new file mode 100644
index 0000000..92ffdcc
--- /dev/null
+++ b/services/java/com/android/server/notification/NotificationManagerInternal.java
@@ -0,0 +1,8 @@
+package com.android.server.notification;
+
+import android.app.Notification;
+
+public interface NotificationManagerInternal {
+ void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int[] idReceived, int userId);
+}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/notification/NotificationManagerService.java
similarity index 78%
rename from services/java/com/android/server/NotificationManagerService.java
rename to services/java/com/android/server/notification/NotificationManagerService.java
index 0438675..db4cf31d 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/notification/NotificationManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.notification;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -47,7 +47,6 @@
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.media.AudioManager;
-import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
@@ -56,9 +55,7 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
@@ -78,6 +75,12 @@
import com.android.internal.R;
import com.android.internal.notification.NotificationScorer;
+import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.SystemService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -99,66 +102,61 @@
import libcore.io.IoUtils;
-
/** {@hide} */
-public class NotificationManagerService extends INotificationManager.Stub
-{
- private static final String TAG = "NotificationService";
- private static final boolean DBG = false;
+public class NotificationManagerService extends SystemService {
+ static final String TAG = "NotificationService";
+ static final boolean DBG = false;
- private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
+ static final int MAX_PACKAGE_NOTIFICATIONS = 50;
// message codes
- private static final int MESSAGE_TIMEOUT = 2;
+ static final int MESSAGE_TIMEOUT = 2;
- private static final int LONG_DELAY = 3500; // 3.5 seconds
- private static final int SHORT_DELAY = 2000; // 2 seconds
+ static final int LONG_DELAY = 3500; // 3.5 seconds
+ static final int SHORT_DELAY = 2000; // 2 seconds
- private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
- private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
+ static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
+ static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
- private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
- private static final boolean SCORE_ONGOING_HIGHER = false;
+ static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
+ static final boolean SCORE_ONGOING_HIGHER = false;
- private static final int JUNK_SCORE = -1000;
- private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
- private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+ static final int JUNK_SCORE = -1000;
+ static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+ static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
// Notifications with scores below this will not interrupt the user, either via LED or
// sound or vibration
- private static final int SCORE_INTERRUPTION_THRESHOLD =
+ static final int SCORE_INTERRUPTION_THRESHOLD =
Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
- private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
- private static final boolean ENABLE_BLOCKED_TOASTS = true;
+ static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
+ static final boolean ENABLE_BLOCKED_TOASTS = true;
- private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+ static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
- final Context mContext;
- final IActivityManager mAm;
- final UserManager mUserManager;
+ private IActivityManager mAm;
+ AudioManager mAudioManager;
+ StatusBarManagerInternal mStatusBar;
+ Vibrator mVibrator;
+
final IBinder mForegroundToken = new Binder();
-
private WorkerHandler mHandler;
- private StatusBarManagerService mStatusBar;
- private LightsService.Light mNotificationLight;
- private LightsService.Light mAttentionLight;
+ private Light mNotificationLight;
+ Light mAttentionLight;
private int mDefaultNotificationColor;
private int mDefaultNotificationLedOn;
+
private int mDefaultNotificationLedOff;
-
private long[] mDefaultVibrationPattern;
+
private long[] mFallbackVibrationPattern;
+ boolean mSystemReady;
- private boolean mSystemReady;
- private int mDisabledNotifications;
-
- private NotificationRecord mSoundNotification;
- private NotificationRecord mVibrateNotification;
-
- private IAudioService mAudioService;
- private Vibrator mVibrator;
+ int mDisabledNotifications;
+ NotificationRecord mSoundNotification;
+ NotificationRecord mVibrateNotification;
// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
@@ -166,15 +164,15 @@
private boolean mNotificationPulseEnabled;
// used as a mutex for access to all active notifications & listeners
- private final ArrayList<NotificationRecord> mNotificationList =
+ final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
- private ArrayList<ToastRecord> mToastQueue;
+ final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
- private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
- private NotificationRecord mLedNotification;
+ ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
+ NotificationRecord mLedNotification;
- private final AppOpsManager mAppOps;
+ private AppOpsManager mAppOps;
// contains connections to all connected listeners, including app services
// and system listeners
@@ -202,9 +200,9 @@
private static final String TAG_PACKAGE = "package";
private static final String ATTR_NAME = "name";
- private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+ final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
- private class NotificationListenerInfo implements DeathRecipient {
+ private class NotificationListenerInfo implements IBinder.DeathRecipient {
INotificationListener listener;
ComponentName component;
int userid;
@@ -262,7 +260,7 @@
public void binderDied() {
if (connection == null) {
// This is not a service; it won't be recreated. We can give up this connection.
- unregisterListener(this.listener, this.userid);
+ unregisterListenerImpl(this.listener, this.userid);
}
}
@@ -400,12 +398,14 @@
tag = parser.getName();
if (type == START_TAG) {
if (TAG_BODY.equals(tag)) {
- version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+ version = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_VERSION));
} else if (TAG_BLOCKED_PKGS.equals(tag)) {
while ((type = parser.next()) != END_DOCUMENT) {
tag = parser.getName();
if (TAG_PACKAGE.equals(tag)) {
- mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+ mBlockedPackages.add(
+ parser.getAttributeValue(null, ATTR_NAME));
} else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
break;
}
@@ -428,15 +428,6 @@
}
}
- /**
- * Use this when you just want to know if notifications are OK for this package.
- */
- public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- checkCallerIsSystem();
- return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
- == AppOpsManager.MODE_ALLOWED);
- }
-
/** Use this when you actually want to post a notification or toast.
*
* Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
@@ -450,21 +441,6 @@
return true;
}
- public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
- checkCallerIsSystem();
-
- Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-
- mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
- enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
- // Now, cancel any outstanding notifications that are part of a just-disabled app
- if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
- cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
- }
- }
-
-
private static String idDebugString(Context baseContext, String packageName, int id) {
Context c = null;
@@ -490,57 +466,6 @@
}
}
- /**
- * System-only API for getting a list of current (i.e. not cleared) notifications.
- *
- * Requires ACCESS_NOTIFICATIONS which is signature|system.
- */
- @Override
- public StatusBarNotification[] getActiveNotifications(String callingPkg) {
- // enforce() will ensure the calling uid has the correct permission
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
- "NotificationManagerService.getActiveNotifications");
-
- StatusBarNotification[] tmp = null;
- int uid = Binder.getCallingUid();
-
- // noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
- == AppOpsManager.MODE_ALLOWED) {
- synchronized (mNotificationList) {
- tmp = new StatusBarNotification[mNotificationList.size()];
- final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- tmp[i] = mNotificationList.get(i).sbn;
- }
- }
- }
- return tmp;
- }
-
- /**
- * System-only API for getting a list of recent (cleared, no longer shown) notifications.
- *
- * Requires ACCESS_NOTIFICATIONS which is signature|system.
- */
- @Override
- public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
- // enforce() will ensure the calling uid has the correct permission
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
- "NotificationManagerService.getHistoricalNotifications");
-
- StatusBarNotification[] tmp = null;
- int uid = Binder.getCallingUid();
-
- // noteOp will check to make sure the callingPkg matches the uid
- if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
- == AppOpsManager.MODE_ALLOWED) {
- synchronized (mArchive) {
- tmp = mArchive.getArray(count);
- }
- }
- return tmp;
- }
/**
* Remove notification access for any services that no longer exist.
@@ -548,12 +473,12 @@
void disableNonexistentListeners() {
int currentUser = ActivityManager.getCurrentUser();
String flatIn = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
currentUser);
if (!TextUtils.isEmpty(flatIn)) {
if (DBG) Slog.v(TAG, "flat before: " + flatIn);
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
new Intent(NotificationListenerService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -589,7 +514,7 @@
}
if (DBG) Slog.v(TAG, "flat after: " + flatOut);
if (!flatIn.equals(flatOut)) {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
flatOut, currentUser);
}
@@ -603,7 +528,7 @@
void rebindListenerServices() {
final int currentUser = ActivityManager.getCurrentUser();
String flat = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
+ getContext().getContentResolver(),
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
currentUser);
@@ -652,28 +577,6 @@
}
}
- /**
- * Register a listener binder directly with the notification manager.
- *
- * Only works with system callers. Apps should extend
- * {@link android.service.notification.NotificationListenerService}.
- */
- @Override
- public void registerListener(final INotificationListener listener,
- final ComponentName component, final int userid) {
- checkCallerIsSystem();
-
- synchronized (mNotificationList) {
- try {
- NotificationListenerInfo info
- = new NotificationListenerInfo(listener, component, userid, true);
- listener.asBinder().linkToDeath(info, 0);
- mListeners.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- }
/**
* Version of registerListener that takes the name of a
@@ -703,7 +606,7 @@
if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
mListeners.remove(i);
if (info.connection != null) {
- mContext.unbindService(info.connection);
+ getContext().unbindService(info.connection);
}
}
}
@@ -713,21 +616,25 @@
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
R.string.notification_listener_binding_label);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
- mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
try {
if (DBG) Slog.v(TAG, "binding: " + intent);
- if (!mContext.bindServiceAsUser(intent,
+ if (!getContext().bindServiceAsUser(intent,
new ServiceConnection() {
INotificationListener mListener;
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mNotificationList) {
mServicesBinding.remove(servicesBindingTag);
try {
mListener = INotificationListener.Stub.asInterface(service);
- NotificationListenerInfo info = new NotificationListenerInfo(
+ NotificationListenerInfo info
+ = new NotificationListenerInfo(
mListener, name, userid, this);
service.linkToDeath(info, 0);
mListeners.add(info);
@@ -756,28 +663,6 @@
}
}
- /**
- * Remove a listener binder directly
- */
- @Override
- public void unregisterListener(INotificationListener listener, int userid) {
- // no need to check permissions; if your listener binder is in the list,
- // that's proof that you had permission to add it in the first place
-
- synchronized (mNotificationList) {
- final int N = mListeners.size();
- for (int i=N-1; i>=0; i--) {
- final NotificationListenerInfo info = mListeners.get(i);
- if (info.listener.asBinder() == listener.asBinder()
- && info.userid == userid) {
- mListeners.remove(i);
- if (info.connection != null) {
- mContext.unbindService(info.connection);
- }
- }
- }
- }
- }
/**
* Remove a listener service for the given user by ComponentName
@@ -794,7 +679,7 @@
mListeners.remove(i);
if (info.connection != null) {
try {
- mContext.unbindService(info.connection);
+ getContext().unbindService(info.connection);
} catch (IllegalArgumentException ex) {
// something happened to the service: we think we have a connection
// but it's bogus.
@@ -809,7 +694,7 @@
/**
* asynchronously notify all listeners about a new notification
*/
- private void notifyPostedLocked(NotificationRecord n) {
+ void notifyPostedLocked(NotificationRecord n) {
// make a copy in case changes are made to the underlying Notification object
final StatusBarNotification sbn = n.sbn.clone();
for (final NotificationListenerInfo info : mListeners) {
@@ -824,7 +709,7 @@
/**
* asynchronously notify all listeners about a removed notification
*/
- private void notifyRemovedLocked(NotificationRecord n) {
+ void notifyRemovedLocked(NotificationRecord n) {
// make a copy in case changes are made to the underlying Notification object
// NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
final StatusBarNotification sbn_light = n.sbn.cloneLight();
@@ -850,66 +735,7 @@
throw new SecurityException("Disallowed call from unknown listener: " + listener);
}
- /**
- * Allow an INotificationListener to simulate a "clear all" operation.
- *
- * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public void cancelAllNotificationsFromListener(INotificationListener token) {
- NotificationListenerInfo info = checkListenerToken(token);
- long identity = Binder.clearCallingIdentity();
- try {
- cancelAll(info.userid);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- /**
- * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
- *
- * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
- NotificationListenerInfo info = checkListenerToken(token);
- long identity = Binder.clearCallingIdentity();
- try {
- cancelNotification(pkg, tag, id, 0,
- Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
- true,
- info.userid);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
- * Allow an INotificationListener to request the list of outstanding notifications seen by
- * the current user. Useful when starting up, after which point the listener callbacks should
- * be used.
- *
- * @param token The binder for the listener, to check that the caller is allowed
- */
- public StatusBarNotification[] getActiveNotificationsFromListener(INotificationListener token) {
- NotificationListenerInfo info = checkListenerToken(token);
-
- StatusBarNotification[] result = new StatusBarNotification[0];
- ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
- synchronized (mNotificationList) {
- final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- StatusBarNotification sbn = mNotificationList.get(i).sbn;
- if (info.enabledAndUserMatches(sbn)) {
- list.add(sbn);
- }
- }
- }
- return list.toArray(result);
- }
// -- end of listener APIs --
@@ -992,8 +818,8 @@
return String.format(
"NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)",
System.identityHashCode(this),
- this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(),
- this.sbn.getScore(), this.sbn.getNotification());
+ this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
+ this.sbn.getTag(), this.sbn.getScore(), this.sbn.getNotification());
}
}
@@ -1031,9 +857,9 @@
}
}
- private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
- = new StatusBarManagerService.NotificationCallbacks() {
+ private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
+ @Override
public void onSetDisabled(int status) {
synchronized (mNotificationList) {
mDisabledNotifications = status;
@@ -1041,7 +867,7 @@
// cancel whatever's going on
long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -1060,12 +886,14 @@
}
}
+ @Override
public void onClearAll() {
// XXX to be totally correct, the caller should tell us which user
// this is for.
cancelAll(ActivityManager.getCurrentUser());
}
+ @Override
public void onNotificationClick(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
@@ -1074,6 +902,7 @@
ActivityManager.getCurrentUser());
}
+ @Override
public void onNotificationClear(String pkg, String tag, int id) {
// XXX to be totally correct, the caller should tell us which user
// this is for.
@@ -1082,6 +911,7 @@
true, ActivityManager.getCurrentUser());
}
+ @Override
public void onPanelRevealed() {
synchronized (mNotificationList) {
// sound
@@ -1089,7 +919,7 @@
long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -1114,6 +944,7 @@
}
}
+ @Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
@@ -1168,7 +999,7 @@
if (packageChanged) {
// We cancel notifications for packages which have just been disabled
try {
- final int enabled = mContext.getPackageManager()
+ final int enabled = getContext().getPackageManager()
.getApplicationEnabledSetting(pkgName);
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
@@ -1244,7 +1075,7 @@
}
void observe() {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
@@ -1257,7 +1088,7 @@
}
public void update(Uri uri) {
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
boolean pulseEnabled = Settings.System.getInt(resolver,
Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
@@ -1287,28 +1118,24 @@
return out;
}
- NotificationManagerService(Context context, StatusBarManagerService statusBar,
- LightsService lights)
- {
- super();
- mContext = context;
- mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+ @Override
+ public void onStart() {
mAm = ActivityManagerNative.getDefault();
- mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
- mToastQueue = new ArrayList<ToastRecord>();
- mHandler = new WorkerHandler();
+ mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
- mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+ mHandler = new WorkerHandler();
importOldBlockDb();
- mStatusBar = statusBar;
- statusBar.setNotificationCallbacks(mNotificationCallbacks);
+ mStatusBar = getLocalService(StatusBarManagerInternal.class);
+ mStatusBar.setNotificationDelegate(mNotificationDelegate);
- mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
- mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+ final LightsManager lights = getLocalService(LightsManager.class);
+ mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+ mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
- Resources resources = mContext.getResources();
+ Resources resources = getContext().getResources();
mDefaultNotificationColor = resources.getColor(
R.color.config_defaultNotificationColor);
mDefaultNotificationLedOn = resources.getInteger(
@@ -1330,7 +1157,7 @@
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
// flag at least once and we'll go back to 0 after that.
- if (0 == Settings.Global.getInt(mContext.getContentResolver(),
+ if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0)) {
mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
}
@@ -1343,7 +1170,7 @@
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_STOPPED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiver(mIntentReceiver, filter);
+ getContext().registerReceiver(mIntentReceiver, filter);
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1351,9 +1178,9 @@
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
- mContext.registerReceiver(mIntentReceiver, pkgFilter);
+ getContext().registerReceiver(mIntentReceiver, pkgFilter);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mIntentReceiver, sdFilter);
+ getContext().registerReceiver(mIntentReceiver, sdFilter);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
@@ -1363,9 +1190,9 @@
R.array.config_notificationScorers);
for (String scorerName : notificationScorerNames) {
try {
- Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+ Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
- scorer.initialize(mContext);
+ scorer.initialize(getContext());
mScorers.add(scorer);
} catch (ClassNotFoundException e) {
Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
@@ -1375,6 +1202,9 @@
Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
}
}
+
+ publishBinderService(Context.NOTIFICATION_SERVICE, mService);
+ publishLocalService(NotificationManagerInternal.class, mInternalService);
}
/**
@@ -1383,12 +1213,12 @@
private void importOldBlockDb() {
loadBlockDb();
- PackageManager pm = mContext.getPackageManager();
+ PackageManager pm = getContext().getPackageManager();
for (String pkg : mBlockedPackages) {
PackageInfo info = null;
try {
info = pm.getPackageInfo(pkg, 0);
- setNotificationsEnabledForPackage(pkg, info.applicationInfo.uid, false);
+ setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
} catch (NameNotFoundException e) {
// forget you
}
@@ -1399,244 +1229,421 @@
}
}
- void systemReady() {
- mAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ // no beeping until we're basically done booting
+ mSystemReady = true;
- // no beeping until we're basically done booting
- mSystemReady = true;
+ // Grab our optional AudioService
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
- // make sure our listener services are properly bound
- rebindListenerServices();
- }
-
- // Toasts
- // ============================================================================
- public void enqueueToast(String pkg, ITransientNotification callback, int duration)
- {
- if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
-
- if (pkg == null || callback == null) {
- Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
- return ;
- }
-
- final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
-
- if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
- if (!isSystemToast) {
- Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
- return;
- }
- }
-
- synchronized (mToastQueue) {
- int callingPid = Binder.getCallingPid();
- long callingId = Binder.clearCallingIdentity();
- try {
- ToastRecord record;
- int index = indexOfToastLocked(pkg, callback);
- // If it's already in the queue, we update it in place, we don't
- // move it to the end of the queue.
- if (index >= 0) {
- record = mToastQueue.get(index);
- record.update(duration);
- } else {
- // Limit the number of toasts that any given package except the android
- // package can enqueue. Prevents DOS attacks and deals with leaks.
- if (!isSystemToast) {
- int count = 0;
- final int N = mToastQueue.size();
- for (int i=0; i<N; i++) {
- final ToastRecord r = mToastQueue.get(i);
- if (r.pkg.equals(pkg)) {
- count++;
- if (count >= MAX_PACKAGE_NOTIFICATIONS) {
- Slog.e(TAG, "Package has already posted " + count
- + " toasts. Not showing more. Package=" + pkg);
- return;
- }
- }
- }
- }
-
- record = new ToastRecord(callingPid, pkg, callback, duration);
- mToastQueue.add(record);
- index = mToastQueue.size() - 1;
- keepProcessAliveLocked(callingPid);
- }
- // If it's at index 0, it's the current toast. It doesn't matter if it's
- // new or just been updated. Call back and tell it to show itself.
- // If the callback fails, this will remove it from the list, so don't
- // assume that it's valid after this.
- if (index == 0) {
- showNextToastLocked();
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
+ // make sure our listener services are properly bound
+ rebindListenerServices();
}
}
- public void cancelToast(String pkg, ITransientNotification callback) {
- Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+ void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
+ Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
- if (pkg == null || callback == null) {
- Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
- return ;
- }
+ mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
+ enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
- synchronized (mToastQueue) {
- long callingId = Binder.clearCallingIdentity();
- try {
- int index = indexOfToastLocked(pkg, callback);
- if (index >= 0) {
- cancelToastLocked(index);
- } else {
- Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
- }
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
+ // Now, cancel any outstanding notifications that are part of a just-disabled app
+ if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+ cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
}
}
- private void showNextToastLocked() {
- ToastRecord record = mToastQueue.get(0);
- while (record != null) {
- if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
- try {
- record.callback.show();
- scheduleTimeoutLocked(record);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Object died trying to show notification " + record.callback
- + " in package " + record.pkg);
- // remove it from the list and let the process die
- int index = mToastQueue.indexOf(record);
- if (index >= 0) {
- mToastQueue.remove(index);
- }
- keepProcessAliveLocked(record.pid);
- if (mToastQueue.size() > 0) {
- record = mToastQueue.get(0);
- } else {
- record = null;
- }
- }
- }
- }
+ private final IBinder mService = new INotificationManager.Stub() {
+ // Toasts
+ // ============================================================================
- private void cancelToastLocked(int index) {
- ToastRecord record = mToastQueue.get(index);
- try {
- record.callback.hide();
- } catch (RemoteException e) {
- Slog.w(TAG, "Object died trying to hide notification " + record.callback
- + " in package " + record.pkg);
- // don't worry about this, we're about to remove it from
- // the list anyway
- }
- mToastQueue.remove(index);
- keepProcessAliveLocked(record.pid);
- if (mToastQueue.size() > 0) {
- // Show the next one. If the callback fails, this will remove
- // it from the list, so don't assume that the list hasn't changed
- // after this point.
- showNextToastLocked();
- }
- }
-
- private void scheduleTimeoutLocked(ToastRecord r)
- {
- mHandler.removeCallbacksAndMessages(r);
- Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
- long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
- mHandler.sendMessageDelayed(m, delay);
- }
-
- private void handleTimeout(ToastRecord record)
- {
- if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
- synchronized (mToastQueue) {
- int index = indexOfToastLocked(record.pkg, record.callback);
- if (index >= 0) {
- cancelToastLocked(index);
- }
- }
- }
-
- // lock on mToastQueue
- private int indexOfToastLocked(String pkg, ITransientNotification callback)
- {
- IBinder cbak = callback.asBinder();
- ArrayList<ToastRecord> list = mToastQueue;
- int len = list.size();
- for (int i=0; i<len; i++) {
- ToastRecord r = list.get(i);
- if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
- return i;
- }
- }
- return -1;
- }
-
- // lock on mToastQueue
- private void keepProcessAliveLocked(int pid)
- {
- int toastCount = 0; // toasts from this pid
- ArrayList<ToastRecord> list = mToastQueue;
- int N = list.size();
- for (int i=0; i<N; i++) {
- ToastRecord r = list.get(i);
- if (r.pid == pid) {
- toastCount++;
- }
- }
- try {
- mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
- } catch (RemoteException e) {
- // Shouldn't happen.
- }
- }
-
- private final class WorkerHandler extends Handler
- {
@Override
- public void handleMessage(Message msg)
+ public void enqueueToast(String pkg, ITransientNotification callback, int duration)
{
- switch (msg.what)
- {
- case MESSAGE_TIMEOUT:
- handleTimeout((ToastRecord)msg.obj);
- break;
+ if (DBG) {
+ Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+ + " duration=" + duration);
}
+
+ if (pkg == null || callback == null) {
+ Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
+ return ;
+ }
+
+ final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+
+ if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
+ if (!isSystemToast) {
+ Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
+ return;
+ }
+ }
+
+ synchronized (mToastQueue) {
+ int callingPid = Binder.getCallingPid();
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ ToastRecord record;
+ int index = indexOfToastLocked(pkg, callback);
+ // If it's already in the queue, we update it in place, we don't
+ // move it to the end of the queue.
+ if (index >= 0) {
+ record = mToastQueue.get(index);
+ record.update(duration);
+ } else {
+ // Limit the number of toasts that any given package except the android
+ // package can enqueue. Prevents DOS attacks and deals with leaks.
+ if (!isSystemToast) {
+ int count = 0;
+ final int N = mToastQueue.size();
+ for (int i=0; i<N; i++) {
+ final ToastRecord r = mToastQueue.get(i);
+ if (r.pkg.equals(pkg)) {
+ count++;
+ if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+ Slog.e(TAG, "Package has already posted " + count
+ + " toasts. Not showing more. Package=" + pkg);
+ return;
+ }
+ }
+ }
+ }
+
+ record = new ToastRecord(callingPid, pkg, callback, duration);
+ mToastQueue.add(record);
+ index = mToastQueue.size() - 1;
+ keepProcessAliveLocked(callingPid);
+ }
+ // If it's at index 0, it's the current toast. It doesn't matter if it's
+ // new or just been updated. Call back and tell it to show itself.
+ // If the callback fails, this will remove it from the list, so don't
+ // assume that it's valid after this.
+ if (index == 0) {
+ showNextToastLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+ }
+
+ @Override
+ public void cancelToast(String pkg, ITransientNotification callback) {
+ Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+
+ if (pkg == null || callback == null) {
+ Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
+ return ;
+ }
+
+ synchronized (mToastQueue) {
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ int index = indexOfToastLocked(pkg, callback);
+ if (index >= 0) {
+ cancelToastLocked(index);
+ } else {
+ Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
+ + " callback=" + callback);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+ }
+
+ @Override
+ public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
+ Notification notification, int[] idOut, int userId) throws RemoteException {
+ enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(),
+ Binder.getCallingPid(), tag, id, notification, idOut, userId);
+ }
+
+ @Override
+ public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
+ checkCallerIsSystemOrSameApp(pkg);
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
+ // Don't allow client applications to cancel foreground service notis.
+ cancelNotification(pkg, tag, id, 0,
+ Binder.getCallingUid() == Process.SYSTEM_UID
+ ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
+ }
+
+ @Override
+ public void cancelAllNotifications(String pkg, int userId) {
+ checkCallerIsSystemOrSameApp(pkg);
+
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
+
+ // Calling from user space, don't allow the canceling of actively
+ // running foreground services.
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
+ }
+
+ @Override
+ public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
+ checkCallerIsSystem();
+
+ setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+ }
+
+ /**
+ * Use this when you just want to know if notifications are OK for this package.
+ */
+ @Override
+ public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+ checkCallerIsSystem();
+ return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+ == AppOpsManager.MODE_ALLOWED);
+ }
+
+ /**
+ * System-only API for getting a list of current (i.e. not cleared) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
+ public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+ // enforce() will ensure the calling uid has the correct permission
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getActiveNotifications");
+
+ StatusBarNotification[] tmp = null;
+ int uid = Binder.getCallingUid();
+
+ // noteOp will check to make sure the callingPkg matches the uid
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ synchronized (mNotificationList) {
+ tmp = new StatusBarNotification[mNotificationList.size()];
+ final int N = mNotificationList.size();
+ for (int i=0; i<N; i++) {
+ tmp[i] = mNotificationList.get(i).sbn;
+ }
+ }
+ }
+ return tmp;
+ }
+
+ /**
+ * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+ *
+ * Requires ACCESS_NOTIFICATIONS which is signature|system.
+ */
+ @Override
+ public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+ // enforce() will ensure the calling uid has the correct permission
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getHistoricalNotifications");
+
+ StatusBarNotification[] tmp = null;
+ int uid = Binder.getCallingUid();
+
+ // noteOp will check to make sure the callingPkg matches the uid
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ synchronized (mArchive) {
+ tmp = mArchive.getArray(count);
+ }
+ }
+ return tmp;
+ }
+
+ /**
+ * Register a listener binder directly with the notification manager.
+ *
+ * Only works with system callers. Apps should extend
+ * {@link android.service.notification.NotificationListenerService}.
+ */
+ @Override
+ public void registerListener(final INotificationListener listener,
+ final ComponentName component, final int userid) {
+ checkCallerIsSystem();
+ registerListenerImpl(listener, component, userid);
+ }
+
+ /**
+ * Remove a listener binder directly
+ */
+ @Override
+ public void unregisterListener(INotificationListener listener, int userid) {
+ // no need to check permissions; if your listener binder is in the list,
+ // that's proof that you had permission to add it in the first place
+ unregisterListenerImpl(listener, userid);
+ }
+
+ /**
+ * Allow an INotificationListener to simulate a "clear all" operation.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void cancelAllNotificationsFromListener(INotificationListener token) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ cancelAll(info.userid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void cancelNotificationFromListener(INotificationListener token, String pkg,
+ String tag, int id) {
+ NotificationListenerInfo info = checkListenerToken(token);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ cancelNotification(pkg, tag, id, 0,
+ Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+ true,
+ info.userid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Allow an INotificationListener to request the list of outstanding notifications seen by
+ * the current user. Useful when starting up, after which point the listener callbacks
+ * should be used.
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public StatusBarNotification[] getActiveNotificationsFromListener(
+ INotificationListener token) {
+ NotificationListenerInfo info = checkListenerToken(token);
+
+ StatusBarNotification[] result = new StatusBarNotification[0];
+ ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
+ synchronized (mNotificationList) {
+ final int N = mNotificationList.size();
+ for (int i=0; i<N; i++) {
+ StatusBarNotification sbn = mNotificationList.get(i).sbn;
+ if (info.enabledAndUserMatches(sbn)) {
+ list.add(sbn);
+ }
+ }
+ }
+ return list.toArray(result);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump NotificationManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
+ }
+ };
+
+ void dumpImpl(PrintWriter pw) {
+ pw.println("Current Notification Manager state:");
+
+ pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
+ + ") enabled for current user:");
+ for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+ pw.println(" " + cmpt);
+ }
+
+ pw.println(" Live listeners (" + mListeners.size() + "):");
+ for (NotificationListenerInfo info : mListeners) {
+ pw.println(" " + info.component
+ + " (user " + info.userid + "): " + info.listener
+ + (info.isSystem?" SYSTEM":""));
+ }
+
+ int N;
+
+ synchronized (mToastQueue) {
+ N = mToastQueue.size();
+ if (N > 0) {
+ pw.println(" Toast Queue:");
+ for (int i=0; i<N; i++) {
+ mToastQueue.get(i).dump(pw, " ");
+ }
+ pw.println(" ");
+ }
+
+ }
+
+ synchronized (mNotificationList) {
+ N = mNotificationList.size();
+ if (N > 0) {
+ pw.println(" Notification List:");
+ for (int i=0; i<N; i++) {
+ mNotificationList.get(i).dump(pw, " ", getContext());
+ }
+ pw.println(" ");
+ }
+
+ N = mLights.size();
+ if (N > 0) {
+ pw.println(" Lights List:");
+ for (int i=0; i<N; i++) {
+ pw.println(" " + mLights.get(i));
+ }
+ pw.println(" ");
+ }
+
+ pw.println(" mSoundNotification=" + mSoundNotification);
+ pw.println(" mVibrateNotification=" + mVibrateNotification);
+ pw.println(" mDisabledNotifications=0x"
+ + Integer.toHexString(mDisabledNotifications));
+ pw.println(" mSystemReady=" + mSystemReady);
+ pw.println(" mArchive=" + mArchive.toString());
+ Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
+ int i=0;
+ while (iter.hasNext()) {
+ pw.println(" " + iter.next());
+ if (++i >= 5) {
+ if (iter.hasNext()) pw.println(" ...");
+ break;
+ }
+ }
+
}
}
+ /**
+ * The private API only accessible to the system process.
+ */
+ private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
+ @Override
+ public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+ String tag, int id, Notification notification, int[] idReceived, int userId) {
+ enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification,
+ idReceived, userId);
+ }
+ };
- // Notifications
- // ============================================================================
- public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
- Notification notification, int[] idOut, int userId)
- {
- enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(),
- tag, id, notification, idOut, userId);
- }
-
- private final static int clamp(int x, int low, int high) {
- return (x < low) ? low : ((x > high) ? high : x);
- }
-
- // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
- // uid/pid of another application)
-
- public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
+ void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
- int[] idOut, int incomingUserId)
- {
+ int[] idOut, int incomingUserId) {
if (DBG) {
- Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
+ Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ + " notification=" + notification);
}
checkCallerIsSystemOrSameApp(pkg);
final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
@@ -1787,23 +1794,21 @@
if (notification.icon != 0) {
if (old != null && old.statusBarKey != null) {
r.statusBarKey = old.statusBarKey;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.updateNotification(r.statusBarKey, n);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
} else {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
r.statusBarKey = mStatusBar.addNotification(n);
if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
&& canInterrupt) {
mAttentionLight.pulse();
}
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
}
@@ -1816,33 +1821,32 @@
} else {
Slog.e(TAG, "Not posting notification with icon==0: " + notification);
if (old != null && old.statusBarKey != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.removeNotification(old.statusBarKey);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
notifyRemovedLocked(r);
}
// ATTENTION: in a future release we will bail out here
- // so that we do not play sounds, show lights, etc. for invalid notifications
+ // so that we do not play sounds, show lights, etc. for invalid
+ // notifications
Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+ n.getPackageName());
}
// If we're not supposed to beep, vibrate, etc. then don't.
- if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+ if (((mDisabledNotifications
+ & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (r.getUserId() == UserHandle.USER_ALL ||
(r.getUserId() == userId && r.getUserId() == currentUser))
&& canInterrupt
- && mSystemReady) {
-
- final AudioManager audioManager = (AudioManager) mContext
- .getSystemService(Context.AUDIO_SERVICE);
+ && mSystemReady
+ && mAudioManager != null) {
// sound
@@ -1861,7 +1865,7 @@
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
// check to see if the default notification sound is silent
- ContentResolver resolver = mContext.getContentResolver();
+ ContentResolver resolver = getContext().getContentResolver();
hasValidSound = Settings.System.getString(resolver,
Settings.System.NOTIFICATION_SOUND) != null;
} else if (notification.sound != null) {
@@ -1870,7 +1874,8 @@
}
if (hasValidSound) {
- boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
+ boolean looping =
+ (notification.flags & Notification.FLAG_INSISTENT) != 0;
int audioStreamType;
if (notification.audioStreamType >= 0) {
audioStreamType = notification.audioStreamType;
@@ -1880,11 +1885,12 @@
mSoundNotification = r;
// do not play notifications if stream volume is 0 (typically because
// ringer mode is silent) or if there is a user of exclusive audio focus
- if ((audioManager.getStreamVolume(audioStreamType) != 0)
- && !audioManager.isAudioFocusExclusive()) {
+ if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
+ && !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player =
+ mAudioManager.getRingtonePlayer();
if (player != null) {
player.playAsync(soundUri, user, looping, audioStreamType);
}
@@ -1904,7 +1910,7 @@
final boolean convertSoundToVibration =
!hasCustomVibrate
&& hasValidSound
- && (audioManager.getRingerMode()
+ && (mAudioManager.getRingerMode()
== AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
@@ -1912,7 +1918,7 @@
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
- && !(audioManager.getRingerMode()
+ && !(mAudioManager.getRingerMode()
== AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = r;
@@ -1966,8 +1972,158 @@
idOut[0] = id;
}
- private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
- AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+ void registerListenerImpl(final INotificationListener listener,
+ final ComponentName component, final int userid) {
+ synchronized (mNotificationList) {
+ try {
+ NotificationListenerInfo info
+ = new NotificationListenerInfo(listener, component, userid, true);
+ listener.asBinder().linkToDeath(info, 0);
+ mListeners.add(info);
+ } catch (RemoteException e) {
+ // already dead
+ }
+ }
+ }
+
+ void unregisterListenerImpl(final INotificationListener listener, final int userid) {
+ synchronized (mNotificationList) {
+ final int N = mListeners.size();
+ for (int i=N-1; i>=0; i--) {
+ final NotificationListenerInfo info = mListeners.get(i);
+ if (info.listener.asBinder() == listener.asBinder()
+ && info.userid == userid) {
+ mListeners.remove(i);
+ if (info.connection != null) {
+ getContext().unbindService(info.connection);
+ }
+ }
+ }
+ }
+ }
+
+ void showNextToastLocked() {
+ ToastRecord record = mToastQueue.get(0);
+ while (record != null) {
+ if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+ try {
+ record.callback.show();
+ scheduleTimeoutLocked(record);
+ return;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Object died trying to show notification " + record.callback
+ + " in package " + record.pkg);
+ // remove it from the list and let the process die
+ int index = mToastQueue.indexOf(record);
+ if (index >= 0) {
+ mToastQueue.remove(index);
+ }
+ keepProcessAliveLocked(record.pid);
+ if (mToastQueue.size() > 0) {
+ record = mToastQueue.get(0);
+ } else {
+ record = null;
+ }
+ }
+ }
+ }
+
+ void cancelToastLocked(int index) {
+ ToastRecord record = mToastQueue.get(index);
+ try {
+ record.callback.hide();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Object died trying to hide notification " + record.callback
+ + " in package " + record.pkg);
+ // don't worry about this, we're about to remove it from
+ // the list anyway
+ }
+ mToastQueue.remove(index);
+ keepProcessAliveLocked(record.pid);
+ if (mToastQueue.size() > 0) {
+ // Show the next one. If the callback fails, this will remove
+ // it from the list, so don't assume that the list hasn't changed
+ // after this point.
+ showNextToastLocked();
+ }
+ }
+
+ private void scheduleTimeoutLocked(ToastRecord r)
+ {
+ mHandler.removeCallbacksAndMessages(r);
+ Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
+ long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+ mHandler.sendMessageDelayed(m, delay);
+ }
+
+ private void handleTimeout(ToastRecord record)
+ {
+ if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
+ synchronized (mToastQueue) {
+ int index = indexOfToastLocked(record.pkg, record.callback);
+ if (index >= 0) {
+ cancelToastLocked(index);
+ }
+ }
+ }
+
+ // lock on mToastQueue
+ int indexOfToastLocked(String pkg, ITransientNotification callback)
+ {
+ IBinder cbak = callback.asBinder();
+ ArrayList<ToastRecord> list = mToastQueue;
+ int len = list.size();
+ for (int i=0; i<len; i++) {
+ ToastRecord r = list.get(i);
+ if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ // lock on mToastQueue
+ void keepProcessAliveLocked(int pid)
+ {
+ int toastCount = 0; // toasts from this pid
+ ArrayList<ToastRecord> list = mToastQueue;
+ int N = list.size();
+ for (int i=0; i<N; i++) {
+ ToastRecord r = list.get(i);
+ if (r.pid == pid) {
+ toastCount++;
+ }
+ }
+ try {
+ mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ }
+
+ private final class WorkerHandler extends Handler
+ {
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch (msg.what)
+ {
+ case MESSAGE_TIMEOUT:
+ handleTimeout((ToastRecord)msg.obj);
+ break;
+ }
+ }
+ }
+
+
+ // Notifications
+ // ============================================================================
+ static int clamp(int x, int low, int high) {
+ return (x < low) ? low : ((x > high) ? high : x);
+ }
+
+ void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
if (!manager.isEnabled()) {
return;
}
@@ -2001,11 +2157,10 @@
// status bar
if (r.getNotification().icon != 0) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mStatusBar.removeNotification(r.statusBarKey);
- }
- finally {
+ } finally {
Binder.restoreCallingIdentity(identity);
}
r.statusBarKey = null;
@@ -2017,7 +2172,7 @@
mSoundNotification = null;
final long identity = Binder.clearCallingIdentity();
try {
- final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+ final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.stopAsync();
}
@@ -2053,7 +2208,7 @@
* Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
* and none of the {@code mustNotHaveFlags}.
*/
- private void cancelNotification(final String pkg, final String tag, final int id,
+ void cancelNotification(final String pkg, final String tag, final int id,
final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
final int userId) {
// In enqueueNotificationInternal notifications are added by scheduling the
@@ -2146,26 +2301,7 @@
}
}
- public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
- checkCallerIsSystemOrSameApp(pkg);
- userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
- // Don't allow client applications to cancel foreground service notis.
- cancelNotification(pkg, tag, id, 0,
- Binder.getCallingUid() == Process.SYSTEM_UID
- ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
- }
- public void cancelAllNotifications(String pkg, int userId) {
- checkCallerIsSystemOrSameApp(pkg);
-
- userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
-
- // Calling from user space, don't allow the canceling of actively
- // running foreground services.
- cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
- }
// Return true if the UID is a system or phone UID and therefore should not have
// any notifications or toasts blocked.
@@ -2225,7 +2361,7 @@
}
// lock on mNotificationList
- private void updateLightsLocked()
+ void updateLightsLocked()
{
// handle notification lights
if (mLedNotification == null) {
@@ -2251,14 +2387,14 @@
}
if (mNotificationPulseEnabled) {
// pulse repeatedly
- mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+ mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
ledOnMS, ledOffMS);
}
}
}
// lock on mNotificationList
- private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
+ int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{
ArrayList<NotificationRecord> list = mNotificationList;
final int len = list.size();
@@ -2288,81 +2424,4 @@
updateLightsLocked();
}
}
-
- // ======================================================================
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump NotificationManager from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- pw.println("Current Notification Manager state:");
-
- pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
- + ") enabled for current user:");
- for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
- pw.println(" " + cmpt);
- }
-
- pw.println(" Live listeners (" + mListeners.size() + "):");
- for (NotificationListenerInfo info : mListeners) {
- pw.println(" " + info.component
- + " (user " + info.userid + "): " + info.listener
- + (info.isSystem?" SYSTEM":""));
- }
-
- int N;
-
- synchronized (mToastQueue) {
- N = mToastQueue.size();
- if (N > 0) {
- pw.println(" Toast Queue:");
- for (int i=0; i<N; i++) {
- mToastQueue.get(i).dump(pw, " ");
- }
- pw.println(" ");
- }
-
- }
-
- synchronized (mNotificationList) {
- N = mNotificationList.size();
- if (N > 0) {
- pw.println(" Notification List:");
- for (int i=0; i<N; i++) {
- mNotificationList.get(i).dump(pw, " ", mContext);
- }
- pw.println(" ");
- }
-
- N = mLights.size();
- if (N > 0) {
- pw.println(" Lights List:");
- for (int i=0; i<N; i++) {
- pw.println(" " + mLights.get(i));
- }
- pw.println(" ");
- }
-
- pw.println(" mSoundNotification=" + mSoundNotification);
- pw.println(" mVibrateNotification=" + mVibrateNotification);
- pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
- pw.println(" mSystemReady=" + mSystemReady);
- pw.println(" mArchive=" + mArchive.toString());
- Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
- int i=0;
- while (iter.hasNext()) {
- pw.println(" " + iter.next());
- if (++i >= 5) {
- if (iter.hasNext()) pw.println(" ...");
- break;
- }
- }
-
- }
- }
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5761f6c..b11ebf5 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -38,10 +38,10 @@
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
-import com.android.server.DeviceStorageMonitorService;
import com.android.server.EventLogTags;
import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
import com.android.server.Watchdog;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -92,6 +92,7 @@
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VerifierInfo;
import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -127,7 +128,6 @@
import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
-import android.view.WindowManager;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -162,6 +162,7 @@
import libcore.io.StructStat;
import com.android.internal.R;
+import com.android.server.storage.DeviceStorageMonitorInternal;
/**
* Keep track of all those .apks everywhere.
@@ -1067,6 +1068,12 @@
return res;
}
+ private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
+ DisplayManager displayManager = (DisplayManager) context.getSystemService(
+ Context.DISPLAY_SERVICE);
+ displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
+ }
+
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1114,9 +1121,7 @@
mInstaller = installer;
- WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- Display d = wm.getDefaultDisplay();
- d.getMetrics(mMetrics);
+ getDefaultDisplayMetrics(context, mMetrics);
synchronized (mInstallLock) {
// writer
@@ -7339,6 +7344,15 @@
return pkgLite.recommendedInstallLocation;
}
+ private long getMemoryLowThreshold() {
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (dsm == null) {
+ return 0L;
+ }
+ return dsm.getMemoryLowThreshold();
+ }
+
/*
* Invoke remote method to get package information and install
* location values. Override install location based on default
@@ -7356,15 +7370,9 @@
Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else {
- final long lowThreshold;
-
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
- if (dsm == null) {
+ final long lowThreshold = getMemoryLowThreshold();
+ if (lowThreshold == 0L) {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
- lowThreshold = 0L;
- } else {
- lowThreshold = dsm.getMemoryLowThreshold();
}
try {
@@ -7922,8 +7930,8 @@
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
final long lowThreshold;
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
if (dsm == null) {
Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
lowThreshold = 0L;
@@ -9738,10 +9746,10 @@
clearExternalStorageDataSync(packageName, userId, true);
if (succeeded) {
// invoke DeviceStorageMonitor's update method to clear any notifications
- DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
- ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
+ DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
if (dsm != null) {
- dsm.updateMemory();
+ dsm.checkMemory();
}
}
if(observer != null) {
@@ -11566,12 +11574,17 @@
return true;
}
+ @Override
public boolean isStorageLow() {
final long token = Binder.clearCallingIdentity();
try {
- final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
- .getService(DeviceStorageMonitorService.SERVICE);
- return dsm.isMemoryLow();
+ final DeviceStorageMonitorInternal
+ dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+ if (dsm != null) {
+ return dsm.isMemoryLow();
+ } else {
+ return false;
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index f93ba2f..8916926 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -17,7 +17,6 @@
package com.android.server.pm;
import com.android.internal.util.XmlUtils;
-import com.android.server.PreferredComponent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/java/com/android/server/pm/PreferredComponent.java
similarity index 99%
rename from services/java/com/android/server/PreferredComponent.java
rename to services/java/com/android/server/pm/PreferredComponent.java
index a7af252..f437372 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/java/com/android/server/pm/PreferredComponent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.pm;
import com.android.internal.util.XmlUtils;
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 60d44c7..b8a78e3 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -16,10 +16,11 @@
package com.android.server.power;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.lights.LightsManager;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
import com.android.server.display.DisplayManagerService;
+import com.android.server.twilight.TwilightState;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -179,10 +180,10 @@
private Handler mCallbackHandler;
// The lights service.
- private final LightsService mLights;
+ private final LightsManager mLights;
// The twilight service.
- private final TwilightService mTwilight;
+ private final TwilightManager mTwilight;
// The display manager.
private final DisplayManagerService mDisplayManager;
@@ -351,7 +352,7 @@
* Creates the display power controller.
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
- LightsService lights, TwilightService twilight, SensorManager sensorManager,
+ LightsManager lights, TwilightManager twilight, SensorManager sensorManager,
DisplayManagerService displayManager,
SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
@@ -528,7 +529,7 @@
private void initialize() {
mPowerState = new DisplayPowerState(
new ElectronBeam(mDisplayManager), mDisplayBlanker,
- mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
+ mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT));
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -1368,8 +1369,7 @@
}
};
- private final TwilightService.TwilightListener mTwilightListener =
- new TwilightService.TwilightListener() {
+ private final TwilightListener mTwilightListener = new TwilightListener() {
@Override
public void onTwilightStateChanged() {
mTwilightChanged = true;
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index fa318f8b..42af4b4 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -16,7 +16,7 @@
package com.android.server.power;
-import com.android.server.LightsService;
+import com.android.server.lights.Light;
import android.os.AsyncTask;
import android.os.Handler;
@@ -56,7 +56,7 @@
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
private final DisplayBlanker mDisplayBlanker;
- private final LightsService.Light mBacklight;
+ private final Light mBacklight;
private final PhotonicModulator mPhotonicModulator;
private boolean mScreenOn;
@@ -72,7 +72,7 @@
private Runnable mCleanListener;
public DisplayPowerState(ElectronBeam electronBean,
- DisplayBlanker displayBlanker, LightsService.Light backlight) {
+ DisplayBlanker displayBlanker, Light backlight) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mElectronBeam = electronBean;
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index da9548f..13f55e2 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -20,10 +20,11 @@
import com.android.internal.app.IBatteryStats;
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
+import com.android.server.lights.LightsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+import com.android.server.twilight.TwilightManager;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
@@ -168,7 +169,7 @@
private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
private Context mContext;
- private LightsService mLightsService;
+ private LightsManager mLightsManager;
private BatteryService mBatteryService;
private DisplayManagerService mDisplayManagerService;
private IBatteryStats mBatteryStats;
@@ -181,7 +182,7 @@
private WirelessChargerDetector mWirelessChargerDetector;
private SettingsObserver mSettingsObserver;
private DreamManagerService mDreamManager;
- private LightsService.Light mAttentionLight;
+ private Light mAttentionLight;
private final Object mLock = new Object();
@@ -396,11 +397,11 @@
* Initialize the power manager.
* Must be called before any other functions within the power manager are called.
*/
- public void init(Context context, LightsService ls,
- ActivityManagerService am, BatteryService bs, IBatteryStats bss,
+ public void init(Context context, LightsManager ls,
+ BatteryService bs, IBatteryStats bss,
IAppOpsService appOps, DisplayManagerService dm) {
mContext = context;
- mLightsService = ls;
+ mLightsManager = ls;
mBatteryService = bs;
mBatteryStats = bss;
mAppOps = appOps;
@@ -427,12 +428,12 @@
}
}
- public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
+ public void systemReady(TwilightManager twilight, DreamManagerService dreamManager) {
synchronized (mLock) {
mSystemReady = true;
mDreamManager = dreamManager;
- PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
@@ -448,7 +449,7 @@
// The display power controller runs on the power manager service's
// own handler thread to ensure timely operation.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
- mContext, mNotifier, mLightsService, twilight, sensorManager,
+ mContext, mNotifier, mLightsManager, twilight, sensorManager,
mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
mDisplayPowerControllerCallbacks, mHandler);
@@ -456,7 +457,7 @@
createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
- mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
+ mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
// Register for broadcasts from other components of the system.
IntentFilter filter = new IntentFilter();
@@ -2061,7 +2062,7 @@
}
private void setAttentionLightInternal(boolean on, int color) {
- LightsService.Light light;
+ Light light;
synchronized (mLock) {
if (!mSystemReady) {
return;
@@ -2070,7 +2071,7 @@
}
// Control light outside of lock.
- light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+ light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
}
/**
diff --git a/services/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/java/com/android/server/statusbar/StatusBarManagerInternal.java
new file mode 100644
index 0000000..4f75189
--- /dev/null
+++ b/services/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.statusbar;
+
+import com.android.server.notification.NotificationDelegate;
+
+import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
+
+public interface StatusBarManagerInternal {
+ void setNotificationDelegate(NotificationDelegate delegate);
+ IBinder addNotification(StatusBarNotification notification);
+ void updateNotification(IBinder key, StatusBarNotification notification);
+ void removeNotification(IBinder key);
+}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/statusbar/StatusBarManagerService.java
similarity index 80%
rename from services/java/com/android/server/StatusBarManagerService.java
rename to services/java/com/android/server/statusbar/StatusBarManagerService.java
index f207c08..2ae467e 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -14,26 +14,28 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.statusbar;
import android.app.StatusBarManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationDelegate;
import com.android.server.wm.WindowManagerService;
import java.io.FileDescriptor;
@@ -51,31 +53,31 @@
public class StatusBarManagerService extends IStatusBarService.Stub
implements WindowManagerService.OnHardKeyboardStatusChangeListener
{
- static final String TAG = "StatusBarManagerService";
- static final boolean SPEW = false;
+ private static final String TAG = "StatusBarManagerService";
+ private static final boolean SPEW = false;
- final Context mContext;
- final WindowManagerService mWindowManager;
- Handler mHandler = new Handler();
- NotificationCallbacks mNotificationCallbacks;
- volatile IStatusBar mBar;
- StatusBarIconList mIcons = new StatusBarIconList();
- HashMap<IBinder,StatusBarNotification> mNotifications
+ private final Context mContext;
+ private final WindowManagerService mWindowManager;
+ private Handler mHandler = new Handler();
+ private NotificationDelegate mNotificationDelegate;
+ private volatile IStatusBar mBar;
+ private StatusBarIconList mIcons = new StatusBarIconList();
+ private HashMap<IBinder,StatusBarNotification> mNotifications
= new HashMap<IBinder,StatusBarNotification>();
// for disabling the status bar
- final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
- IBinder mSysUiVisToken = new Binder();
- int mDisabled = 0;
+ private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+ private IBinder mSysUiVisToken = new Binder();
+ private int mDisabled = 0;
- Object mLock = new Object();
+ private Object mLock = new Object();
// encompasses lights-out mode and other flags defined on View
- int mSystemUiVisibility = 0;
- boolean mMenuVisible = false;
- int mImeWindowVis = 0;
- int mImeBackDisposition;
- IBinder mImeToken = null;
- int mCurrentUserId;
+ private int mSystemUiVisibility = 0;
+ private boolean mMenuVisible = false;
+ private int mImeWindowVis = 0;
+ private int mImeBackDisposition;
+ private IBinder mImeToken = null;
+ private int mCurrentUserId;
private class DisableRecord implements IBinder.DeathRecipient {
int userId;
@@ -90,16 +92,6 @@
}
}
- public interface NotificationCallbacks {
- void onSetDisabled(int status);
- void onClearAll();
- void onNotificationClick(String pkg, String tag, int id);
- void onNotificationClear(String pkg, String tag, int id);
- void onPanelRevealed();
- void onNotificationError(String pkg, String tag, int id,
- int uid, int initialPid, String message);
- }
-
/**
* Construct the service, add the status bar view to the window manager
*/
@@ -110,15 +102,74 @@
final Resources res = context.getResources();
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
+
+ LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
}
- public void setNotificationCallbacks(NotificationCallbacks listener) {
- mNotificationCallbacks = listener;
- }
+ /**
+ * Private API used by NotificationManagerService.
+ */
+ private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
+ @Override
+ public void setNotificationDelegate(NotificationDelegate delegate) {
+ synchronized (mNotifications) {
+ mNotificationDelegate = delegate;
+ }
+ }
+
+ @Override
+ public IBinder addNotification(StatusBarNotification notification) {
+ synchronized (mNotifications) {
+ IBinder key = new Binder();
+ mNotifications.put(key, notification);
+ if (mBar != null) {
+ try {
+ mBar.addNotification(key, notification);
+ } catch (RemoteException ex) {
+ }
+ }
+ return key;
+ }
+ }
+
+ @Override
+ public void updateNotification(IBinder key, StatusBarNotification notification) {
+ synchronized (mNotifications) {
+ if (!mNotifications.containsKey(key)) {
+ throw new IllegalArgumentException("updateNotification key not found: " + key);
+ }
+ mNotifications.put(key, notification);
+ if (mBar != null) {
+ try {
+ mBar.updateNotification(key, notification);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void removeNotification(IBinder key) {
+ synchronized (mNotifications) {
+ final StatusBarNotification n = mNotifications.remove(key);
+ if (n == null) {
+ Slog.e(TAG, "removeNotification key not found: " + key);
+ return;
+ }
+ if (mBar != null) {
+ try {
+ mBar.removeNotification(key);
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+ };
// ================================================================================
// From IStatusBarService
// ================================================================================
+ @Override
public void expandNotificationsPanel() {
enforceExpandStatusBar();
@@ -130,6 +181,7 @@
}
}
+ @Override
public void collapsePanels() {
enforceExpandStatusBar();
@@ -141,6 +193,7 @@
}
}
+ @Override
public void expandSettingsPanel() {
enforceExpandStatusBar();
@@ -152,6 +205,7 @@
}
}
+ @Override
public void disable(int what, IBinder token, String pkg) {
disableInternal(mCurrentUserId, what, token, pkg);
}
@@ -177,7 +231,7 @@
mDisabled = net;
mHandler.post(new Runnable() {
public void run() {
- mNotificationCallbacks.onSetDisabled(net);
+ mNotificationDelegate.onSetDisabled(net);
}
});
if (mBar != null) {
@@ -189,6 +243,7 @@
}
}
+ @Override
public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
String contentDescription) {
enforceStatusBar();
@@ -214,6 +269,7 @@
}
}
+ @Override
public void setIconVisibility(String slot, boolean visible) {
enforceStatusBar();
@@ -241,6 +297,7 @@
}
}
+ @Override
public void removeIcon(String slot) {
enforceStatusBar();
@@ -265,6 +322,7 @@
* Hide or show the on-screen Menu key. Only call this from the window manager, typically in
* response to a window with FLAG_NEEDS_MENU_KEY set.
*/
+ @Override
public void topAppWindowChanged(final boolean menuVisible) {
enforceStatusBar();
@@ -285,6 +343,7 @@
}
}
+ @Override
public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
enforceStatusBar();
@@ -312,6 +371,7 @@
}
}
+ @Override
public void setSystemUiVisibility(int vis, int mask) {
// also allows calls from window manager which is in this process.
enforceStatusBarService();
@@ -344,6 +404,7 @@
}
}
+ @Override
public void setHardKeyboardEnabled(final boolean enabled) {
mHandler.post(new Runnable() {
public void run() {
@@ -426,6 +487,7 @@
// ================================================================================
// Callbacks from the status bar service.
// ================================================================================
+ @Override
public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
int switches[], List<IBinder> binders) {
@@ -458,86 +520,64 @@
* The status bar service should call this each time the user brings the panel from
* invisible to visible in order to clear the notification light.
*/
+ @Override
public void onPanelRevealed() {
enforceStatusBarService();
-
- // tell the notification manager to turn off the lights.
- mNotificationCallbacks.onPanelRevealed();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // tell the notification manager to turn off the lights.
+ mNotificationDelegate.onPanelRevealed();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationClick(String pkg, String tag, int id) {
enforceStatusBarService();
-
- mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationClick(pkg, tag, id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message) {
enforceStatusBarService();
-
- // WARNING: this will call back into us to do the remove. Don't hold any locks.
- mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // WARNING: this will call back into us to do the remove. Don't hold any locks.
+ mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onNotificationClear(String pkg, String tag, int id) {
enforceStatusBarService();
-
- mNotificationCallbacks.onNotificationClear(pkg, tag, id);
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationClear(pkg, tag, id);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
+ @Override
public void onClearAllNotifications() {
enforceStatusBarService();
-
- mNotificationCallbacks.onClearAll();
- }
-
- // ================================================================================
- // Callbacks for NotificationManagerService.
- // ================================================================================
- public IBinder addNotification(StatusBarNotification notification) {
- synchronized (mNotifications) {
- IBinder key = new Binder();
- mNotifications.put(key, notification);
- if (mBar != null) {
- try {
- mBar.addNotification(key, notification);
- } catch (RemoteException ex) {
- }
- }
- return key;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onClearAll();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
- public void updateNotification(IBinder key, StatusBarNotification notification) {
- synchronized (mNotifications) {
- if (!mNotifications.containsKey(key)) {
- throw new IllegalArgumentException("updateNotification key not found: " + key);
- }
- mNotifications.put(key, notification);
- if (mBar != null) {
- try {
- mBar.updateNotification(key, notification);
- } catch (RemoteException ex) {
- }
- }
- }
- }
-
- public void removeNotification(IBinder key) {
- synchronized (mNotifications) {
- final StatusBarNotification n = mNotifications.remove(key);
- if (n == null) {
- Slog.e(TAG, "removeNotification key not found: " + key);
- return;
- }
- if (mBar != null) {
- try {
- mBar.removeNotification(key);
- } catch (RemoteException ex) {
- }
- }
- }
- }
// ================================================================================
// Can be called from any thread
diff --git a/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java b/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java
new file mode 100644
index 0000000..a91a81b
--- /dev/null
+++ b/services/java/com/android/server/storage/DeviceStorageMonitorInternal.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.storage;
+
+public interface DeviceStorageMonitorInternal {
+ boolean isMemoryLow();
+ long getMemoryLowThreshold();
+ void checkMemory();
+}
+
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/storage/DeviceStorageMonitorService.java
similarity index 79%
rename from services/java/com/android/server/DeviceStorageMonitorService.java
rename to services/java/com/android/server/storage/DeviceStorageMonitorService.java
index 016c561..8805084 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.storage;
+
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
import android.app.Notification;
import android.app.NotificationManager;
@@ -29,8 +32,8 @@
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
@@ -66,13 +69,13 @@
* settings parameter with a default value of 2MB), the free memory is
* logged to the event log.
*/
-public class DeviceStorageMonitorService extends Binder {
- private static final String TAG = "DeviceStorageMonitorService";
+public class DeviceStorageMonitorService extends SystemService {
+ static final String TAG = "DeviceStorageMonitorService";
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = false;
+ static final boolean DEBUG = false;
+ static final boolean localLOGV = false;
- private static final int DEVICE_MEMORY_WHAT = 1;
+ static final int DEVICE_MEMORY_WHAT = 1;
private static final int MONITOR_INTERVAL = 1; //in minutes
private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
@@ -84,9 +87,8 @@
private long mFreeMemAfterLastCacheClear; // on /data
private long mLastReportedFreeMem;
private long mLastReportedFreeMemTime;
- private boolean mLowMemFlag=false;
+ boolean mLowMemFlag=false;
private boolean mMemFullFlag=false;
- private Context mContext;
private ContentResolver mResolver;
private long mTotalMemory; // on /data
private StatFs mDataFileStats;
@@ -98,19 +100,19 @@
private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
private long mThreadStartTime = -1;
- private boolean mClearSucceeded = false;
- private boolean mClearingCache;
+ boolean mClearSucceeded = false;
+ boolean mClearingCache;
private Intent mStorageLowIntent;
private Intent mStorageOkIntent;
private Intent mStorageFullIntent;
private Intent mStorageNotFullIntent;
private CachePackageDataObserver mClearCacheObserver;
- private final CacheFileDeletedObserver mCacheFileDeletedObserver;
+ private CacheFileDeletedObserver mCacheFileDeletedObserver;
private static final int _TRUE = 1;
private static final int _FALSE = 0;
// This is the raw threshold that has been set at which we consider
// storage to be low.
- private long mMemLowThreshold;
+ long mMemLowThreshold;
// This is the threshold at which we start trying to flush caches
// to get below the low threshold limit. It is less than the low
// threshold; we will allow storage to get a bit beyond the limit
@@ -126,13 +128,13 @@
/**
* This string is used for ServiceManager access to this class.
*/
- public static final String SERVICE = "devicestoragemonitor";
+ static final String SERVICE = "devicestoragemonitor";
/**
* Handler that checks the amount of disk space on the device and sends a
* notification if the device runs low on disk space
*/
- Handler mHandler = new Handler() {
+ private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//don't handle an invalid message
@@ -144,7 +146,7 @@
}
};
- class CachePackageDataObserver extends IPackageDataObserver.Stub {
+ private class CachePackageDataObserver extends IPackageDataObserver.Stub {
public void onRemoveCompleted(String packageName, boolean succeeded) {
mClearSucceeded = succeeded;
mClearingCache = false;
@@ -154,7 +156,7 @@
}
}
- private final void restatDataDir() {
+ private void restatDataDir() {
try {
mDataFileStats.restat(DATA_PATH.getAbsolutePath());
mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
@@ -206,7 +208,7 @@
}
}
- private final void clearCache() {
+ private void clearCache() {
if (mClearCacheObserver == null) {
// Lazy instantiation
mClearCacheObserver = new CachePackageDataObserver();
@@ -223,7 +225,7 @@
}
}
- private final void checkMemory(boolean checkCache) {
+ void checkMemory(boolean checkCache) {
//if the thread that was started to clear cache is still running do nothing till its
//finished clearing cache. Ideally this flag could be modified by clearCache
// and should be accessed via a lock but even if it does this test will fail now and
@@ -300,7 +302,7 @@
postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
}
- private void postCheckMemoryMsg(boolean clearCache, long delay) {
+ void postCheckMemoryMsg(boolean clearCache, long delay) {
// Remove queued messages
mHandler.removeMessages(DEVICE_MEMORY_WHAT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
@@ -312,10 +314,10 @@
* Constructor to run service. initializes the disk space threshold value
* and posts an empty message to kickstart the process.
*/
- public DeviceStorageMonitorService(Context context) {
+ @Override
+ public void onCreate(Context context) {
mLastReportedFreeMemTime = 0;
- mContext = context;
- mResolver = mContext.getContentResolver();
+ mResolver = context.getContentResolver();
//create StatFs object
mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
@@ -331,9 +333,12 @@
mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ }
+ @Override
+ public void onStart() {
// cache storage thresholds
- final StorageManager sm = StorageManager.from(context);
+ final StorageManager sm = StorageManager.from(getContext());
mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
@@ -345,6 +350,78 @@
mCacheFileDeletedObserver = new CacheFileDeletedObserver();
mCacheFileDeletedObserver.startWatching();
+
+ publishBinderService(SERVICE, mRemoteService);
+ publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
+ }
+
+ private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
+ @Override
+ public void checkMemory() {
+ // force an early check
+ postCheckMemoryMsg(true, 0);
+ }
+
+ @Override
+ public boolean isMemoryLow() {
+ return mLowMemFlag;
+ }
+
+ @Override
+ public long getMemoryLowThreshold() {
+ return mMemLowThreshold;
+ }
+ };
+
+ private final IBinder mRemoteService = new Binder() {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+
+ pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ dumpImpl(pw);
+ }
+ };
+
+ void dumpImpl(PrintWriter pw) {
+ final Context context = getContext();
+
+ pw.println("Current DeviceStorageMonitor state:");
+
+ pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(context, mFreeMem));
+ pw.print(" mTotalMemory=");
+ pw.println(Formatter.formatFileSize(context, mTotalMemory));
+
+ pw.print(" mFreeMemAfterLastCacheClear=");
+ pw.println(Formatter.formatFileSize(context, mFreeMemAfterLastCacheClear));
+
+ pw.print(" mLastReportedFreeMem=");
+ pw.print(Formatter.formatFileSize(context, mLastReportedFreeMem));
+ pw.print(" mLastReportedFreeMemTime=");
+ TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
+ pw.println();
+
+ pw.print(" mLowMemFlag="); pw.print(mLowMemFlag);
+ pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
+
+ pw.print(" mClearSucceeded="); pw.print(mClearSucceeded);
+ pw.print(" mClearingCache="); pw.println(mClearingCache);
+
+ pw.print(" mMemLowThreshold=");
+ pw.print(Formatter.formatFileSize(context, mMemLowThreshold));
+ pw.print(" mMemFullThreshold=");
+ pw.println(Formatter.formatFileSize(context, mMemFullThreshold));
+
+ pw.print(" mMemCacheStartTrimThreshold=");
+ pw.print(Formatter.formatFileSize(context, mMemCacheStartTrimThreshold));
+ pw.print(" mMemCacheTrimToThreshold=");
+ pw.println(Formatter.formatFileSize(context, mMemCacheTrimToThreshold));
}
/**
@@ -352,7 +429,8 @@
* an error dialog indicating low disk space and launch the Installer
* application
*/
- private final void sendNotification() {
+ private void sendNotification() {
+ final Context context = getContext();
if(localLOGV) Slog.i(TAG, "Sending low memory notification");
//log the event to event log with the amount of free storage(in bytes) left on the device
EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
@@ -363,86 +441,58 @@
lowMemIntent.putExtra("memory", mFreeMem);
lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager mNotificationMgr =
- (NotificationManager)mContext.getSystemService(
+ (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
- CharSequence title = mContext.getText(
+ CharSequence title = context.getText(
com.android.internal.R.string.low_internal_storage_view_title);
- CharSequence details = mContext.getText(
+ CharSequence details = context.getText(
com.android.internal.R.string.low_internal_storage_view_text);
- PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0, lowMemIntent, 0,
+ PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
Notification notification = new Notification();
notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
notification.tickerText = title;
notification.flags |= Notification.FLAG_NO_CLEAR;
- notification.setLatestEventInfo(mContext, title, details, intent);
+ notification.setLatestEventInfo(context, title, details, intent);
mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
- mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+ context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
}
/**
* Cancels low storage notification and sends OK intent.
*/
- private final void cancelNotification() {
+ private void cancelNotification() {
+ final Context context = getContext();
if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
NotificationManager mNotificationMgr =
- (NotificationManager)mContext.getSystemService(
+ (NotificationManager)context.getSystemService(
Context.NOTIFICATION_SERVICE);
//cancel notification since memory has been freed
mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL);
- mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
- mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
+ context.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+ context.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
}
/**
* Send a notification when storage is full.
*/
- private final void sendFullNotification() {
+ private void sendFullNotification() {
if(localLOGV) Slog.i(TAG, "Sending memory full notification");
- mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+ getContext().sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
}
/**
* Cancels memory full notification and sends "not full" intent.
*/
- private final void cancelFullNotification() {
+ private void cancelFullNotification() {
if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
- mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
- mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
+ getContext().removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+ getContext().sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
}
- public void updateMemory() {
- int callingUid = getCallingUid();
- if(callingUid != Process.SYSTEM_UID) {
- return;
- }
- // force an early check
- postCheckMemoryMsg(true, 0);
- }
-
- /**
- * Callable from other things in the system service to obtain the low memory
- * threshold.
- *
- * @return low memory threshold in bytes
- */
- public long getMemoryLowThreshold() {
- return mMemLowThreshold;
- }
-
- /**
- * Callable from other things in the system process to check whether memory
- * is low.
- *
- * @return true is memory is low
- */
- public boolean isMemoryLow() {
- return mLowMemFlag;
- }
-
- public static class CacheFileDeletedObserver extends FileObserver {
+ private static class CacheFileDeletedObserver extends FileObserver {
public CacheFileDeletedObserver() {
super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
}
@@ -452,40 +502,4 @@
EventLogTags.writeCacheFileDeleted(path);
}
}
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
-
- pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
-
- pw.println("Current DeviceStorageMonitor state:");
- pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem));
- pw.print(" mTotalMemory=");
- pw.println(Formatter.formatFileSize(mContext, mTotalMemory));
- pw.print(" mFreeMemAfterLastCacheClear=");
- pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear));
- pw.print(" mLastReportedFreeMem=");
- pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem));
- pw.print(" mLastReportedFreeMemTime=");
- TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
- pw.println();
- pw.print(" mLowMemFlag="); pw.print(mLowMemFlag);
- pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
- pw.print(" mClearSucceeded="); pw.print(mClearSucceeded);
- pw.print(" mClearingCache="); pw.println(mClearingCache);
- pw.print(" mMemLowThreshold=");
- pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold));
- pw.print(" mMemFullThreshold=");
- pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold));
- pw.print(" mMemCacheStartTrimThreshold=");
- pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold));
- pw.print(" mMemCacheTrimToThreshold=");
- pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold));
- }
}
diff --git a/services/java/com/android/server/twilight/TwilightListener.java b/services/java/com/android/server/twilight/TwilightListener.java
new file mode 100644
index 0000000..29ead44
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightListener.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.twilight;
+
+public interface TwilightListener {
+ void onTwilightStateChanged();
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/twilight/TwilightManager.java b/services/java/com/android/server/twilight/TwilightManager.java
new file mode 100644
index 0000000..b3de58b
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightManager.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.twilight;
+
+import android.os.Handler;
+
+public interface TwilightManager {
+ void registerListener(TwilightListener listener, Handler handler);
+ TwilightState getCurrentState();
+}
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/twilight/TwilightService.java
similarity index 74%
rename from services/java/com/android/server/TwilightService.java
rename to services/java/com/android/server/twilight/TwilightService.java
index 0356faa..8feb97b 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/java/com/android/server/twilight/TwilightService.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.twilight;
+
+import com.android.server.SystemService;
+import com.android.server.TwilightCalculator;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -34,9 +37,7 @@
import android.text.format.Time;
import android.util.Slog;
-import java.text.DateFormat;
import java.util.ArrayList;
-import java.util.Date;
import java.util.Iterator;
import libcore.util.Objects;
@@ -47,78 +48,88 @@
* Used by the UI mode manager and other components to adjust night mode
* effects based on sunrise and sunset.
*/
-public final class TwilightService {
- private static final String TAG = "TwilightService";
-
- private static final boolean DEBUG = false;
-
- private static final String ACTION_UPDATE_TWILIGHT_STATE =
+public final class TwilightService extends SystemService {
+ static final String TAG = "TwilightService";
+ static final boolean DEBUG = false;
+ static final String ACTION_UPDATE_TWILIGHT_STATE =
"com.android.server.action.UPDATE_TWILIGHT_STATE";
- private final Context mContext;
- private final AlarmManager mAlarmManager;
- private final LocationManager mLocationManager;
- private final LocationHandler mLocationHandler;
+ final Object mLock = new Object();
- private final Object mLock = new Object();
+ AlarmManager mAlarmManager;
+ LocationManager mLocationManager;
+ LocationHandler mLocationHandler;
- private final ArrayList<TwilightListenerRecord> mListeners =
+ final ArrayList<TwilightListenerRecord> mListeners =
new ArrayList<TwilightListenerRecord>();
- private boolean mSystemReady;
+ TwilightState mTwilightState;
- private TwilightState mTwilightState;
-
- public TwilightService(Context context) {
- mContext = context;
-
- mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
- mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+ @Override
+ public void onStart() {
+ mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+ mLocationManager = (LocationManager) getContext().getSystemService(
+ Context.LOCATION_SERVICE);
mLocationHandler = new LocationHandler();
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+ getContext().registerReceiver(mUpdateLocationReceiver, filter);
+
+ publishLocalService(TwilightManager.class, mService);
}
- void systemReady() {
- synchronized (mLock) {
- mSystemReady = true;
+ private static class TwilightListenerRecord implements Runnable {
+ private final TwilightListener mListener;
+ private final Handler mHandler;
- IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(Intent.ACTION_TIME_CHANGED);
- filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
- filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
- mContext.registerReceiver(mUpdateLocationReceiver, filter);
+ public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+ mListener = listener;
+ mHandler = handler;
+ }
- if (!mListeners.isEmpty()) {
- mLocationHandler.enableLocationUpdates();
+ public void postUpdate() {
+ mHandler.post(this);
+ }
+
+ @Override
+ public void run() {
+ mListener.onTwilightStateChanged();
+ }
+
+ }
+
+ private final TwilightManager mService = new TwilightManager() {
+ /**
+ * Gets the current twilight state.
+ *
+ * @return The current twilight state, or null if no information is available.
+ */
+ @Override
+ public TwilightState getCurrentState() {
+ synchronized (mLock) {
+ return mTwilightState;
}
}
- }
- /**
- * Gets the current twilight state.
- *
- * @return The current twilight state, or null if no information is available.
- */
- public TwilightState getCurrentState() {
- synchronized (mLock) {
- return mTwilightState;
- }
- }
+ /**
+ * Listens for twilight time.
+ *
+ * @param listener The listener.
+ */
+ @Override
+ public void registerListener(TwilightListener listener, Handler handler) {
+ synchronized (mLock) {
+ mListeners.add(new TwilightListenerRecord(listener, handler));
- /**
- * Listens for twilight time.
- *
- * @param listener The listener.
- * @param handler The handler on which to post calls into the listener.
- */
- public void registerListener(TwilightListener listener, Handler handler) {
- synchronized (mLock) {
- mListeners.add(new TwilightListenerRecord(listener, handler));
-
- if (mSystemReady && mListeners.size() == 1) {
- mLocationHandler.enableLocationUpdates();
+ if (mListeners.size() == 1) {
+ mLocationHandler.enableLocationUpdates();
+ }
}
}
- }
+ };
private void setTwilightState(TwilightState state) {
synchronized (mLock) {
@@ -128,9 +139,10 @@
}
mTwilightState = state;
- int count = mListeners.size();
- for (int i = 0; i < count; i++) {
- mListeners.get(i).post();
+
+ final int listenerLen = mListeners.size();
+ for (int i = 0; i < listenerLen; i++) {
+ mListeners.get(i).postUpdate();
}
}
}
@@ -162,124 +174,6 @@
return distance >= totalAccuracy;
}
- /**
- * Describes whether it is day or night.
- * This object is immutable.
- */
- public static final class TwilightState {
- private final boolean mIsNight;
- private final long mYesterdaySunset;
- private final long mTodaySunrise;
- private final long mTodaySunset;
- private final long mTomorrowSunrise;
-
- TwilightState(boolean isNight,
- long yesterdaySunset,
- long todaySunrise, long todaySunset,
- long tomorrowSunrise) {
- mIsNight = isNight;
- mYesterdaySunset = yesterdaySunset;
- mTodaySunrise = todaySunrise;
- mTodaySunset = todaySunset;
- mTomorrowSunrise = tomorrowSunrise;
- }
-
- /**
- * Returns true if it is currently night time.
- */
- public boolean isNight() {
- return mIsNight;
- }
-
- /**
- * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getYesterdaySunset() {
- return mYesterdaySunset;
- }
-
- /**
- * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTodaySunrise() {
- return mTodaySunrise;
- }
-
- /**
- * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
- * or -1 if the sun never sets.
- */
- public long getTodaySunset() {
- return mTodaySunset;
- }
-
- /**
- * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
- * or -1 if the sun never rises.
- */
- public long getTomorrowSunrise() {
- return mTomorrowSunrise;
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof TwilightState && equals((TwilightState)o);
- }
-
- public boolean equals(TwilightState other) {
- return other != null
- && mIsNight == other.mIsNight
- && mYesterdaySunset == other.mYesterdaySunset
- && mTodaySunrise == other.mTodaySunrise
- && mTodaySunset == other.mTodaySunset
- && mTomorrowSunrise == other.mTomorrowSunrise;
- }
-
- @Override
- public int hashCode() {
- return 0; // don't care
- }
-
- @Override
- public String toString() {
- DateFormat f = DateFormat.getDateTimeInstance();
- return "{TwilightState: isNight=" + mIsNight
- + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
- + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
- + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
- + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
- + "}";
- }
- }
-
- /**
- * Listener for changes in twilight state.
- */
- public interface TwilightListener {
- public void onTwilightStateChanged();
- }
-
- private static final class TwilightListenerRecord implements Runnable {
- private final TwilightListener mListener;
- private final Handler mHandler;
-
- public TwilightListenerRecord(TwilightListener listener, Handler handler) {
- mListener = listener;
- mHandler = handler;
- }
-
- public void post() {
- mHandler.post(this);
- }
-
- @Override
- public void run() {
- mListener.onTwilightStateChanged();
- }
- }
-
private final class LocationHandler extends Handler {
private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
@@ -518,11 +412,12 @@
}
Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ getContext(), 0, updateIntent, 0);
mAlarmManager.cancel(pendingIntent);
mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent);
}
- };
+ }
private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
@Override
diff --git a/services/java/com/android/server/twilight/TwilightState.java b/services/java/com/android/server/twilight/TwilightState.java
new file mode 100644
index 0000000..91e24d7
--- /dev/null
+++ b/services/java/com/android/server/twilight/TwilightState.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.twilight;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * Describes whether it is day or night.
+ * This object is immutable.
+ */
+public class TwilightState {
+ private final boolean mIsNight;
+ private final long mYesterdaySunset;
+ private final long mTodaySunrise;
+ private final long mTodaySunset;
+ private final long mTomorrowSunrise;
+
+ TwilightState(boolean isNight,
+ long yesterdaySunset,
+ long todaySunrise, long todaySunset,
+ long tomorrowSunrise) {
+ mIsNight = isNight;
+ mYesterdaySunset = yesterdaySunset;
+ mTodaySunrise = todaySunrise;
+ mTodaySunset = todaySunset;
+ mTomorrowSunrise = tomorrowSunrise;
+ }
+
+ /**
+ * Returns true if it is currently night time.
+ */
+ public boolean isNight() {
+ return mIsNight;
+ }
+
+ /**
+ * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getYesterdaySunset() {
+ return mYesterdaySunset;
+ }
+
+ /**
+ * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTodaySunrise() {
+ return mTodaySunrise;
+ }
+
+ /**
+ * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never sets.
+ */
+ public long getTodaySunset() {
+ return mTodaySunset;
+ }
+
+ /**
+ * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+ * or -1 if the sun never rises.
+ */
+ public long getTomorrowSunrise() {
+ return mTomorrowSunrise;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof TwilightState && equals((TwilightState)o);
+ }
+
+ public boolean equals(TwilightState other) {
+ return other != null
+ && mIsNight == other.mIsNight
+ && mYesterdaySunset == other.mYesterdaySunset
+ && mTodaySunrise == other.mTodaySunrise
+ && mTodaySunset == other.mTodaySunset
+ && mTomorrowSunrise == other.mTomorrowSunrise;
+ }
+
+ @Override
+ public int hashCode() {
+ return 0; // don't care
+ }
+
+ @Override
+ public String toString() {
+ DateFormat f = DateFormat.getDateTimeInstance();
+ return "{TwilightState: isNight=" + mIsNight
+ + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+ + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+ + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+ + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+ + "}";
+ }
+}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/wallpaper/WallpaperManagerService.java
similarity index 98%
rename from services/java/com/android/server/WallpaperManagerService.java
rename to services/java/com/android/server/wallpaper/WallpaperManagerService.java
index e6b6b93..97ea52c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.wallpaper;
import static android.os.ParcelFileDescriptor.*;
@@ -85,8 +85,8 @@
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
-class WallpaperManagerService extends IWallpaperManager.Stub {
- static final String TAG = "WallpaperService";
+public class WallpaperManagerService extends IWallpaperManager.Stub {
+ static final String TAG = "WallpaperManagerService";
static final boolean DEBUG = false;
final Object mLock = new Object[0];
@@ -98,7 +98,6 @@
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
static final String WALLPAPER = "wallpaper";
static final String WALLPAPER_INFO = "wallpaper_info.xml";
-
/**
* Name of the component used to display bitmap wallpapers from either the gallery or
* built-in wallpapers.
@@ -505,7 +504,12 @@
}
}
- String getName() {
+ /** Called by SystemBackupAgent */
+ public String getName() {
+ // Verify caller is the system
+ if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+ throw new RuntimeException("getName() can only be called from the system process");
+ }
synchronized (mLock) {
return mWallpaperMap.get(0).name;
}
@@ -1175,7 +1179,11 @@
}
// Called by SystemBackupAgent after files are restored to disk.
- void settingsRestored() {
+ public void settingsRestored() {
+ // Verify caller is the system
+ if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+ throw new RuntimeException("settingsRestored() can only be called from the system process");
+ }
// TODO: If necessary, make it work for secondary users as well. This currently assumes
// restores only to the primary user
if (DEBUG) Slog.v(TAG, "settingsRestored");
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/java/com/android/server/wm/DimLayer.java
index c189ddd..978d5b7 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/java/com/android/server/wm/DimLayer.java
@@ -166,7 +166,7 @@
final int dw, dh;
final float xPos, yPos;
- if (mStack.hasSibling()) {
+ if (!mStack.isFullscreen()) {
dw = mBounds.width();
dh = mBounds.height();
xPos = mBounds.left;
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index d358b4c..4352ece 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -21,10 +21,8 @@
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
-import android.app.ActivityManager.StackBoxInfo;
import android.graphics.Rect;
import android.graphics.Region;
-import android.os.Debug;
import android.util.EventLog;
import android.util.Slog;
import android.view.Display;
@@ -74,6 +72,7 @@
private final Display mDisplay;
Rect mBaseDisplayRect = new Rect();
+ Rect mContentRect = new Rect();
// Accessed directly by all users.
boolean layoutNeeded;
@@ -92,11 +91,12 @@
*/
final AppTokenList mExitingAppTokens = new AppTokenList();
- /** Array containing the home StackBox and possibly one more which would contain apps. Array
+ /** Array containing all TaskStacks on this display. Array
* is stored in display order with the current bottom stack at 0. */
- private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
+ private ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
- /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
+ /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
+ * (except a future lockscreen TaskStack) moves to the top. */
private TaskStack mHomeStack = null;
/** Detect user tapping outside of current focused stack bounds .*/
@@ -123,13 +123,6 @@
display.getDisplayInfo(mDisplayInfo);
isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
mService = service;
-
- StackBox newBox = new StackBox(service, this, null);
- mStackBoxes.add(newBox);
- TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
- newStack.mStackBox = newBox;
- newBox.mStack = newStack;
- mHomeStack = newStack;
}
int getDisplayId() {
@@ -155,10 +148,6 @@
return mDisplay.hasAccess(uid);
}
- boolean homeOnTop() {
- return mStackBoxes.get(0).mStack != mHomeStack;
- }
-
public boolean isPrivate() {
return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
}
@@ -205,7 +194,18 @@
}
void updateDisplayInfo() {
+ // Save old size.
+ int oldWidth = mDisplayInfo.logicalWidth;
+ int oldHeight = mDisplayInfo.logicalHeight;
mDisplay.getDisplayInfo(mDisplayInfo);
+
+ for (int i = mStacks.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mStacks.get(i);
+ if (!stack.isFullscreen()) {
+ stack.resizeBounds(oldWidth, oldHeight, mDisplayInfo.logicalWidth,
+ mDisplayInfo.logicalHeight);
+ }
+ }
}
void getLogicalDisplayRect(Rect out) {
@@ -227,159 +227,58 @@
return count;
}
- /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
- TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
- TaskStack newStack = null;
- if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
- + relativeStackBoxId + " position=" + position + " weight=" + weight);
+ /** Refer to {@link WindowManagerService#createStack(int, int)} */
+ TaskStack createStack(int stackId) {
+ if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId);
+ TaskStack newStack = new TaskStack(mService, stackId, this);
if (stackId == HOME_STACK_ID) {
- if (mStackBoxes.size() != 1) {
+ if (mHomeStack != null) {
throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
}
- newStack = mHomeStack;
- } else {
- int stackBoxNdx;
- for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- final StackBox box = mStackBoxes.get(stackBoxNdx);
- if (position == StackBox.TASK_STACK_GOES_OVER
- || position == StackBox.TASK_STACK_GOES_UNDER) {
- // Position indicates a new box is added at top level only.
- if (box.contains(relativeStackBoxId)) {
- StackBox newBox = new StackBox(mService, this, null);
- newStack = new TaskStack(mService, stackId, this);
- newStack.mStackBox = newBox;
- newBox.mStack = newStack;
- final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
- if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
- (stackBoxNdx + offset));
- mStackBoxes.add(stackBoxNdx + offset, newBox);
- break;
- }
- } else {
- // Remaining position values indicate a box must be split.
- newStack = box.split(stackId, relativeStackBoxId, position, weight);
- if (newStack != null) {
- break;
- }
- }
- }
- if (stackBoxNdx < 0) {
- throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
- + " not found.");
- }
+ mHomeStack = newStack;
}
- if (newStack != null) {
- layoutNeeded = true;
- }
- EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
- (int)(weight * 100 + 0.5));
+ mStacks.add(newStack);
+ layoutNeeded = true;
return newStack;
}
- /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
- boolean resizeStack(int stackBoxId, float weight) {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- final StackBox box = mStackBoxes.get(stackBoxNdx);
- if (box.resize(stackBoxId, weight)) {
- layoutNeeded = true;
+ void moveStack(TaskStack stack, boolean toTop) {
+ mStacks.remove(stack);
+ mStacks.add(toTop ? mStacks.size() : 0, stack);
+ }
+
+ TaskStack topStack() {
+ return mStacks.get(mStacks.size() - 1);
+ }
+
+ /**
+ * Propagate the new bounds to all child stacks.
+ * @param contentRect The bounds to apply at the top level.
+ */
+ void resize(Rect contentRect) {
+ mContentRect.set(contentRect);
+ }
+
+ boolean getStackBounds(int stackId, Rect bounds) {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mStacks.get(stackNdx);
+ if (stackId == stack.mStackId) {
+ bounds.set(stack.mBounds);
return true;
}
}
return false;
}
- void addStackBox(StackBox box, boolean toTop) {
- if (mStackBoxes.size() >= 2) {
- throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
- }
- mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
- }
-
- void removeStackBox(StackBox box) {
- if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
- final TaskStack stack = box.mStack;
- if (stack != null && stack.mStackId == HOME_STACK_ID) {
- // Never delete the home stack, even if it is empty.
- if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
- return;
- }
- mStackBoxes.remove(box);
- }
-
- StackBoxInfo getStackBoxInfo(StackBox box) {
- StackBoxInfo info = new StackBoxInfo();
- info.stackBoxId = box.mStackBoxId;
- info.weight = box.mWeight;
- info.vertical = box.mVertical;
- info.bounds = new Rect(box.mBounds);
- if (box.mStack != null) {
- info.stackId = box.mStack.mStackId;
- // ActivityManagerService will fill in the StackInfo.
- } else {
- info.stackId = -1;
- info.children = new StackBoxInfo[2];
- info.children[0] = getStackBoxInfo(box.mFirst);
- info.children[1] = getStackBoxInfo(box.mSecond);
- }
- return info;
- }
-
- ArrayList<StackBoxInfo> getStackBoxInfos() {
- ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
- }
- return list;
- }
-
- /**
- * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
- * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
- * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
- * @return true if a change was made, false otherwise.
- */
- boolean moveHomeStackBox(boolean toTop) {
- if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
- Debug.getCallers(4));
- EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
- switch (mStackBoxes.size()) {
- case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
- case 1: return false; // Only the home StackBox exists.
- case 2:
- if (homeOnTop() ^ toTop) {
- mStackBoxes.add(mStackBoxes.remove(0));
- return true;
- }
- return false;
- default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
- }
- }
-
- /**
- * Propagate the new bounds to all child stack boxes, applying weights as we move down.
- * @param contentRect The bounds to apply at the top level.
- */
- boolean setStackBoxSize(Rect contentRect) {
- boolean change = false;
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
- }
- return change;
- }
-
- Rect getStackBounds(int stackId) {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
- if (bounds != null) {
- return bounds;
+ int stackIdFromPoint(int x, int y) {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mStacks.get(stackNdx);
+ stack.getBounds(mTmpRect);
+ if (mTmpRect.contains(x, y)) {
+ return stack.mStackId;
}
}
- return null;
- }
-
- int stackIdFromPoint(int x, int y) {
- StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
- return topBox.stackIdFromPoint(x, y);
+ return -1;
}
void setTouchExcludeRegion(TaskStack focusedStack) {
@@ -408,48 +307,48 @@
}
}
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).switchUser(newUserId);
}
}
void resetAnimationBackgroundAnimator() {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
}
}
boolean animateDimLayers() {
boolean result = false;
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ result |= mStacks.get(stackNdx).animateDimLayers();
}
return result;
}
void resetDimming() {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- mStackBoxes.get(stackBoxNdx).resetDimming();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).resetDimmingTag();
}
}
boolean isDimming() {
boolean result = false;
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- result |= mStackBoxes.get(stackBoxNdx).isDimming();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ result |= mStacks.get(stackNdx).isDimming();
}
return result;
}
void stopDimmingIfNeeded() {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).stopDimmingIfNeeded();
}
}
void close() {
- for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
- mStackBoxes.get(stackBoxNdx).close();
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).close();
}
}
@@ -477,9 +376,10 @@
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
- for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
- pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
- mStackBoxes.get(boxNdx).dump(prefix + " ", pw);
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mStacks.get(stackNdx);
+ pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
+ stack.dump(prefix + " ", pw);
}
int ndx = numTokens();
if (ndx > 0) {
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/java/com/android/server/wm/FocusedStackFrame.java
index cc48b86..f1f5fe8 100644
--- a/services/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/java/com/android/server/wm/FocusedStackFrame.java
@@ -41,7 +41,7 @@
private final SurfaceControl mSurfaceControl;
private final Surface mSurface = new Surface();
private final Rect mLastBounds = new Rect();
- private final Rect mBounds = new Rect();
+ final Rect mBounds = new Rect();
private final Rect mTmpDrawRect = new Rect();
public FocusedStackFrame(Display display, SurfaceSession session) {
@@ -131,9 +131,9 @@
}
}
- public void setBounds(Rect bounds) {
- if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds);
- mBounds.set(bounds);
+ public void setBounds(TaskStack stack) {
+ stack.getBounds(mBounds);
+ if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
}
public void setLayer(int layer) {
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 3d2ec45..803b9ac 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -58,6 +58,8 @@
private final Object mInputDevicesReadyMonitor = new Object();
private boolean mInputDevicesReady;
+ Rect mTmpRect = new Rect();
+
public InputMonitor(WindowManagerService service) {
mService = service;
}
@@ -175,7 +177,8 @@
if (modal && child.mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
- inputWindowHandle.touchableRegion.set(child.getStackBounds());
+ child.getStackBounds(mTmpRect);
+ inputWindowHandle.touchableRegion.set(mTmpRect);
} else {
// Not modal or full screen modal
child.getTouchableRegion(inputWindowHandle.touchableRegion);
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
deleted file mode 100644
index d351925..0000000
--- a/services/java/com/android/server/wm/StackBox.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-import android.util.Slog;
-
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerService.TAG;
-
-import java.io.PrintWriter;
-
-public class StackBox {
- /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
- public static final int TASK_STACK_GOES_BEFORE = 0;
- /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
- public static final int TASK_STACK_GOES_AFTER = 1;
- /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */
- public static final int TASK_STACK_TO_LEFT_OF = 2;
- /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */
- public static final int TASK_STACK_TO_RIGHT_OF = 3;
- /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */
- public static final int TASK_STACK_GOES_ABOVE = 4;
- /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */
- public static final int TASK_STACK_GOES_BELOW = 5;
- /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */
- public static final int TASK_STACK_GOES_OVER = 6;
- /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
- public static final int TASK_STACK_GOES_UNDER = 7;
-
- static int sCurrentBoxId = 0;
-
- /** Unique id for this box */
- final int mStackBoxId;
-
- /** The service */
- final WindowManagerService mService;
-
- /** The display this box sits in. */
- final DisplayContent mDisplayContent;
-
- /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
- * is this entire size of mDisplayContent. */
- StackBox mParent;
-
- /** First child, this is null exactly when mStack is non-null. */
- StackBox mFirst;
-
- /** Second child, this is null exactly when mStack is non-null. */
- StackBox mSecond;
-
- /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
- TaskStack mStack;
-
- /** Content limits relative to the DisplayContent this sits in. */
- Rect mBounds = new Rect();
-
- /** Relative orientation of mFirst and mSecond. */
- boolean mVertical;
-
- /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */
- float mWeight;
-
- /** Dirty flag. Something inside this or some descendant of this has changed. */
- boolean layoutNeeded;
-
- /** True if this StackBox sits below the Status Bar. */
- boolean mUnderStatusBar;
-
- /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */
- Rect mTmpRect = new Rect();
-
- StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
- synchronized (StackBox.class) {
- mStackBoxId = sCurrentBoxId++;
- }
-
- mService = service;
- mDisplayContent = displayContent;
- mParent = parent;
- }
-
- /** Propagate #layoutNeeded bottom up. */
- void makeDirty() {
- layoutNeeded = true;
- if (mParent != null) {
- mParent.makeDirty();
- }
- }
-
- /**
- * Determine if a particular StackBox is this one or a descendant of this one.
- * @param stackBoxId The StackBox being searched for.
- * @return true if the specified StackBox matches this or one of its descendants.
- */
- boolean contains(int stackBoxId) {
- return mStackBoxId == stackBoxId ||
- (mStack == null && (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId)));
- }
-
- /**
- * Return the stackId of the stack that intersects the passed point.
- * @param x coordinate of point.
- * @param y coordinate of point.
- * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack.
- */
- int stackIdFromPoint(int x, int y) {
- if (!mBounds.contains(x, y)) {
- return -1;
- }
- if (mStack != null) {
- return mStack.mStackId;
- }
- int stackId = mFirst.stackIdFromPoint(x, y);
- if (stackId >= 0) {
- return stackId;
- }
- return mSecond.stackIdFromPoint(x, y);
- }
-
- /** Determine if this StackBox is the first child or second child.
- * @return true if this is the first child.
- */
- boolean isFirstChild() {
- return mParent != null && mParent.mFirst == this;
- }
-
- /** Returns the bounds of the specified TaskStack if it is contained in this StackBox.
- * @param stackId the TaskStack to find the bounds of.
- * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise.
- */
- Rect getStackBounds(int stackId) {
- if (mStack != null) {
- return mStack.mStackId == stackId ? new Rect(mBounds) : null;
- }
- Rect bounds = mFirst.getStackBounds(stackId);
- if (bounds != null) {
- return bounds;
- }
- return mSecond.getStackBounds(stackId);
- }
-
- /**
- * Create a new TaskStack relative to a specified one by splitting the StackBox containing
- * the specified TaskStack into two children. The size and position each of the new StackBoxes
- * is determined by the passed parameters.
- * @param stackId The id of the new TaskStack to create.
- * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to.
- * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
- * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
- * @return The new TaskStack.
- */
- TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {
- if (mStackBoxId != relativeStackBoxId) {
- // This is not the targeted StackBox.
- if (mStack != null) {
- return null;
- }
- // Propagate the split to see if the targeted StackBox is in either sub box.
- TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);
- if (stack != null) {
- return stack;
- }
- return mSecond.split(stackId, relativeStackBoxId, position, weight);
- }
-
- // Found it!
- TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);
- TaskStack firstStack;
- TaskStack secondStack;
- if (position == TASK_STACK_GOES_BEFORE) {
- // TODO: Test Configuration here for LTR/RTL.
- position = TASK_STACK_TO_LEFT_OF;
- } else if (position == TASK_STACK_GOES_AFTER) {
- // TODO: Test Configuration here for LTR/RTL.
- position = TASK_STACK_TO_RIGHT_OF;
- }
- switch (position) {
- default:
- case TASK_STACK_TO_LEFT_OF:
- case TASK_STACK_TO_RIGHT_OF:
- mVertical = false;
- if (position == TASK_STACK_TO_LEFT_OF) {
- mWeight = weight;
- firstStack = stack;
- secondStack = mStack;
- } else {
- mWeight = 1.0f - weight;
- firstStack = mStack;
- secondStack = stack;
- }
- break;
- case TASK_STACK_GOES_ABOVE:
- case TASK_STACK_GOES_BELOW:
- mVertical = true;
- if (position == TASK_STACK_GOES_ABOVE) {
- mWeight = weight;
- firstStack = stack;
- secondStack = mStack;
- } else {
- mWeight = 1.0f - weight;
- firstStack = mStack;
- secondStack = stack;
- }
- break;
- }
-
- mFirst = new StackBox(mService, mDisplayContent, this);
- firstStack.mStackBox = mFirst;
- mFirst.mStack = firstStack;
-
- mSecond = new StackBox(mService, mDisplayContent, this);
- secondStack.mStackBox = mSecond;
- mSecond.mStack = secondStack;
-
- mStack = null;
- return stack;
- }
-
- /** Return the stackId of the first mFirst StackBox with a non-null mStack */
- int getStackId() {
- if (mStack != null) {
- return mStack.mStackId;
- }
- return mFirst.getStackId();
- }
-
- /** Remove this box and propagate its sibling's content up to their parent.
- * @return The first stackId of the resulting StackBox. */
- int remove() {
- mDisplayContent.layoutNeeded = true;
-
- if (mParent == null) {
- // This is the top-plane stack.
- if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
- mDisplayContent.removeStackBox(this);
- return HOME_STACK_ID;
- }
-
- StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
- StackBox grandparent = mParent.mParent;
- sibling.mParent = grandparent;
- if (grandparent == null) {
- // mParent is a top-plane stack. Now sibling will be.
- if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
- mDisplayContent.removeStackBox(mParent);
- mDisplayContent.addStackBox(sibling, true);
- } else {
- if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
- if (mParent.isFirstChild()) {
- grandparent.mFirst = sibling;
- } else {
- grandparent.mSecond = sibling;
- }
- }
- return sibling.getStackId();
- }
-
- boolean resize(int stackBoxId, float weight) {
- if (mStackBoxId != stackBoxId) {
- return mStack == null &&
- (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight));
- }
- // Don't change weight on topmost stack.
- if (mParent != null) {
- mParent.mWeight = isFirstChild() ? weight : 1.0f - weight;
- }
- return true;
- }
-
- /** If this is a terminal StackBox (contains a TaskStack) set the bounds.
- * @param bounds The rectangle to set the bounds to.
- * @param underStatusBar True if the StackBox is directly below the Status Bar.
- * @return True if the bounds changed, false otherwise. */
- boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) {
- boolean change = false;
- if (mUnderStatusBar != underStatusBar) {
- change = true;
- mUnderStatusBar = underStatusBar;
- }
- if (mStack != null) {
- change |= !mBounds.equals(bounds);
- if (change) {
- mBounds.set(bounds);
- mStack.setBounds(bounds, underStatusBar);
- }
- } else {
- mTmpRect.set(bounds);
- if (mVertical) {
- final int height = bounds.height();
- int firstHeight = (int)(height * mWeight);
- mTmpRect.bottom = bounds.top + firstHeight;
- change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
- mTmpRect.top = mTmpRect.bottom;
- mTmpRect.bottom = bounds.top + height;
- change |= mSecond.setStackBoxSizes(mTmpRect, false);
- } else {
- final int width = bounds.width();
- int firstWidth = (int)(width * mWeight);
- mTmpRect.right = bounds.left + firstWidth;
- change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
- mTmpRect.left = mTmpRect.right;
- mTmpRect.right = bounds.left + width;
- change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar);
- }
- }
- return change;
- }
-
- void resetAnimationBackgroundAnimator() {
- if (mStack != null) {
- mStack.resetAnimationBackgroundAnimator();
- return;
- }
- mFirst.resetAnimationBackgroundAnimator();
- mSecond.resetAnimationBackgroundAnimator();
- }
-
- boolean animateDimLayers() {
- if (mStack != null) {
- return mStack.animateDimLayers();
- }
- boolean result = mFirst.animateDimLayers();
- result |= mSecond.animateDimLayers();
- return result;
- }
-
- void resetDimming() {
- if (mStack != null) {
- mStack.resetDimmingTag();
- return;
- }
- mFirst.resetDimming();
- mSecond.resetDimming();
- }
-
- boolean isDimming() {
- if (mStack != null) {
- return mStack.isDimming();
- }
- boolean result = mFirst.isDimming();
- result |= mSecond.isDimming();
- return result;
- }
-
- void stopDimmingIfNeeded() {
- if (mStack != null) {
- mStack.stopDimmingIfNeeded();
- return;
- }
- mFirst.stopDimmingIfNeeded();
- mSecond.stopDimmingIfNeeded();
- }
-
- void switchUserStacks(int userId) {
- if (mStack != null) {
- mStack.switchUser(userId);
- return;
- }
- mFirst.switchUserStacks(userId);
- mSecond.switchUserStacks(userId);
- }
-
- void close() {
- if (mStack != null) {
- mStack.mDimLayer.mDimSurface.destroy();
- mStack.mAnimationBackgroundSurface.mDimSurface.destroy();
- return;
- }
- mFirst.close();
- mSecond.close();
- }
-
- public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mParent="); pw.println(mParent);
- pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
- pw.print(" mVertical="); pw.print(mVertical);
- pw.print(" layoutNeeded="); pw.println(layoutNeeded);
- if (mFirst != null) {
- pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst));
- mFirst.dump(prefix + " ", pw);
- pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond));
- mSecond.dump(prefix + " ", pw);
- } else {
- pw.print(prefix); pw.print("mStack="); pw.println(mStack);
- mStack.dump(prefix + " ", pw);
- }
- }
-
- @Override
- public String toString() {
- if (mStack != null) {
- return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}";
- }
- return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent)
- + " first=" + System.identityHashCode(mFirst)
- + " second=" + System.identityHashCode(mSecond) + "}";
- }
-}
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index cb29df4..df1d108 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -26,8 +26,6 @@
import android.util.TypedValue;
import com.android.server.EventLogTags;
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -49,8 +47,9 @@
* mTaskHistory in the ActivityStack with the same mStackId */
private final ArrayList<Task> mTasks = new ArrayList<Task>();
- /** The StackBox this sits in. */
- StackBox mStackBox;
+ /** Content limits relative to the DisplayContent this sits in. Empty indicates fullscreen,
+ * Nonempty is size of this TaskStack but is also used to scale if DisplayContent changes. */
+ Rect mBounds = new Rect();
/** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
final DimLayer mDimLayer;
@@ -74,6 +73,9 @@
mDisplayContent = displayContent;
mDimLayer = new DimLayer(service, this);
mAnimationBackgroundSurface = new DimLayer(service, this);
+ // TODO: remove bounds from log, they are always 0.
+ EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
+ mBounds.right, mBounds.bottom);
}
DisplayContent getDisplayContent() {
@@ -84,12 +86,64 @@
return mTasks;
}
- boolean isHomeStack() {
- return mStackId == HOME_STACK_ID;
+ private void resizeWindows() {
+ final boolean underStatusBar = mBounds.top == 0;
+
+ final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+ for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ if (!resizingWindows.contains(win)) {
+ if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+ "setBounds: Resizing " + win);
+ resizingWindows.add(win);
+ }
+ win.mUnderStatusBar = underStatusBar;
+ }
+ }
+ }
}
- boolean hasSibling() {
- return mStackBox.mParent != null;
+ boolean setBounds(Rect bounds) {
+ if (mBounds.equals(bounds)) {
+ return false;
+ }
+
+ mDimLayer.setBounds(bounds);
+ mAnimationBackgroundSurface.setBounds(bounds);
+ mBounds.set(bounds);
+
+ resizeWindows();
+ return true;
+ }
+
+ void getBounds(Rect out) {
+ if (mBounds.isEmpty()) {
+ mDisplayContent.getLogicalDisplayRect(out);
+ } else {
+ out.set(mBounds);
+ }
+ out.intersect(mDisplayContent.mContentRect);
+ }
+
+ boolean isFullscreen() {
+ return mBounds.isEmpty();
+ }
+
+ void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
+ if (oldWidth == newWidth && oldHeight == newHeight) {
+ return;
+ }
+ float widthScale = newWidth / oldWidth;
+ float heightScale = newHeight / oldHeight;
+ mBounds.left = (int)(mBounds.left * widthScale + 0.5);
+ mBounds.top = (int)(mBounds.top * heightScale + 0.5);
+ mBounds.right = (int)(mBounds.right * widthScale + 0.5);
+ mBounds.bottom = (int)(mBounds.bottom * heightScale + 0.5);
+ resizeWindows();
}
/**
@@ -97,9 +151,7 @@
* @param task The task to add.
* @param toTop Whether to add it to the top or bottom.
*/
- boolean addTask(Task task, boolean toTop) {
- mStackBox.makeDirty();
-
+ void addTask(Task task, boolean toTop) {
int stackNdx;
if (!toTop) {
stackNdx = 0;
@@ -122,20 +174,20 @@
task.mStack = this;
mDisplayContent.addTask(task, toTop);
- return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
+ mDisplayContent.moveStack(this, true);
}
- boolean moveTaskToTop(Task task) {
+ void moveTaskToTop(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
+ Debug.getCallers(6));
mTasks.remove(task);
- return addTask(task, true);
+ addTask(task, true);
}
- boolean moveTaskToBottom(Task task) {
+ void moveTaskToBottom(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
mTasks.remove(task);
- return addTask(task, false);
+ addTask(task, false);
}
/**
@@ -145,7 +197,6 @@
*/
void removeTask(Task task) {
if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
- mStackBox.makeDirty();
mTasks.remove(task);
mDisplayContent.removeTask(task);
}
@@ -154,7 +205,7 @@
mAnimationBackgroundSurface.destroySurface();
mDimLayer.destroySurface();
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
- return mStackBox.remove();
+ return mDisplayContent.topStack().mStackId;
}
void resetAnimationBackgroundAnimator() {
@@ -259,28 +310,6 @@
}
}
- void setBounds(Rect bounds, boolean underStatusBar) {
- mDimLayer.setBounds(bounds);
- mAnimationBackgroundSurface.setBounds(bounds);
-
- final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
- for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
- for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
- final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
- for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
- final WindowState win = windows.get(winNdx);
- if (!resizingWindows.contains(win)) {
- if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
- "setBounds: Resizing " + win);
- resizingWindows.add(win);
- }
- win.mUnderStatusBar = underStatusBar;
- }
- }
- }
- }
-
void switchUser(int userId) {
int top = mTasks.size();
for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
@@ -293,6 +322,11 @@
}
}
+ void close() {
+ mDimLayer.mDimSurface.destroy();
+ mAnimationBackgroundSurface.mDimSurface.destroy();
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f9773a6..e50d61f 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -45,7 +45,6 @@
import com.android.server.power.ShutdownThread;
import android.Manifest;
-import android.app.ActivityManager.StackBoxInfo;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.StatusBarManager;
@@ -293,8 +292,6 @@
final private KeyguardDisableHandler mKeyguardDisableHandler;
- private final boolean mHeadless;
-
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -734,7 +731,6 @@
com.android.internal.R.bool.config_sf_limitedAlpha);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerService = displayManager;
- mHeadless = displayManager.isHeadless();
mDisplaySettings = new DisplaySettings(context);
mDisplaySettings.readSettingsLocked();
@@ -3778,10 +3774,8 @@
if (stack == null) {
mFocusedStackFrame.setVisibility(false);
} else {
- final StackBox box = stack.mStackBox;
- final Rect bounds = box.mBounds;
- final boolean multipleStacks = box.mParent != null;
- mFocusedStackFrame.setBounds(bounds);
+ mFocusedStackFrame.setBounds(stack);
+ final boolean multipleStacks = !stack.isFullscreen();
mFocusedStackFrame.setVisibility(multipleStacks);
}
} finally {
@@ -4788,10 +4782,12 @@
}
final TaskStack stack = task.mStack;
final DisplayContent displayContent = task.getDisplayContent();
- final boolean isHomeStackTask = stack.isHomeStack();
- if (isHomeStackTask != displayContent.homeOnTop()) {
- // First move the stack itself.
- displayContent.moveHomeStackBox(isHomeStackTask);
+ displayContent.moveStack(stack, true);
+ final TaskStack homeStack = displayContent.getHomeStack();
+ if (homeStack != stack) {
+ // When a non-home stack moves to the top, the home stack moves to the
+ // bottom.
+ displayContent.moveStack(homeStack, false);
}
stack.moveTaskToTop(task);
}
@@ -4822,36 +4818,19 @@
/**
* Create a new TaskStack and place it next to an existing stack.
* @param stackId The unique identifier of the new stack.
- * @param relativeStackBoxId The existing stack that this stack goes before or after.
- * @param position One of:
- * {@link StackBox#TASK_STACK_GOES_BEFORE}
- * {@link StackBox#TASK_STACK_GOES_AFTER}
- * {@link StackBox#TASK_STACK_GOES_ABOVE}
- * {@link StackBox#TASK_STACK_GOES_BELOW}
- * {@link StackBox#TASK_STACK_GOES_UNDER}
- * {@link StackBox#TASK_STACK_GOES_OVER}
- * @param weight Relative weight for determining how big to make the new TaskStack.
*/
- public void createStack(int stackId, int relativeStackBoxId, int position, float weight) {
+ public void createStack(int stackId, int displayId) {
synchronized (mWindowMap) {
- if (position <= StackBox.TASK_STACK_GOES_BELOW &&
- (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) {
- throw new IllegalArgumentException(
- "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
- STACK_WEIGHT_MAX + ", weight=" + weight);
- }
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
- TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position,
- weight);
- if (stack != null) {
+ if (displayContent.getDisplayId() == displayId) {
+ TaskStack stack = displayContent.createStack(stackId);
mStackIdToStack.put(stackId, stack);
performLayoutAndPlaceSurfacesLocked();
return;
}
}
- Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId);
}
}
@@ -4898,40 +4877,27 @@
}
}
- public void resizeStackBox(int stackBoxId, float weight) {
- if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) {
- throw new IllegalArgumentException(
- "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
- STACK_WEIGHT_MAX + ", weight=" + weight);
- }
+ public void resizeStack(int stackId, Rect bounds) {
synchronized (mWindowMap) {
- final int numDisplays = mDisplayContents.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) {
- performLayoutAndPlaceSurfacesLocked();
- return;
- }
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ + " not found.");
}
- }
- throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId
- + " not found.");
- }
-
- public ArrayList<StackBoxInfo> getStackBoxInfos() {
- synchronized(mWindowMap) {
- return getDefaultDisplayContentLocked().getStackBoxInfos();
+ if (stack.setBounds(bounds)) {
+ stack.getDisplayContent().layoutNeeded = true;
+ performLayoutAndPlaceSurfacesLocked();
+ }
}
}
- public Rect getStackBounds(int stackId) {
- final int numDisplays = mDisplayContents.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId);
- if (bounds != null) {
- return bounds;
- }
+ public void getStackBounds(int stackId, Rect bounds) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack != null) {
+ stack.getBounds(bounds);
+ return;
}
- return null;
+ bounds.setEmpty();
}
// -------------------------------------------------------------
@@ -5259,7 +5225,7 @@
public void performBootTimeout() {
synchronized(mWindowMap) {
- if (mDisplayEnabled || mHeadless) {
+ if (mDisplayEnabled) {
return;
}
Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5443,7 +5409,6 @@
// only allow disables from pids which have count on, etc.
@Override
public void showStrictModeViolation(boolean on) {
- if (mHeadless) return;
int pid = Binder.getCallingPid();
mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
}
@@ -5589,7 +5554,7 @@
continue;
}
appWin = ws;
- stackBounds.set(ws.getStackBounds());
+ ws.getStackBounds(stackBounds);
}
}
@@ -8218,7 +8183,7 @@
}
mPolicy.getContentRectLw(mTmpContentRect);
- displayContent.setStackBoxSize(mTmpContentRect);
+ displayContent.resize(mTmpContentRect);
int seq = mLayoutSeq+1;
if (seq < 0) seq = 0;
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 4d53cea..e6c1e98 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -463,8 +463,8 @@
mHaveFrame = true;
TaskStack stack = mAppToken != null ? getStack() : null;
- if (stack != null && stack.hasSibling()) {
- mContainingFrame.set(getStackBounds(stack));
+ if (stack != null && !stack.isFullscreen()) {
+ getStackBounds(stack, mContainingFrame);
if (mUnderStatusBar) {
mContainingFrame.top = pf.top;
}
@@ -723,15 +723,16 @@
return mDisplayContent.getHomeStack();
}
- Rect getStackBounds() {
- return getStackBounds(getStack());
+ void getStackBounds(Rect bounds) {
+ getStackBounds(getStack(), bounds);
}
- private Rect getStackBounds(TaskStack stack) {
+ private void getStackBounds(TaskStack stack, Rect bounds) {
if (stack != null) {
- return stack.mStackBox.mBounds;
+ stack.getBounds(bounds);
+ return;
}
- return mFrame;
+ bounds.set(mFrame);
}
public long getInputDispatchingTimeoutNanos() {
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 98e9b30..a98b1c3 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -8,7 +8,7 @@
com_android_server_input_InputApplicationHandle.cpp \
com_android_server_input_InputManagerService.cpp \
com_android_server_input_InputWindowHandle.cpp \
- com_android_server_LightsService.cpp \
+ com_android_server_lights_LightsService.cpp \
com_android_server_power_PowerManagerService.cpp \
com_android_server_SerialService.cpp \
com_android_server_SystemServer.cpp \
diff --git a/services/jni/com_android_server_LightsService.cpp b/services/jni/com_android_server_lights_LightsService.cpp
similarity index 97%
rename from services/jni/com_android_server_LightsService.cpp
rename to services/jni/com_android_server_lights_LightsService.cpp
index 401e1aa..ea03cfa 100644
--- a/services/jni/com_android_server_LightsService.cpp
+++ b/services/jni/com_android_server_lights_LightsService.cpp
@@ -134,7 +134,7 @@
int register_android_server_LightsService(JNIEnv *env)
{
- return jniRegisterNativeMethods(env, "com/android/server/LightsService",
+ return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
method_table, NELEM(method_table));
}