diff options
67 files changed, 3656 insertions, 3270 deletions
diff --git a/Android.mk b/Android.mk index 3a3169cf6475..ade5e385a33b 100644 --- a/Android.mk +++ b/Android.mk @@ -59,6 +59,8 @@ LOCAL_SRC_FILES += \ core/java/android/accounts/IAccountManagerResponse.aidl \ core/java/android/accounts/IAccountAuthenticator.aidl \ core/java/android/accounts/IAccountAuthenticatorResponse.aidl \ + core/java/android/app/IActivityContainer.aidl \ + core/java/android/app/IActivityContainerCallback.aidl \ core/java/android/app/IActivityController.aidl \ core/java/android/app/IActivityPendingResult.aidl \ core/java/android/app/IAlarmManager.aidl \ diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 0344d261fd35..7adf5ec69767 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -19,8 +19,9 @@ 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.IActivityContainer; import android.app.IActivityController; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; @@ -31,9 +32,11 @@ import android.content.IIntentReceiver; 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; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; @@ -106,11 +109,11 @@ public class Am extends BaseCommand { " 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> <DISPLAY_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 +207,16 @@ public class Am extends BaseCommand { "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 +1546,11 @@ public class Am extends BaseCommand { } 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,16 +1560,16 @@ public class Am extends BaseCommand { 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); + String displayIdStr = nextArgRequired(); + int displayId = Integer.valueOf(displayIdStr); try { - int stackId = mAm.createStack(taskId, relativeTo, position, weight); - System.out.println("createStack returned new stackId=" + stackId + "\n\n"); + IBinder homeActivityToken = mAm.getHomeActivityToken(); + IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null); + final int stackId = container.getStackId(); + System.out.println("createStack returned new stackId=" + stackId + "\n"); + container.attachToDisplay(displayId); + mAm.moveTaskToStack(taskId, stackId, true); } catch (RemoteException e) { } } @@ -1601,34 +1596,40 @@ public class Am extends BaseCommand { } } - 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 7ca345993c23..c877cd3ac264 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1289,106 +1289,15 @@ public class ActivityManager { } /** - * 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 @@ public class ActivityManager { dest.writeInt(bounds.bottom); dest.writeIntArray(taskIds); dest.writeStringArray(taskNames); + dest.writeInt(displayId); } public void readFromParcel(Parcel source) { @@ -1412,6 +1322,7 @@ public class ActivityManager { 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 class ActivityManager { 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 74266ccf58a2..0f38095a0b34 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.ParceledListSlice; 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; @@ -611,18 +612,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - 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); - reply.writeNoException(); - reply.writeInt(res); - return true; - } - case MOVE_TASK_TO_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int taskId = data.readInt(); @@ -635,25 +624,26 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM 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); @@ -2028,6 +2018,26 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case CREATE_ACTIVITY_CONTAINER_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder parentActivityToken = data.readStrongBinder(); + IActivityContainerCallback callback = + (IActivityContainerCallback) data.readStrongBinder(); + IActivityContainer activityContainer = + createActivityContainer(parentActivityToken, callback); + reply.writeNoException(); + reply.writeStrongBinder(activityContainer.asBinder()); + return true; + } + + case GET_HOME_ACTIVITY_TOKEN_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder homeActivityToken = getHomeActivityToken(); + reply.writeNoException(); + reply.writeStrongBinder(homeActivityToken); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2715,24 +2725,6 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override - public int createStack(int taskId, int relativeStackBoxId, int position, float weight) - 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(); - data.recycle(); - reply.recycle(); - return res; - } - @Override public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException { Parcel data = Parcel.obtain(); @@ -2747,44 +2739,44 @@ class ActivityManagerProxy implements IActivityManager 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(); @@ -4660,5 +4652,33 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(parentActivityToken); + data.writeStrongBinder((IBinder)callback); + mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0); + reply.readException(); + IActivityContainer res = + IActivityContainer.Stub.asInterface(reply.readStrongBinder()); + data.recycle(); + reply.recycle(); + return res; + } + + public IBinder getHomeActivityToken() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_HOME_ACTIVITY_TOKEN_TRANSACTION, data, reply, 0); + reply.readException(); + IBinder res = reply.readStrongBinder(); + data.recycle(); + reply.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl new file mode 100644 index 000000000000..2883d25ddd7d --- /dev/null +++ b/core/java/android/app/IActivityContainer.aidl @@ -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 android.app; + +import android.app.IActivityContainerCallback; +import android.content.Intent; +import android.os.IBinder; + +/** @hide */ +interface IActivityContainer { + void attachToDisplay(int displayId); + int getStackId(); + void detachFromDisplay(); + void startActivity(in Intent intent); +} diff --git a/core/java/android/app/IActivityContainerCallback.aidl b/core/java/android/app/IActivityContainerCallback.aidl new file mode 100644 index 000000000000..55c2001e90ef --- /dev/null +++ b/core/java/android/app/IActivityContainerCallback.aidl @@ -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 android.app; + +import android.os.IBinder; + +/** @hide */ +interface IActivityContainerCallback { + oneway void onLastActivityRemoved(IBinder container); +} diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 77c2ea0c1694..4be194597b6f 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -18,7 +18,7 @@ package android.app; 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.ProviderInfo; 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,10 @@ public interface IActivityManager extends IInterface { 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 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 */ @@ -408,6 +407,11 @@ public interface IActivityManager extends IInterface { public void performIdleMaintenance() throws RemoteException; + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException; + + public IBinder getHomeActivityToken() throws RemoteException; + /* * Private non-Binder interfaces */ @@ -678,12 +682,12 @@ public interface IActivityManager extends IInterface { int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166; - int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167; + int CREATE_ACTIVITY_CONTAINER_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; @@ -694,4 +698,5 @@ public interface IActivityManager extends IInterface { int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180; int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181; int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182; + int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183; } diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl index 3efd3c0ede8b..181eb63bce69 100644 --- a/core/java/android/app/IWallpaperManager.aidl +++ b/core/java/android/app/IWallpaperManager.aidl @@ -71,4 +71,14 @@ interface IWallpaperManager { * 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 b22d5cf32af5..a06a20b21b07 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -79,9 +79,6 @@ public class SurfaceControl { 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 @@ public class SurfaceControl { new Throwable()); } - checkHeadless(); - mName = name; mNativeObject = nativeCreate(session, name, w, h, format, flags); if (mNativeObject == 0) { @@ -619,10 +614,4 @@ public class SurfaceControl { } 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 b198937df18d..e5461178390b 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 c33bd3546aba..f33ab40efecf 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@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 8c3d0f09197c..9651239f6db2 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 2e1b0af7b099..3cdf170494d4 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -31,6 +31,7 @@ import android.net.Uri; 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 static android.app.AlarmManager.ELAPSED_REALTIME; 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 - - 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 int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup + + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } // 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private static final class FilterStats { + static final class FilterStats { final BroadcastStats mBroadcastStats; final Pair<String, ComponentName> mTarget; @@ -443,7 +441,7 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - private static final class BroadcastStats { + static final class BroadcastStats { final String mPackageName; long aggregateTime; @@ -459,47 +457,48 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } - @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; + } + + 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)); } - set(type, triggerAtTime, windowLength, interval, operation, false, workSource); + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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; + 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"); } - } - 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); - } + setImpl(type, triggerAtTime, windowLength, interval, operation, + false, workSource); } - } - - 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)); - } - - 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()); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } - } finally { - Binder.restoreCallingIdentity(oldId); - } - } - - 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 setTime(long millis) { + getContext().enforceCallingOrSelfPermission( + "android.permission.SET_TIME", + "setTime"); - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(operation) changed bounds; rebatching"); - } - rebatchAllAlarmsLocked(true); - rescheduleKernelAlarmsLocked(); + SystemClock.setCurrentTimeMillis(millis); } - } - 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); + @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(package) changed bounds; rebatching"); - } - rebatchAllAlarmsLocked(true); - rescheduleKernelAlarmsLocked(); - } - } + @Override + public void remove(PendingIntent operation) { + removeImpl(operation); - 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); - } } - if (didRemove) { - if (DEBUG_BATCH) { - Slog.v(TAG, "remove(user) 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 boolean lookForPackageLocked(String packageName) { - for (int i = 0; i < mAlarmBatches.size(); i++) { - Batch b = mAlarmBatches.get(i); - if (b.hasPackage(packageName)) { - return true; - } + dumpImpl(pw); } - 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 @@ class AlarmManagerService extends IAlarmManager.Stub { } } + 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 @@ class AlarmManagerService extends IAlarmManager.Stub { 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 5f3f894ca68e..cc9055dd480e 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -19,6 +19,8 @@ package com.android.server; 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 @@ public final class BatteryService extends Binder { 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 @@ public final class BatteryService extends Binder { "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 @@ public final class BatteryService extends Binder { }; 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 @@ public final class BatteryService extends Binder { 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 @@ public final class BatteryService extends Binder { 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 @@ public final class BatteryService extends Binder { } 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 a996dbda5cf5..26424a58061f 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.IInputMethodClient; 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 000000000000..deff79dccc72 --- /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 a42cbcfe0d64..662df922fd26 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.accessibility.AccessibilityManagerService; 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.PowerManagerService; 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 @@ class ServerThread { 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 @@ class ServerThread { 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 @@ class ServerThread { 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 @@ class ServerThread { 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 @@ class ServerThread { // 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 @@ class ServerThread { 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 @@ class ServerThread { ActivityManagerNative.getDefault().showBootMessage( context.getResources().getText( com.android.internal.R.string.android_upgrading_starting_apps), - false); + false); } catch (RemoteException e) { } @@ -567,22 +580,12 @@ class ServerThread { 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 @@ class ServerThread { 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 @@ class ServerThread { } } - 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 @@ class ServerThread { } } - 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 @@ class ServerThread { 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 @@ class ServerThread { } 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 @@ class ServerThread { 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 @@ class ServerThread { // 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 @@ class ServerThread { } 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 000000000000..37afb4f87541 --- /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 000000000000..648975a9b7ca --- /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 062be01ab26a..de912dcc1332 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -34,9 +34,9 @@ import android.content.res.Configuration; 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 java.io.PrintWriter; 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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; + int mNightMode = UiModeManager.MODE_NIGHT_NO; - private 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; - private int mSetUiMode = 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { } }; - 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; - - ServiceManager.addService(Context.UI_MODE_SERVICE, this); - - mContext.registerReceiver(mDockModeReceiver, + @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); + + 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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; + @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 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); + @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); + } } - final long ident = Binder.clearCallingIdentity(); - try { + @Override + public int getNightMode() { synchronized (mLock) { - if (isDoingNightModeLocked() && mNightMode != mode) { - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.UI_NIGHT_MODE, mode); - mNightMode = mode; - updateLocked(0, 0); - } + return mNightMode; } - } finally { - Binder.restoreCallingIdentity(ident); } - } - @Override // Binder call - public int getNightMode() { + @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 @@ final class UiModeManagerService extends IUiModeManager.Stub { } } - 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { } 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { // 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { // 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { 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 @@ final class UiModeManagerService extends IUiModeManager.Stub { } } - private void updateTwilight() { + void updateTwilight() { synchronized (mLock) { if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { updateComputedNightModeLocked(); @@ -573,36 +608,11 @@ final class UiModeManagerService extends IUiModeManager.Stub { } 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 e17f42d9f415..b24995382372 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -80,9 +80,6 @@ public class Watchdog extends Thread { 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 @@ public class Watchdog extends Thread { "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 fc66e45c0cee..4540c1cbbe6b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -28,11 +28,15 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import android.app.AppOpsManager; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.appwidget.AppWidgetManager; +import android.graphics.Rect; import android.util.ArrayMap; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; +import com.android.internal.app.ProcessMap; import com.android.internal.app.ProcessStats; import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatteryStatsImpl; @@ -45,14 +49,12 @@ import com.android.internal.util.Preconditions; import com.android.server.AppOpsService; import com.android.server.AttributeCache; import com.android.server.IntentResolver; -import com.android.internal.app.ProcessMap; import com.android.server.SystemServer; import com.android.server.Watchdog; import com.android.server.am.ActivityStack.ActivityState; 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 +70,6 @@ import org.xmlpull.v1.XmlSerializer; 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 +332,6 @@ public final class ActivityManagerService extends ActivityManagerNative 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 +1771,6 @@ public final class ActivityManagerService extends ActivityManagerNative public void setWindowManager(WindowManagerService wm) { mWindowManager = wm; mStackSupervisor.setWindowManager(wm); - wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f); } public void startObservingNativeCrashes() { @@ -1803,7 +1801,7 @@ public final class ActivityManagerService extends ActivityManagerNative m.mFactoryTest = factoryTest; m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface()); - m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper); + m.mStackSupervisor = new ActivityStackSupervisor(m); m.mBatteryStatsService.publish(context); m.mUsageStatsService.publish(context); @@ -1984,8 +1982,6 @@ public final class ActivityManagerService extends ActivityManagerNative 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 @@ public final class ActivityManagerService extends ActivityManagerNative } 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 @@ public final class ActivityManagerService extends ActivityManagerNative // 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,23 +7096,28 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public int createStack(int taskId, int relativeStackBoxId, int position, float weight) { + public IBinder getHomeActivityToken() throws RemoteException { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, - "createStack()"); - if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" + - relativeStackBoxId + " position=" + position + " weight=" + weight); + "getHomeActivityToken()"); synchronized (this) { - long ident = Binder.clearCallingIdentity(); - try { - int stackId = mStackSupervisor.createStack(); - mWindowManager.createStack(stackId, relativeStackBoxId, position, weight); - if (taskId > 0) { - moveTaskToStack(taskId, stackId, true); - } - return stackId; - } finally { - Binder.restoreCallingIdentity(ident); + return mStackSupervisor.getHomeActivityToken(); + } + } + + @Override + public IActivityContainer createActivityContainer(IBinder parentActivityToken, + IActivityContainerCallback callback) throws RemoteException { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "createActivityContainer()"); + synchronized (this) { + if (parentActivityToken == null) { + throw new IllegalArgumentException("parent token must not be null"); + } + ActivityRecord r = ActivityRecord.forToken(parentActivityToken); + if (r == null) { + return null; } + return mStackSupervisor.createActivityContainer(r, callback); } } @@ -7148,99 +7142,40 @@ public final class ActivityManagerService extends ActivityManagerNative } @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()"); + "getAllStackInfos()"); 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.getAllStackInfosLocked(); } - 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.getStackInfoLocked(stackId); } - return info; } finally { Binder.restoreCallingIdentity(ident); } @@ -9496,10 +9431,6 @@ public final class ActivityManagerService extends ActivityManagerNative 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 +13973,6 @@ public final class ActivityManagerService extends ActivityManagerNative */ 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) { @@ -14127,18 +14055,21 @@ public final class ActivityManagerService extends ActivityManagerNative boolean kept = true; final ActivityStack mainStack = mStackSupervisor.getFocusedStack(); - if (changes != 0 && starting == null) { - // If the configuration changed, and the caller is not already - // in the process of starting an activity, then find the top - // activity to check if its configuration needs to change. - starting = mainStack.topRunningActivityLocked(null); - } - - if (starting != null) { - kept = mainStack.ensureActivityConfigurationLocked(starting, changes); - // And we need to make sure at this point that all other activities - // are made visible with the correct configuration. - mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + // mainStack is null during startup. + if (mainStack != null) { + if (changes != 0 && starting == null) { + // If the configuration changed, and the caller is not already + // in the process of starting an activity, then find the top + // activity to check if its configuration needs to change. + starting = mainStack.topRunningActivityLocked(null); + } + + if (starting != null) { + kept = mainStack.ensureActivityConfigurationLocked(starting, changes); + // And we need to make sure at this point that all other activities + // are made visible with the correct configuration. + mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes); + } } if (values != null && mWindowManager != null) { diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 49f29fe6c372..38b01df5adc4 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -21,6 +21,7 @@ import com.android.internal.R.styleable; import com.android.internal.app.ResolverActivity; import com.android.server.AttributeCache; import com.android.server.am.ActivityStack.ActivityState; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import android.app.ActivityOptions; import android.app.ResultInfo; @@ -138,6 +139,7 @@ final class ActivityRecord { boolean forceNewConfig; // force re-create with new config next time int launchCount; // count of launches since last state long lastLaunchTime; // time of last lauch of this activity + ArrayList<ActivityStack> mChildContainers = new ArrayList<ActivityStack>(); String stringName; // for caching of toString(). diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 37f4cd7a32af..8faee556af7e 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -39,6 +39,7 @@ import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; +import com.android.server.am.ActivityStackSupervisor.ActivityContainer; import com.android.server.wm.AppTransition; import com.android.server.wm.TaskGroup; import com.android.server.wm.WindowManagerService; @@ -52,7 +53,6 @@ import android.app.IThumbnailReceiver; import android.app.ResultInfo; import android.app.ActivityManager.RunningTaskInfo; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -139,8 +139,6 @@ final class ActivityStack { final ActivityManagerService mService; final WindowManagerService mWindowManager; - final Context mContext; - /** * The back history of all previous (and possibly still * running) activities. It contains #TaskRecord objects. @@ -230,6 +228,8 @@ final class ActivityStack { final int mStackId; + final ActivityContainer mActivityContainer; + /** Run all ActivityStacks through this */ final ActivityStackSupervisor mStackSupervisor; @@ -327,14 +327,14 @@ final class ActivityStack { return count; } - ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) { - mHandler = new ActivityStackHandler(looper); - mService = service; - mWindowManager = service.mWindowManager; - mStackSupervisor = service.mStackSupervisor; - mContext = context; - mStackId = stackId; - mCurrentUser = service.mCurrentUserId; + ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) { + mActivityContainer = activityContainer; + mStackSupervisor = activityContainer.getOuter(); + mService = mStackSupervisor.mService; + mHandler = new ActivityStackHandler(mService.mHandler.getLooper()); + mWindowManager = mService.mWindowManager; + mStackId = activityContainer.mStackId; + mCurrentUser = mService.mCurrentUserId; } boolean okToShow(ActivityRecord r) { @@ -436,25 +436,6 @@ final class ActivityStack { return null; } - boolean containsApp(ProcessRecord app) { - if (app == null) { - return false; - } - for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { - final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.finishing) { - continue; - } - if (r.app == app) { - return true; - } - } - } - return false; - } - final boolean updateLRUListLocked(ActivityRecord r) { final boolean hadit = mLRUActivities.remove(r); mLRUActivities.add(r); @@ -465,6 +446,13 @@ final class ActivityStack { return mStackId == HOME_STACK_ID; } + ArrayList<ActivityStack> getStacksLocked() { + if (mActivityContainer.isAttached()) { + return mActivityContainer.mActivityDisplayInfo.stacks; + } + return null; + } + /** * Returns the top activity in any existing task matching the given * Intent. Returns null if no such task is found. @@ -1287,17 +1275,7 @@ final class ActivityStack { 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 +1727,9 @@ final class ActivityStack { 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 +2390,12 @@ final class ActivityStack { 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 483b4a04390e..f1ac7fe14151 100644 --- a/services/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/java/com/android/server/am/ActivityStackSupervisor.java @@ -34,8 +34,11 @@ import static com.android.server.am.ActivityManagerService.TAG; import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.IActivityContainer; +import android.app.IActivityContainerCallback; import android.app.IActivityManager; import android.app.IApplicationThread; import android.app.IThumbnailReceiver; @@ -53,6 +56,9 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; +import android.graphics.Point; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.os.Binder; import android.os.Bundle; import android.os.Debug; @@ -68,13 +74,15 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; -import android.util.SparseIntArray; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.Display; +import android.view.DisplayInfo; 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; @@ -83,7 +91,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -public final class ActivityStackSupervisor { +public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG = ActivityManagerService.DEBUG || false; static final boolean DEBUG_ADD_REMOVE = DEBUG || false; static final boolean DEBUG_APP = DEBUG || false; @@ -107,19 +115,22 @@ public final class ActivityStackSupervisor { static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2; static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3; static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4; + static final int HANDLE_DISPLAY_ADDED = FIRST_SUPERVISOR_STACK_MSG + 5; + static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6; + static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7; + // For debugging to make sure the caller when acquiring/releasing our // wake lock is the system process. static final boolean VALIDATE_WAKE_LOCK_CALLER = false; final ActivityManagerService mService; - final Context mContext; - final Looper mLooper; final ActivityStackSupervisorHandler mHandler; /** Short cut */ WindowManagerService mWindowManager; + DisplayManager mDisplayManager; /** Dismiss the keyguard after the next activity is displayed? */ boolean mDismissKeyguardOnNextActivity = false; @@ -142,14 +153,10 @@ public final class ActivityStackSupervisor { * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */ private ActivityStack mFocusedStack; - /** All the non-launcher stacks */ - private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>(); - - private static final int STACK_STATE_HOME_IN_FRONT = 0; - private static final int STACK_STATE_HOME_TO_BACK = 1; - private static final int STACK_STATE_HOME_IN_BACK = 2; - private static final int STACK_STATE_HOME_TO_FRONT = 3; - private int mStackState = STACK_STATE_HOME_IN_FRONT; + /** If this is the same as mFocusedStack then the activity on the top of the focused stack has + * been resumed. If stacks are changing position this will hold the old stack until the new + * stack becomes resumed after which it will be set to the new stack. */ + private ActivityStack mLastFocusedStack; /** List of activities that are waiting for a new activity to become visible before completing * whatever operation they are supposed to do. */ @@ -206,14 +213,17 @@ public final class ActivityStackSupervisor { /** Stack id of the front stack when user switched, indexed by userId. */ SparseIntArray mUserStackInFront = new SparseIntArray(2); - public ActivityStackSupervisor(ActivityManagerService service, Context context, - Looper looper) { + /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */ + SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>(); + + /** Mapping from displayId to display current state */ + SparseArray<ActivityDisplayInfo> mDisplayInfos = new SparseArray<ActivityDisplayInfo>(); + + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; - mContext = context; - mLooper = looper; - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mHandler = new ActivityStackSupervisorHandler(looper); + mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper()); if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) { throw new IllegalStateException("Calling must be system uid"); } @@ -223,9 +233,23 @@ public final class ActivityStackSupervisor { } void setWindowManager(WindowManagerService wm) { - mWindowManager = wm; - mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID); - mStacks.add(mHomeStack); + synchronized (mService) { + mWindowManager = wm; + + mDisplayManager = + (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE); + mDisplayManager.registerDisplayListener(this, null); + + Display[] displays = mDisplayManager.getDisplays(); + for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) { + final int displayId = displays[displayNdx].getDisplayId(); + ActivityDisplayInfo info = new ActivityDisplayInfo(displayId); + mDisplayInfos.put(displayId, info); + } + + createStackOnDisplay(null, HOME_STACK_ID, Display.DEFAULT_DISPLAY); + mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID); + } } void dismissKeyguard() { @@ -237,43 +261,38 @@ public final class ActivityStackSupervisor { } ActivityStack getFocusedStack() { - if (mFocusedStack == null) { - return mHomeStack; - } - switch (mStackState) { - case STACK_STATE_HOME_IN_FRONT: - case STACK_STATE_HOME_TO_FRONT: - return mHomeStack; - case STACK_STATE_HOME_IN_BACK: - case STACK_STATE_HOME_TO_BACK: - default: - return mFocusedStack; - } + return mFocusedStack; } ActivityStack getLastStack() { - switch (mStackState) { - case STACK_STATE_HOME_IN_FRONT: - case STACK_STATE_HOME_TO_BACK: - return mHomeStack; - case STACK_STATE_HOME_TO_FRONT: - case STACK_STATE_HOME_IN_BACK: - default: - return mFocusedStack; - } + return mLastFocusedStack; } + // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the + // top of all visible stacks. boolean isFrontStack(ActivityStack stack) { - return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack()); + ArrayList<ActivityStack> stacks = stack.getStacksLocked(); + if (stacks != null && !stacks.isEmpty()) { + return stack == stacks.get(stacks.size() - 1); + } + return false; } void moveHomeStack(boolean toFront) { - final boolean homeInFront = isFrontStack(mHomeStack); - if (homeInFront ^ toFront) { - if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" + - stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ? - STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT)); - mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT; + ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked(); + int topNdx = stacks.size() - 1; + if (topNdx <= 0) { + return; + } + ActivityStack topStack = stacks.get(topNdx); + final boolean homeInFront = topStack == mHomeStack; + if (homeInFront != toFront) { + mLastFocusedStack = topStack; + stacks.remove(mHomeStack); + stacks.add(toFront ? topNdx : 0, mHomeStack); + mFocusedStack = stacks.get(topNdx); + if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new=" + + mFocusedStack); } } @@ -301,21 +320,29 @@ public final class ActivityStackSupervisor { } TaskRecord anyTaskForIdLocked(int id) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); - TaskRecord task = stack.taskForIdLocked(id); - if (task != null) { - return task; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); + TaskRecord task = stack.taskForIdLocked(id); + if (task != null) { + return task; + } } } return null; } ActivityRecord isInAnyStackLocked(IBinder token) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token); - if (r != null) { - return r; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token); + if (r != null) { + return r; + } } } return null; @@ -340,14 +367,11 @@ public final class ActivityStackSupervisor { } if (stack.removeTask(task) && !stack.isHomeStack()) { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack); - mStacks.remove(stack); + stack.mActivityContainer.detachLocked(); final int stackId = stack.mStackId; final int nextStackId = mWindowManager.removeStack(stackId); // TODO: Perhaps we need to let the ActivityManager determine the next focus... - if (mFocusedStack == null || mFocusedStack.mStackId == stackId) { - // If this is the last app stack, set mFocusedStack to null. - mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId); - } + mFocusedStack = getStack(nextStackId); } } @@ -366,29 +390,29 @@ public final class ActivityStackSupervisor { return resumedActivity; } - boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception { - boolean didSomething = false; + boolean attachApplicationLocked(ProcessRecord app) throws Exception { final String processName = app.processName; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - ActivityRecord hr = stack.topRunningActivityLocked(null); - if (hr != null) { - 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)) { - didSomething = true; + boolean didSomething = false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack)) { + continue; + } + ActivityRecord hr = stack.topRunningActivityLocked(null); + if (hr != null) { + if (hr.app == null && app.uid == hr.info.applicationInfo.uid + && processName.equals(hr.processName)) { + try { + if (realStartActivityLocked(hr, app, true, true)) { + didSomething = true; + } + } catch (Exception e) { + Slog.w(TAG, "Exception in new application when starting activity " + + hr.intent.getComponent().flattenToShortString(), e); + throw e; } - } catch (Exception e) { - Slog.w(TAG, "Exception in new application when starting activity " - + hr.intent.getComponent().flattenToShortString(), e); - throw e; } } } @@ -400,53 +424,52 @@ public final class ActivityStackSupervisor { } boolean allResumedActivitiesIdle() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - continue; - } - final ActivityRecord resumedActivity = stack.mResumedActivity; - if (resumedActivity == null || !resumedActivity.idle) { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack)) { + continue; + } + final ActivityRecord resumedActivity = stack.mResumedActivity; + if (resumedActivity == null || !resumedActivity.idle) { + return false; + } } } return true; } boolean allResumedActivitiesComplete() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - final ActivityRecord r = stack.mResumedActivity; - if (r != null && r.state != ActivityState.RESUMED) { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + final ActivityRecord r = stack.mResumedActivity; + if (r != null && r.state != ActivityState.RESUMED) { + return false; + } } } } // TODO: Not sure if this should check if all Paused are complete too. - switch (mStackState) { - case STACK_STATE_HOME_TO_BACK: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_BACK)); - mStackState = STACK_STATE_HOME_IN_BACK; - break; - case STACK_STATE_HOME_TO_FRONT: - if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" + - stackStateToString(STACK_STATE_HOME_IN_FRONT)); - mStackState = STACK_STATE_HOME_IN_FRONT; - break; - } + if (DEBUG_STACK) Slog.d(TAG, + "allResumedActivitiesComplete: mLastFocusedStack changing from=" + + mLastFocusedStack + " to=" + mFocusedStack); + mLastFocusedStack = mFocusedStack; return true; } boolean allResumedActivitiesVisible() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - final ActivityRecord r = stack.mResumedActivity; - if (r != null && (!r.nowVisible || r.waitingVisible)) { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mResumedActivity; + if (r != null && (!r.nowVisible || r.waitingVisible)) { + return false; + } } } return true; @@ -459,13 +482,16 @@ public final class ActivityStackSupervisor { */ boolean pauseBackStacks(boolean userLeaving) { boolean someActivityPaused = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack) && stack.mResumedActivity != null) { - if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + - " mResumedActivity=" + stack.mResumedActivity); - stack.startPausingLocked(userLeaving, false); - someActivityPaused = true; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!isFrontStack(stack) && stack.mResumedActivity != null) { + if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack + + " mResumedActivity=" + stack.mResumedActivity); + stack.startPausingLocked(userLeaving, false); + someActivityPaused = true; + } } } return someActivityPaused; @@ -473,17 +499,20 @@ public final class ActivityStackSupervisor { boolean allPausedActivitiesComplete() { boolean pausing = true; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - final ActivityRecord r = stack.mPausingActivity; - if (r != null && r.state != ActivityState.PAUSED - && r.state != ActivityState.STOPPED - && r.state != ActivityState.STOPPING) { - if (DEBUG_STATES) { - Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); - pausing = false; - } else { - return false; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + final ActivityRecord r = stack.mPausingActivity; + if (r != null && r.state != ActivityState.PAUSED + && r.state != ActivityState.STOPPED + && r.state != ActivityState.STOPPING) { + if (DEBUG_STATES) { + Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state); + pausing = false; + } else { + return false; + } } } } @@ -525,8 +554,10 @@ public final class ActivityStackSupervisor { return r; } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // Return to the home stack. + final ArrayList<ActivityStack> stacks = mHomeStack.getStacksLocked(); + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); if (stack != focusedStack && isFrontStack(stack)) { r = stack.topRunningActivityLocked(null); if (r != null) { @@ -542,15 +573,19 @@ public final class ActivityStackSupervisor { ActivityRecord r = null; // Gather all of the running tasks for each stack into runningTaskLists. - final int numStacks = mStacks.size(); - ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks]; - for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); - runningTaskLists[stackNdx] = stackTaskList; - final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); - if (isFrontStack(stack)) { - r = ar; + ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = + new ArrayList<ArrayList<RunningTaskInfo>>(); + final int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>(); + runningTaskLists.add(stackTaskList); + final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList); + if (r == null && isFrontStack(stack)) { + r = ar; + } } } @@ -559,8 +594,9 @@ public final class ActivityStackSupervisor { while (maxNum > 0) { long mostRecentActiveTime = Long.MIN_VALUE; ArrayList<RunningTaskInfo> selectedStackList = null; - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx]; + final int numTaskLists = runningTaskLists.size(); + for (int stackNdx = 0; stackNdx < numTaskLists; ++stackNdx) { + ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists.get(stackNdx); if (!stackTaskList.isEmpty()) { final long lastActiveTime = stackTaskList.get(0).lastActiveTime; if (lastActiveTime > mostRecentActiveTime) { @@ -1266,7 +1302,7 @@ public final class ActivityStackSupervisor { if (mFocusedStack != taskStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task); - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; + mFocusedStack = taskStack; } else { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Focused stack already=" + mFocusedStack); @@ -1274,25 +1310,28 @@ public final class ActivityStackSupervisor { return taskStack; } - if (mFocusedStack != null) { + if (mFocusedStack != mHomeStack) { if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Have a focused stack=" + mFocusedStack); return mFocusedStack; } - for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) { - ActivityStack stack = mStacks.get(stackNdx); - if (!stack.isHomeStack()) { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "adjustStackFocus: Setting focused stack=" + stack); - mFocusedStack = stack; - return mFocusedStack; + int numDisplays = mDisplayInfos.size(); + for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + ActivityStack stack = stacks.get(stackNdx); + if (!stack.isHomeStack()) { + if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, + "adjustStackFocus: Setting focused stack=" + stack); + mFocusedStack = stack; + return mFocusedStack; + } } } - // 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); + // Need to create an app stack for this user. + int stackId = createStackOnDisplay(null, getNextStackId(), Display.DEFAULT_DISPLAY); if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r + " stackId=" + stackId); mFocusedStack = getStack(stackId); @@ -1302,30 +1341,10 @@ public final class ActivityStackSupervisor { } void setFocusedStack(ActivityRecord r) { - if (r == null) { - return; - } - if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) { - if (mStackState != STACK_STATE_HOME_IN_FRONT) { - if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_FRONT) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_FRONT; - } - } else { - if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, - "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task + - " Callers=" + Debug.getCallers(3)); - final ActivityStack taskStack = r.task.stack; - mFocusedStack = taskStack.isHomeStack() ? null : taskStack; - if (mStackState != STACK_STATE_HOME_IN_BACK) { - if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" + - stackStateToString(mStackState) + " new=" + - stackStateToString(STACK_STATE_HOME_TO_BACK) + - " Callers=" + Debug.getCallers(3)); - mStackState = STACK_STATE_HOME_TO_BACK; - } + if (r != null) { + final boolean isHomeActivity = + !r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask()); + moveHomeStack(isHomeActivity); } } @@ -1941,17 +1960,21 @@ public final class ActivityStackSupervisor { boolean handleAppDiedLocked(ProcessRecord app) { boolean hasVisibleActivities = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app); + } } return hasVisibleActivities; } void closeSystemDialogsLocked() { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.closeSystemDialogsLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).closeSystemDialogsLocked(); + } } } @@ -1964,11 +1987,14 @@ public final class ActivityStackSupervisor { */ boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { - didSomething = true; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) { + didSomething = true; + } } } return didSomething; @@ -1983,15 +2009,18 @@ public final class ActivityStackSupervisor { // we don't blow away the previous app if this activity is being // hosted by the process that is actually still the foreground. ProcessRecord fgApp = null; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - if (stack.mResumedActivity != null) { - fgApp = stack.mResumedActivity.app; - } else if (stack.mPausingActivity != null) { - fgApp = stack.mPausingActivity.app; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + if (stack.mResumedActivity != null) { + fgApp = stack.mResumedActivity.app; + } else if (stack.mPausingActivity != null) { + fgApp = stack.mPausingActivity.app; + } + break; } - break; } } @@ -2015,13 +2044,16 @@ public final class ActivityStackSupervisor { targetStack = getFocusedStack(); } boolean result = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - if (stack == targetStack) { - result = stack.resumeTopActivityLocked(target, targetOptions); - } else { - stack.resumeTopActivityLocked(null); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (isFrontStack(stack)) { + if (stack == targetStack) { + result = stack.resumeTopActivityLocked(target, targetOptions); + } else { + stack.resumeTopActivityLocked(null); + } } } } @@ -2029,38 +2061,91 @@ public final class ActivityStackSupervisor { } void finishTopRunningActivityLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.finishTopRunningActivityLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.finishTopRunningActivityLocked(app); + } } } void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { - if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + - mStacks.get(stackNdx)); - return; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { + if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + + stacks.get(stackNdx)); + return; + } } } } ActivityStack getStack(int stackId) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (stack.getStackId() == stackId) { - return stack; - } + ActivityContainer activityContainer = mActivityContainers.get(stackId); + if (activityContainer != null) { + return activityContainer.mStack; } return null; } ArrayList<ActivityStack> getStacks() { - return new ArrayList<ActivityStack>(mStacks); + ArrayList<ActivityStack> allStacks = new ArrayList<ActivityStack>(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + allStacks.addAll(mDisplayInfos.valueAt(displayNdx).stacks); + } + return allStacks; + } + + IBinder getHomeActivityToken() { + final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = tasks.get(taskNdx); + if (task.isHomeTask()) { + final ArrayList<ActivityRecord> activities = task.mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.isHomeActivity()) { + return r.appToken; + } + } + } + } + return null; + } + + ActivityContainer createActivityContainer(ActivityRecord parentActivity, int stackId, + IActivityContainerCallback callback) { + ActivityContainer activityContainer = new ActivityContainer(parentActivity, stackId, + callback); + mActivityContainers.put(stackId, activityContainer); + if (parentActivity != null) { + parentActivity.mChildContainers.add(activityContainer.mStack); + } + return activityContainer; + } + + ActivityContainer createActivityContainer(ActivityRecord parentActivity, + IActivityContainerCallback callback) { + return createActivityContainer(parentActivity, getNextStackId(), callback); } - int createStack() { + private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) { + ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId); + if (displayInfo == null) { + return -1; + } + + ActivityContainer activityContainer = + createActivityContainer(parentActivity, stackId, null); + activityContainer.attachToDisplayLocked(displayInfo); + return stackId; + } + + int getNextStackId() { while (true) { if (++mLastStackId <= HOME_STACK_ID) { mLastStackId = HOME_STACK_ID + 1; @@ -2069,7 +2154,6 @@ public final class ActivityStackSupervisor { break; } } - mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId)); return mLastStackId; } @@ -2091,15 +2175,18 @@ public final class ActivityStackSupervisor { ActivityRecord findTaskLocked(ActivityRecord r) { if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!r.isApplicationActivity() && !stack.isHomeStack()) { - if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); - continue; - } - final ActivityRecord ar = stack.findTaskLocked(r); - if (ar != null) { - return ar; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (!r.isApplicationActivity() && !stack.isHomeStack()) { + if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack); + continue; + } + final ActivityRecord ar = stack.findTaskLocked(r); + if (ar != null) { + return ar; + } } } if (DEBUG_TASKS) Slog.d(TAG, "No task found"); @@ -2107,10 +2194,13 @@ public final class ActivityStackSupervisor { } ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info); - if (ar != null) { - return ar; + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info); + if (ar != null) { + return ar; + } } } return null; @@ -2138,8 +2228,11 @@ public final class ActivityStackSupervisor { final long endTime = System.currentTimeMillis() + timeout; while (true) { boolean cantShutdown = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (cantShutdown) { long timeRemaining = endTime - System.currentTimeMillis(); @@ -2170,11 +2263,14 @@ public final class ActivityStackSupervisor { if (mGoingToSleep.isHeld()) { mGoingToSleep.release(); } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.awakeFromSleepingLocked(); - if (isFrontStack(stack)) { - resumeTopActivitiesLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.awakeFromSleepingLocked(); + if (isFrontStack(stack)) { + resumeTopActivitiesLocked(); + } } } mGoingToSleepActivities.clear(); @@ -2193,8 +2289,11 @@ public final class ActivityStackSupervisor { if (!mSleepTimeout) { boolean dontSleep = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked(); + } } if (mStoppingActivities.size() > 0) { @@ -2217,8 +2316,11 @@ public final class ActivityStackSupervisor { } } - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).goToSleep(); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).goToSleep(); + } } removeSleepTimeouts(); @@ -2245,37 +2347,45 @@ public final class ActivityStackSupervisor { } void handleAppCrashLocked(ProcessRecord app) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.handleAppCrashLocked(app); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.handleAppCrashLocked(app); + } } } void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) { // First the front stacks. In case any are not fullscreen and are in front of home. boolean showHomeBehindStack = false; - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (isFrontStack(stack)) { - showHomeBehindStack = - stack.ensureActivitiesVisibleLocked(starting, configChanges); - } - } - // Now do back stacks. - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - if (!isFrontStack(stack)) { - stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int topStackNdx = stacks.size() - 1; + for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + if (stackNdx == topStackNdx) { + // Top stack. + showHomeBehindStack = + stack.ensureActivitiesVisibleLocked(starting, configChanges); + } else { + // Back stack. + stack.ensureActivitiesVisibleLocked(starting, configChanges, + showHomeBehindStack); + } } } } void scheduleDestroyAllActivities(ProcessRecord app, String reason) { - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - stack.scheduleDestroyActivities(app, false, reason); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + stack.scheduleDestroyActivities(app, false, reason); + } } } @@ -2285,8 +2395,11 @@ public final class ActivityStackSupervisor { mCurrentUser = userId; mStartingUsers.add(uss); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - mStacks.get(stackNdx).switchUserLocked(userId); + for (int displayNdx = mDisplayInfos.size() - 1; displayNdx >= 0; --displayNdx) { + final ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + stacks.get(stackNdx).switchUserLocked(userId); + } } ActivityStack stack = getStack(restoreStackId); @@ -2340,8 +2453,9 @@ public final class ActivityStackSupervisor { } void validateTopActivitiesLocked() { - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); + // FIXME +/* for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); final ActivityRecord r = stack.topRunningActivityLocked(null); final ActivityState state = r == null ? ActivityState.DESTROYED : r.state; if (isFrontStack(stack)) { @@ -2371,23 +2485,14 @@ public final class ActivityStackSupervisor { } } } - } - - private static String stackStateToString(int stackState) { - switch (stackState) { - case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT"; - case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK"; - case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK"; - case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT"; - default: return "Unknown stackState=" + stackState; - } +*/ } public void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity="); pw.println(mDismissKeyguardOnNextActivity); pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack); - pw.print(" mStackState="); pw.println(stackStateToString(mStackState)); + pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack); pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout); pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId); pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront); @@ -2416,42 +2521,48 @@ public final class ActivityStackSupervisor { boolean dumpClient, String dumpPackage) { boolean printed = false; boolean needSep = false; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { - final ActivityStack stack = mStacks.get(stackNdx); - StringBuilder stackHeader = new StringBuilder(128); - stackHeader.append(" Stack #"); - stackHeader.append(mStacks.indexOf(stack)); - stackHeader.append(":"); - printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep, - stackHeader.toString()); - printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, !dumpAll, - false, dumpPackage, true, " Running activities (most recent first):", null); - - needSep = printed; - boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, - " mPausingActivity: "); - if (pr) { - printed = true; - needSep = false; - } - pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, - " mResumedActivity: "); - if (pr) { - printed = true; - needSep = false; - } - if (dumpAll) { - pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, - " mLastPausedActivity: "); + for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) { + ActivityDisplayInfo info = mDisplayInfos.valueAt(displayNdx); + pw.print("Display #"); pw.println(info.mDisplayId); + ArrayList<ActivityStack> stacks = info.stacks; + final int numStacks = stacks.size(); + for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + final ActivityStack stack = stacks.get(stackNdx); + StringBuilder stackHeader = new StringBuilder(128); + stackHeader.append(" Stack #"); + stackHeader.append(stack.mStackId); + stackHeader.append(":"); + printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, + needSep, stackHeader.toString()); + printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false, + !dumpAll, false, dumpPackage, true, + " Running activities (most recent first):", null); + + needSep = printed; + boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep, + " mPausingActivity: "); + if (pr) { + printed = true; + needSep = false; + } + pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep, + " mResumedActivity: "); if (pr) { printed = true; - needSep = true; + needSep = false; } - printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, - needSep, " mLastNoHistoryActivity: "); + if (dumpAll) { + pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep, + " mLastPausedActivity: "); + if (pr) { + printed = true; + needSep = true; + } + printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage, + needSep, " mLastNoHistoryActivity: "); + } + needSep = printed; } - needSep = printed; } printed |= dumpHistoryList(fd, pw, mFinishingActivities, " ", "Fin", false, !dumpAll, @@ -2581,6 +2692,95 @@ public final class ActivityStackSupervisor { mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT); } + @Override + public void onDisplayAdded(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0)); + } + + @Override + public void onDisplayRemoved(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0)); + } + + @Override + public void onDisplayChanged(int displayId) { + mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0)); + } + + public void handleDisplayAddedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = new ActivityDisplayInfo(displayId); + mDisplayInfos.put(displayId, info); + } + mWindowManager.onDisplayAdded(displayId); + } + + public void handleDisplayRemovedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = mDisplayInfos.get(displayId); + if (info != null) { + ArrayList<ActivityStack> stacks = info.stacks; + for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { + info.detachActivities(stacks.get(stackNdx)); + } + mDisplayInfos.remove(displayId); + } + } + mWindowManager.onDisplayRemoved(displayId); + } + + public void handleDisplayChangedLocked(int displayId) { + synchronized (mService) { + ActivityDisplayInfo info = mDisplayInfos.get(displayId); + if (info != null) { + // TODO: Update the bounds. + } + } + mWindowManager.onDisplayChanged(displayId); + } + + 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 getStackInfoLocked(int stackId) { + ActivityStack stack = getStack(stackId); + if (stack != null) { + return getStackInfo(stack); + } + return null; + } + + ArrayList<StackInfo> getAllStackInfosLocked() { + ArrayList<StackInfo> list = new ArrayList<StackInfo>(); + for (int displayNdx = 0; displayNdx < mDisplayInfos.size(); ++displayNdx) { + ArrayList<ActivityStack> stacks = mDisplayInfos.valueAt(displayNdx).stacks; + for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) { + list.add(getStackInfo(stacks.get(ndx))); + } + } + return list; + } + private final class ActivityStackSupervisorHandler extends Handler { public ActivityStackSupervisorHandler(Looper looper) { @@ -2644,7 +2844,131 @@ public final class ActivityStackSupervisor { } } } break; + case HANDLE_DISPLAY_ADDED: { + handleDisplayAddedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_CHANGED: { + handleDisplayChangedLocked(msg.arg1); + } break; + case HANDLE_DISPLAY_REMOVED: { + handleDisplayRemovedLocked(msg.arg1); + } break; + } + } + } + + class ActivityContainer extends IActivityContainer.Stub { + final int mStackId; + final IActivityContainerCallback mCallback; + final ActivityStack mStack; + final ActivityRecord mParentActivity; + + /** Display this ActivityStack is currently on. Null if not attached to a Display. */ + ActivityDisplayInfo mActivityDisplayInfo; + + ActivityContainer(ActivityRecord parentActivity, int stackId, + IActivityContainerCallback callback) { + synchronized (mService) { + mStackId = stackId; + mStack = new ActivityStack(this); + mParentActivity = parentActivity; + mCallback = callback; + } + } + + void attachToDisplayLocked(ActivityDisplayInfo displayInfo) { + mActivityDisplayInfo = displayInfo; + displayInfo.attachActivities(mStack); + mWindowManager.createStack(mStackId, displayInfo.mDisplayId); + } + + @Override + public void attachToDisplay(int displayId) throws RemoteException { + synchronized (mService) { + ActivityDisplayInfo displayInfo = mDisplayInfos.get(displayId); + if (displayInfo == null) { + return; + } + attachToDisplayLocked(displayInfo); + } + } + + @Override + public int getStackId() throws RemoteException { + return mStack.mStackId; + } + + void detachLocked() { + if (mActivityDisplayInfo != null) { + mActivityDisplayInfo.detachActivities(mStack); + mActivityDisplayInfo = null; + } + } + + @Override + public void detachFromDisplay() throws RemoteException { + synchronized (mService) { + detachLocked(); } } + + @Override + public void startActivity(Intent intent) throws RemoteException { + + } + + @Override + public IBinder asBinder() { + return this; + } + + ActivityStackSupervisor getOuter() { + return ActivityStackSupervisor.this; + } + + boolean isAttached() { + return mActivityDisplayInfo != null; + } + + void getBounds(Point outBounds) { + if (mActivityDisplayInfo != null) { + mActivityDisplayInfo.getBounds(outBounds); + } else { + outBounds.set(0, 0); + } + } + } + + /** Exactly one of these classes per Display in the system. Capable of holding zero or more + * attached {@link ActivityStack}s */ + final class ActivityDisplayInfo { + /** Actual Display this object tracks. */ + final int mDisplayId; + final Display mDisplay; + final DisplayInfo mDisplayInfo = new DisplayInfo(); + + /** All of the stacks on this display. Order matters, topmost stack is in front of all other + * stacks, bottommost behind. Accessed directly by ActivityManager package classes */ + final ArrayList<ActivityStack> stacks = new ArrayList<ActivityStack>(); + + ActivityDisplayInfo(int displayId) { + mDisplayId = displayId; + mDisplay = mDisplayManager.getDisplay(displayId); + mDisplay.getDisplayInfo(mDisplayInfo); + } + + void attachActivities(ActivityStack stack) { + stacks.add(stack); + } + + void detachActivities(ActivityStack stack) { + stacks.remove(stack); + } + + void getBounds(Point bounds) { + mDisplay.getDisplayInfo(mDisplayInfo); + bounds.x = mDisplayInfo.appWidth; + bounds.y = mDisplayInfo.appHeight; + } } } diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index 80e6e9497ece..cb04835dce53 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -18,7 +18,8 @@ package com.android.server.am; 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 class ServiceRecord extends Binder { 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 @@ final class ServiceRecord extends Binder { 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 3d568ffb8e07..9105103ac632 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -159,18 +159,33 @@ final class TaskRecord extends ThumbnailHolder { 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; activityNdx < numActivities; ++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 index 203cca692df0..6fd8871c2185 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 @@ import java.util.Locale; /** * 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 @@ class AppWidgetService extends IAppWidgetService.Stub 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 index 69ae846597f7..98dead312469 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 index 00bfee78bfbb..c2b0d10cff49 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.BackupConstants; 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.IvParameterSpec; 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 @@ class BackupManagerService extends IBackupManager.Stub { // 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 @@ class BackupManagerService extends IBackupManager.Stub { 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 index 77bddb0717ec..495da886fa65 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 index 8cf273dee8cc..26e2e2ac356c 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.app.backup.WallpaperBackupHelper; 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 class SystemBackupAgent extends BackupAgentHelper { 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 @@ public class SystemBackupAgent extends BackupAgentHelper { 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 @@ public class SystemBackupAgent extends BackupAgentHelper { 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 index 069ae23f5596..6aa596d9d78e 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 index 2bb99d68ed77..af362467aa84 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 @@ import java.util.Set; */ 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { }; 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } catch (InterruptedException e1) { - Log.w(TAG, "installCaCertsToKeyChain(): ", e1); + Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1); Thread.currentThread().interrupt(); } return false; @@ -2134,10 +2159,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 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 bcb677fa455f..73040d5e2734 100644 --- a/services/java/com/android/server/display/DisplayManagerService.java +++ b/services/java/com/android/server/display/DisplayManagerService.java @@ -102,7 +102,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub { // 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 @@ public final class DisplayManagerService extends IDisplayManager.Stub { 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 final class DisplayManagerService extends IDisplayManager.Stub { 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 @@ public final class DisplayManagerService extends IDisplayManager.Stub { } /** - * 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 @@ public final class DisplayManagerService extends IDisplayManager.Stub { 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 @@ public final class DisplayManagerService extends IDisplayManager.Stub { 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 7a104d7e5a8a..000000000000 --- 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 000000000000..b496b4c6ce8c --- /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 000000000000..2f20509dddf5 --- /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 index 89bfcacd8cac..d81478500a9f 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 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 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 class LightsService extends SystemService { + static final String TAG = "LightsService"; + static final boolean DEBUG = false; - private final Light mLights[] = new Light[LIGHT_ID_COUNT]; + final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; - public final class Light { + private final class LightImpl extends 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 @@ public class LightsService { } } + @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 @@ public class LightsService { } } + @Override public void turnOff() { synchronized (this) { setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0); @@ -153,9 +136,10 @@ public class LightsService { } 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 @@ public class LightsService { } }; - 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 @@ public class LightsService { 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 000000000000..df2aaca49eca --- /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 000000000000..92ffdccb50f0 --- /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 index 04386759df50..db4cf31d7dad 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.content.res.Resources; 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.IBinder; 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 android.widget.Toast; 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 java.util.Set; 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; - final IBinder mForegroundToken = new Binder(); + 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 int mDefaultNotificationLedOff; private long[] mDefaultVibrationPattern; - private long[] mFallbackVibrationPattern; - - private boolean mSystemReady; - private int mDisabledNotifications; - private NotificationRecord mSoundNotification; - private NotificationRecord mVibrateNotification; + private long[] mFallbackVibrationPattern; + boolean mSystemReady; - 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - /** - * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub /** * 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 @@ public class NotificationManagerService extends INotificationManager.Stub /** * 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - 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 @@ public class NotificationManagerService extends INotificationManager.Stub // 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } + @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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub true, ActivityManager.getCurrentUser()); } + @Override public void onPanelRevealed() { synchronized (mNotificationList) { // sound @@ -1089,7 +919,7 @@ public class NotificationManagerService extends INotificationManager.Stub long identity = Binder.clearCallingIdentity(); try { - final IRingtonePlayer player = mAudioService.getRingtonePlayer(); + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); if (player != null) { player.stopAsync(); } @@ -1114,6 +944,7 @@ public class NotificationManagerService extends INotificationManager.Stub } } + @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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } 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 class NotificationManagerService extends INotificationManager.Stub } 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub // 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e); } } + + publishBinderService(Context.NOTIFICATION_SERVICE, mService); + publishLocalService(NotificationManagerInternal.class, mInternalService); } /** @@ -1383,12 +1213,12 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } } - 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(); + // 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); + void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) { + 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); - if (pkg == null || callback == null) { - Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback); - return ; + // 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)); } + } - final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg)); + private final IBinder mService = new INotificationManager.Stub() { + // Toasts + // ============================================================================ - if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) { - if (!isSystemToast) { - Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request."); - return; + @Override + public void enqueueToast(String pkg, ITransientNotification callback, int duration) + { + if (DBG) { + Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + + " duration=" + duration); } - } - 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; + 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 ; + } - record = new ToastRecord(callingPid, pkg, callback, duration); - mToastQueue.add(record); - index = mToastQueue.size() - 1; - keepProcessAliveLocked(callingPid); + 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); } - // 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(); + } + } + + @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; + } } - } finally { - Binder.restoreCallingIdentity(callingId); } + return tmp; } - } - public void cancelToast(String pkg, ITransientNotification callback) { - Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback); + /** + * 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; + } - if (pkg == null || callback == null) { - Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback); - return ; + /** + * 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); } - synchronized (mToastQueue) { - long callingId = Binder.clearCallingIdentity(); + /** + * 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 { - int index = indexOfToastLocked(pkg, callback); - if (index >= 0) { - cancelToastLocked(index); - } else { - Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback); - } + cancelAll(info.userid); } finally { - Binder.restoreCallingIdentity(callingId); + Binder.restoreCallingIdentity(identity); } } - } - private void showNextToastLocked() { - ToastRecord record = mToastQueue.get(0); - while (record != null) { - if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); + /** + * 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 { - 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; + 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); } - } - 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 + @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); } - 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(); + }; + + 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); } - } - 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); - } + pw.println(" Live listeners (" + mListeners.size() + "):"); + for (NotificationListenerInfo info : mListeners) { + pw.println(" " + info.component + + " (user " + info.userid + "): " + info.listener + + (info.isSystem?" SYSTEM":"")); + } + + int N; - 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); + N = mToastQueue.size(); + if (N > 0) { + pw.println(" Toast Queue:"); + for (int i=0; i<N; i++) { + mToastQueue.get(i).dump(pw, " "); + } + pw.println(" "); } + } - } - // 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; + 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(" "); } - } - 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++; + N = mLights.size(); + if (N > 0) { + pw.println(" Lights List:"); + for (int i=0; i<N; i++) { + pw.println(" " + mLights.get(i)); + } + pw.println(" "); } - } - 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); + 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; + } } - } - } - - // 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) + /** + * 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); + } + }; - 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub } 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub (notification.defaults & Notification.DEFAULT_VIBRATE) != 0; if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate) - && !(audioManager.getRingerMode() + && !(mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) { mVibrateNotification = r; @@ -1966,8 +1972,158 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub // 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 @@ public class NotificationManagerService extends INotificationManager.Stub * 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 class NotificationManagerService extends INotificationManager.Stub } } - 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 @@ public class NotificationManagerService extends INotificationManager.Stub } // lock on mNotificationList - private void updateLightsLocked() + void updateLightsLocked() { // handle notification lights if (mLedNotification == null) { @@ -2251,14 +2387,14 @@ public class NotificationManagerService extends INotificationManager.Stub } 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 @@ public class NotificationManagerService extends INotificationManager.Stub 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 5761f6c07adb..b11ebf5bd5d5 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.content.PackageHelper; 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.VerificationParams; 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.Slog; 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.Libcore; 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 @@ public class PackageManagerService extends IPackageManager.Stub { 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 f93ba2fe9c59..89169264b0b6 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 index a7af252ca2ed..f437372e31a0 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 60d44c78e5b6..b8a78e34b1a1 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 @@ final class DisplayPowerController { 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 @@ final class DisplayPowerController { * 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 @@ final class DisplayPowerController { 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 @@ final class DisplayPowerController { } }; - 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 fa318f8b6198..42af4b48bde9 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 @@ final class DisplayPowerState { 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 @@ final class DisplayPowerState { 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 da9548f7266e..13f55e2e4c54 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.IAppOpsService; 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 @@ public final class PowerManagerService extends IPowerManager.Stub 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 @@ public final class PowerManagerService extends IPowerManager.Stub 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 @@ public final class PowerManagerService extends IPowerManager.Stub * 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 final class PowerManagerService extends IPowerManager.Stub } } - 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 @@ public final class PowerManagerService extends IPowerManager.Stub // 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 @@ public final class PowerManagerService extends IPowerManager.Stub 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 @@ public final class PowerManagerService extends IPowerManager.Stub } private void setAttentionLightInternal(boolean on, int color) { - LightsService.Light light; + Light light; synchronized (mLock) { if (!mSystemReady) { return; @@ -2070,7 +2071,7 @@ public final class PowerManagerService extends IPowerManager.Stub } // 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 000000000000..4f7518966681 --- /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 index f207c08c579c..2ae467eabdd1 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 @@ import java.util.Map; public class StatusBarManagerService extends IStatusBarService.Stub implements WindowManagerService.OnHardKeyboardStatusChangeListener { - static final String TAG = "StatusBarManagerService"; - 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 static final String TAG = "StatusBarManagerService"; + private static final boolean SPEW = false; + + 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 class StatusBarManagerService extends IStatusBarService.Stub } } - 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 @@ public class StatusBarManagerService extends IStatusBarService.Stub final Resources res = context.getResources(); mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons)); - } - public void setNotificationCallbacks(NotificationCallbacks listener) { - mNotificationCallbacks = listener; + LocalServices.addService(StatusBarManagerInternal.class, mInternalService); } + /** + * 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 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void collapsePanels() { enforceExpandStatusBar(); @@ -141,6 +193,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void expandSettingsPanel() { enforceExpandStatusBar(); @@ -152,6 +205,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void disable(int what, IBinder token, String pkg) { disableInternal(mCurrentUserId, what, token, pkg); } @@ -177,7 +231,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub mDisabled = net; mHandler.post(new Runnable() { public void run() { - mNotificationCallbacks.onSetDisabled(net); + mNotificationDelegate.onSetDisabled(net); } }); if (mBar != null) { @@ -189,6 +243,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription) { enforceStatusBar(); @@ -214,6 +269,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setIconVisibility(String slot, boolean visible) { enforceStatusBar(); @@ -241,6 +297,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void removeIcon(String slot) { enforceStatusBar(); @@ -265,6 +322,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub * 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 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) { enforceStatusBar(); @@ -312,6 +371,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setSystemUiVisibility(int vis, int mask) { // also allows calls from window manager which is in this process. enforceStatusBarService(); @@ -344,6 +404,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + @Override public void setHardKeyboardEnabled(final boolean enabled) { mHandler.post(new Runnable() { public void run() { @@ -426,6 +487,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ // 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 @@ public class StatusBarManagerService extends IStatusBarService.Stub * 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 000000000000..a91a81b3bffc --- /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 index 016c561077dc..88050841698f 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.Binder; 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 @@ import java.io.PrintWriter; * 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { /** * 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 @@ public class DeviceStorageMonitorService extends Binder { } }; - 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 @@ public class DeviceStorageMonitorService extends Binder { } } - private final void restatDataDir() { + private void restatDataDir() { try { mDataFileStats.restat(DATA_PATH.getAbsolutePath()); mFreeMem = (long) mDataFileStats.getAvailableBlocks() * @@ -206,7 +208,7 @@ public class DeviceStorageMonitorService extends Binder { } } - private final void clearCache() { + private void clearCache() { if (mClearCacheObserver == null) { // Lazy instantiation mClearCacheObserver = new CachePackageDataObserver(); @@ -223,7 +225,7 @@ public class DeviceStorageMonitorService extends Binder { } } - 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { * 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { * 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 @@ public class DeviceStorageMonitorService extends Binder { 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 @@ public class DeviceStorageMonitorService extends Binder { 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 000000000000..29ead445892e --- /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 000000000000..b3de58b279af --- /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 index 0356faa610f5..8feb97b36f46 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.DateUtils; 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 @@ import libcore.util.Objects; * 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; + @Override + public void onStart() { + mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); + mLocationManager = (LocationManager) getContext().getSystemService( + Context.LOCATION_SERVICE); + mLocationHandler = new LocationHandler(); - public TwilightService(Context context) { - mContext = context; + 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); - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); - mLocationHandler = new LocationHandler(); + 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); } - } - /** - * Gets the current twilight state. - * - * @return The current twilight state, or null if no information is available. - */ - public TwilightState getCurrentState() { - synchronized (mLock) { - return mTwilightState; + @Override + public void run() { + mListener.onTwilightStateChanged(); } + } - /** - * 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)); + 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; + } + } - if (mSystemReady && mListeners.size() == 1) { - mLocationHandler.enableLocationUpdates(); + /** + * Listens for twilight time. + * + * @param listener The listener. + */ + @Override + public void registerListener(TwilightListener listener, Handler handler) { + synchronized (mLock) { + mListeners.add(new TwilightListenerRecord(listener, handler)); + + if (mListeners.size() == 1) { + mLocationHandler.enableLocationUpdates(); + } } } - } + }; private void setTwilightState(TwilightState state) { synchronized (mLock) { @@ -128,9 +139,10 @@ public final class TwilightService { } 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 @@ public final class TwilightService { 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 @@ public final class TwilightService { } 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 000000000000..91e24d7d55bf --- /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 index e6b6b93a1d46..97ea52c0a4a2 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.content.PackageMonitor; 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 @@ class WallpaperManagerService extends IWallpaperManager.Stub { 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 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } } - 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 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } // 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 c189ddd86c14..978d5b742ee5 100644 --- a/services/java/com/android/server/wm/DimLayer.java +++ b/services/java/com/android/server/wm/DimLayer.java @@ -166,7 +166,7 @@ public class DimLayer { 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 d358b4c6ed67..40643774c14d 100644 --- a/services/java/com/android/server/wm/DisplayContent.java +++ b/services/java/com/android/server/wm/DisplayContent.java @@ -21,14 +21,13 @@ import static com.android.server.wm.WindowManagerService.DEBUG_STACK; 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; import android.view.DisplayInfo; +import android.view.Surface; import com.android.server.EventLogTags; import java.io.PrintWriter; @@ -74,6 +73,7 @@ class DisplayContent { private final Display mDisplay; Rect mBaseDisplayRect = new Rect(); + Rect mContentRect = new Rect(); // Accessed directly by all users. boolean layoutNeeded; @@ -92,11 +92,12 @@ class DisplayContent { */ 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 +124,6 @@ class DisplayContent { 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 +149,6 @@ class DisplayContent { return mDisplay.hasAccess(uid); } - boolean homeOnTop() { - return mStackBoxes.get(0).mStack != mHomeStack; - } - public boolean isPrivate() { return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0; } @@ -205,16 +195,32 @@ class DisplayContent { } 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) { updateDisplayInfo(); // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked. + final int orientation = mDisplayInfo.rotation; + boolean rotated = (orientation == Surface.ROTATION_90 + || orientation == Surface.ROTATION_270); + final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; + final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; int width = mDisplayInfo.logicalWidth; - int left = (mBaseDisplayWidth - width) / 2; + int left = (physWidth - width) / 2; int height = mDisplayInfo.logicalHeight; - int top = (mBaseDisplayHeight - height) / 2; + int top = (physHeight - height) / 2; out.set(left, top, left + width, top + height); } @@ -227,159 +233,62 @@ class DisplayContent { 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; - 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; + void moveStack(TaskStack stack, boolean toTop) { + mStacks.remove(stack); + mStacks.add(toTop ? mStacks.size() : 0, stack); } - 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!"); + TaskStack removeStack(TaskStack stack) { + mStacks.remove(stack); + if (!mStacks.isEmpty()) { + return mStacks.get(mStacks.size() - 1); } + return null; } /** - * Propagate the new bounds to all child stack boxes, applying weights as we move down. + * Propagate the new bounds to all child stacks. * @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; + void resize(Rect contentRect) { + mContentRect.set(contentRect); } - 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; + 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 null; + return false; } int stackIdFromPoint(int x, int y) { - StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1); - return topBox.stackIdFromPoint(x, 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 -1; } void setTouchExcludeRegion(TaskStack focusedStack) { @@ -408,48 +317,48 @@ class DisplayContent { } } - 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 +386,10 @@ class DisplayContent { 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 cc48b867f6df..f1f5fe88cc85 100644 --- a/services/java/com/android/server/wm/FocusedStackFrame.java +++ b/services/java/com/android/server/wm/FocusedStackFrame.java @@ -41,7 +41,7 @@ class FocusedStackFrame { 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 @@ class FocusedStackFrame { } } - 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 3d2ec4577acf..803b9acac3d9 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -58,6 +58,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private final Object mInputDevicesReadyMonitor = new Object(); private boolean mInputDevicesReady; + Rect mTmpRect = new Rect(); + public InputMonitor(WindowManagerService service) { mService = service; } @@ -175,7 +177,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { 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 d351925015ee..000000000000 --- 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 cb29df474874..ef245f9d123a 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.Slog; 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 @@ public class TaskStack { * 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 @@ public class TaskStack { 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 @@ public class TaskStack { 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 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 hasSibling() { - return mStackBox.mParent != null; + 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 @@ public class TaskStack { * @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 @@ public class TaskStack { 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 @@ public class TaskStack { */ 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,11 @@ public class TaskStack { mAnimationBackgroundSurface.destroySurface(); mDimLayer.destroySurface(); EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId); - return mStackBox.remove(); + TaskStack next = mDisplayContent.removeStack(this); + if (next != null) { + return next.mStackId; + } + return -1; } void resetAnimationBackgroundAnimator() { @@ -259,28 +314,6 @@ public class TaskStack { } } - 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 +326,11 @@ public class TaskStack { } } + 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 f9773a6f25cf..04129e211c2e 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.PowerManagerService; 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub 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 @@ public class WindowManagerService extends IWindowManager.Stub } 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 @@ public class WindowManagerService extends IWindowManager.Stub /** * 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); } } @@ -4863,7 +4842,9 @@ public class WindowManagerService extends IWindowManager.Stub int nextStackId = stack.remove(); stack.getDisplayContent().layoutNeeded = true; requestTraversalLocked(); - return nextStackId; + if (nextStackId > HOME_STACK_ID) { + return nextStackId; + } } if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId); } @@ -4898,40 +4879,27 @@ public class WindowManagerService extends IWindowManager.Stub } } - 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."); + } + if (stack.setBounds(bounds)) { + stack.getDisplayContent().layoutNeeded = true; + performLayoutAndPlaceSurfacesLocked(); } - } - throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId - + " not found."); - } - - public ArrayList<StackBoxInfo> getStackBoxInfos() { - synchronized(mWindowMap) { - return getDefaultDisplayContentLocked().getStackBoxInfos(); } } - 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 +5227,7 @@ public class WindowManagerService extends IWindowManager.Stub public void performBootTimeout() { synchronized(mWindowMap) { - if (mDisplayEnabled || mHeadless) { + if (mDisplayEnabled) { return; } Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); @@ -5443,7 +5411,6 @@ public class WindowManagerService extends IWindowManager.Stub // 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 +5556,7 @@ public class WindowManagerService extends IWindowManager.Stub continue; } appWin = ws; - stackBounds.set(ws.getStackBounds()); + ws.getStackBounds(stackBounds); } } @@ -8218,7 +8185,7 @@ public class WindowManagerService extends IWindowManager.Stub } mPolicy.getContentRectLw(mTmpContentRect); - displayContent.setStackBoxSize(mTmpContentRect); + displayContent.resize(mTmpContentRect); int seq = mLayoutSeq+1; if (seq < 0) seq = 0; @@ -8813,7 +8780,8 @@ public class WindowManagerService extends IWindowManager.Stub if (canBeSeen) { // This function assumes that the contents of the default display are // processed first before secondary displays. - if (w.mDisplayContent.isDefaultDisplay) { + final DisplayContent displayContent = w.mDisplayContent; + if (displayContent.isDefaultDisplay) { // While a dream or keyguard is showing, obscure ordinary application // content on secondary displays (by forcibly enabling mirroring unless // there is other content we want to show) but still allow opaque diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 4d53cea4370d..e6c1e98b0547 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -463,8 +463,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { 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 @@ final class WindowState implements WindowManagerPolicy.WindowState { 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 98e9b3085736..a98b1c3b95ae 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -8,7 +8,7 @@ LOCAL_SRC_FILES:= \ 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 index 401e1aaf8851..ea03cfa1b147 100644 --- a/services/jni/com_android_server_LightsService.cpp +++ b/services/jni/com_android_server_lights_LightsService.cpp @@ -134,7 +134,7 @@ static JNINativeMethod method_table[] = { 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)); } |