summaryrefslogtreecommitdiffstats
path: root/services/java/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android')
-rw-r--r--services/java/com/android/server/AppWidgetService.java151
-rw-r--r--services/java/com/android/server/AppWidgetServiceImpl.java27
-rw-r--r--services/java/com/android/server/BatteryService.java98
-rwxr-xr-xservices/java/com/android/server/BluetoothManagerService.java5
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java8
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java8
-rw-r--r--services/java/com/android/server/LocationManagerService.java220
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java13
-rw-r--r--services/java/com/android/server/ServiceWatcher.java85
-rw-r--r--services/java/com/android/server/StatusBarManagerService.java2
-rw-r--r--services/java/com/android/server/TextServicesManagerService.java259
-rw-r--r--services/java/com/android/server/UiModeManagerService.java19
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java51
-rw-r--r--services/java/com/android/server/WiredAccessoryManager.java2
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java26
-rw-r--r--services/java/com/android/server/accessibility/ScreenMagnifier.java34
-rw-r--r--services/java/com/android/server/accessibility/TouchExplorer.java186
-rw-r--r--services/java/com/android/server/am/ActiveServices.java33
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java221
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java4
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java27
-rw-r--r--services/java/com/android/server/am/AppErrorDialog.java8
-rw-r--r--services/java/com/android/server/am/AppNotRespondingDialog.java12
-rw-r--r--services/java/com/android/server/am/AppWaitingForDebuggerDialog.java5
-rw-r--r--services/java/com/android/server/am/BaseErrorDialog.java4
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java52
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java10
-rw-r--r--services/java/com/android/server/am/FactoryErrorDialog.java5
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java2
-rw-r--r--services/java/com/android/server/am/UserStartedState.java14
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java3
-rw-r--r--services/java/com/android/server/display/DisplayDevice.java12
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java67
-rw-r--r--services/java/com/android/server/display/LocalDisplayAdapter.java14
-rw-r--r--services/java/com/android/server/dreams/DreamController.java11
-rw-r--r--services/java/com/android/server/location/GeocoderProxy.java9
-rw-r--r--services/java/com/android/server/location/GeofenceManager.java6
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java5
-rw-r--r--services/java/com/android/server/location/LocationBlacklist.java38
-rw-r--r--services/java/com/android/server/location/LocationProviderInterface.java2
-rw-r--r--services/java/com/android/server/location/LocationProviderProxy.java14
-rw-r--r--services/java/com/android/server/location/MockProvider.java5
-rw-r--r--services/java/com/android/server/location/PassiveProvider.java5
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java219
-rw-r--r--services/java/com/android/server/pm/PreferredActivity.java15
-rw-r--r--services/java/com/android/server/pm/PreferredIntentResolver.java38
-rw-r--r--services/java/com/android/server/pm/Settings.java143
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java7
-rw-r--r--services/java/com/android/server/power/DisplayBlanker.java25
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java200
-rw-r--r--services/java/com/android/server/power/DisplayPowerRequest.java18
-rw-r--r--services/java/com/android/server/power/DisplayPowerState.java23
-rw-r--r--services/java/com/android/server/power/ElectronBeam.java91
-rw-r--r--services/java/com/android/server/power/Notifier.java94
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java307
-rw-r--r--services/java/com/android/server/power/ScreenOnBlocker.java41
-rw-r--r--services/java/com/android/server/wm/AppWindowToken.java1
-rw-r--r--services/java/com/android/server/wm/InputMonitor.java23
-rw-r--r--services/java/com/android/server/wm/Session.java15
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java190
-rw-r--r--services/java/com/android/server/wm/WindowState.java49
-rw-r--r--services/java/com/android/server/wm/WindowStateAnimator.java6
62 files changed, 2315 insertions, 972 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 9be7045..c18fe0e 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -17,34 +17,28 @@
package com.android.server;
import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.widget.RemoteViews;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.widget.IRemoteViewsAdapterConnection;
+import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -56,85 +50,11 @@ class AppWidgetService extends IAppWidgetService.Stub
{
private static final String TAG = "AppWidgetService";
- /*
- * When identifying a Host or Provider based on the calling process, use the uid field.
- * When identifying a Host or Provider based on a package manager broadcast, use the
- * package given.
- */
-
- static class Provider {
- int uid;
- AppWidgetProviderInfo info;
- ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
- PendingIntent broadcast;
- boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-
- int tag; // for use while saving state (the index)
- }
-
- static class Host {
- int uid;
- int hostId;
- String packageName;
- ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>();
- IAppWidgetHost callbacks;
- boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
-
- int tag; // for use while saving state (the index)
- }
-
- static class AppWidgetId {
- int appWidgetId;
- Provider provider;
- RemoteViews views;
- Host host;
- }
-
- /**
- * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection.
- * This needs to be a static inner class since a reference to the ServiceConnection is held
- * globally and may lead us to leak AppWidgetService instances (if there were more than one).
- */
- static class ServiceConnectionProxy implements ServiceConnection {
- private final IBinder mConnectionCb;
-
- ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) {
- mConnectionCb = connectionCb;
- }
- public void onServiceConnected(ComponentName name, IBinder service) {
- final IRemoteViewsAdapterConnection cb =
- IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
- try {
- cb.onServiceConnected(service);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public void onServiceDisconnected(ComponentName name) {
- disconnect();
- }
- public void disconnect() {
- final IRemoteViewsAdapterConnection cb =
- IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb);
- try {
- cb.onServiceDisconnected();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
Context mContext;
Locale mLocale;
PackageManager mPackageManager;
- AlarmManager mAlarmManager;
- ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>();
- int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1;
- final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>();
- ArrayList<Host> mHosts = new ArrayList<Host>();
boolean mSafeMode;
-
private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
AppWidgetService(Context context) {
@@ -195,9 +115,16 @@ class AppWidgetService extends IAppWidgetService.Stub
}, UserHandle.ALL, userFilter, null, null);
}
+ /**
+ * This returns the user id of the caller, if the caller is not the system process,
+ * otherwise it assumes that the calls are from the lockscreen and hence are meant for the
+ * current user. TODO: Instead, have lockscreen make explicit calls with userId
+ */
private int getCallingOrCurrentUserId() {
int callingUid = Binder.getCallingUid();
- if (callingUid == android.os.Process.myUid()) {
+ // Also check the PID because Settings (power control widget) also runs as System UID
+ if (callingUid == android.os.Process.myUid()
+ && Binder.getCallingPid() == android.os.Process.myPid()) {
try {
return ActivityManagerNative.getDefault().getCurrentUser().id;
} catch (RemoteException re) {
@@ -272,13 +199,16 @@ class AppWidgetService extends IAppWidgetService.Stub
}
public void onUserRemoved(int userId) {
- AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
if (userId < 1) return;
-
- if (impl == null) {
- AppWidgetServiceImpl.getSettingsFile(userId).delete();
- } else {
- impl.onUserRemoved();
+ synchronized (mAppWidgetServices) {
+ AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+ mAppWidgetServices.remove(userId);
+
+ if (impl == null) {
+ AppWidgetServiceImpl.getSettingsFile(userId).delete();
+ } else {
+ impl.onUserRemoved();
+ }
}
}
@@ -286,17 +216,23 @@ class AppWidgetService extends IAppWidgetService.Stub
}
private AppWidgetServiceImpl getImplForUser(int userId) {
- AppWidgetServiceImpl service = mAppWidgetServices.get(userId);
- if (service == null) {
- Slog.e(TAG, "Unable to find AppWidgetServiceImpl for the current user");
- // TODO: Verify that it's a valid user
- service = new AppWidgetServiceImpl(mContext, userId);
- service.systemReady(mSafeMode);
- // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+ boolean sendInitial = false;
+ AppWidgetServiceImpl service;
+ synchronized (mAppWidgetServices) {
+ service = mAppWidgetServices.get(userId);
+ if (service == null) {
+ Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
+ // TODO: Verify that it's a valid user
+ service = new AppWidgetServiceImpl(mContext, userId);
+ service.systemReady(mSafeMode);
+ // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+ mAppWidgetServices.append(userId, service);
+ sendInitial = true;
+ }
+ }
+ if (sendInitial) {
service.sendInitialBroadcasts();
- mAppWidgetServices.append(userId, service);
}
-
return service;
}
@@ -325,15 +261,6 @@ class AppWidgetService extends IAppWidgetService.Stub
return getImplForUser(getCallingOrCurrentUserId()).getAppWidgetOptions(appWidgetId);
}
- static int[] getAppWidgetIds(Provider p) {
- int instancesSize = p.instances.size();
- int appWidgetIds[] = new int[instancesSize];
- for (int i=0; i<instancesSize; i++) {
- appWidgetIds[i] = p.instances.get(i).appWidgetId;
- }
- return appWidgetIds;
- }
-
@Override
public List<AppWidgetProviderInfo> getInstalledProviders() throws RemoteException {
return getImplForUser(getCallingOrCurrentUserId()).getInstalledProviders();
@@ -378,9 +305,15 @@ class AppWidgetService extends IAppWidgetService.Stub
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
// Dump the state of all the app widget providers
- for (int i = 0; i < mAppWidgetServices.size(); i++) {
- AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
- service.dump(fd, pw, args);
+ synchronized (mAppWidgetServices) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ for (int i = 0; i < mAppWidgetServices.size(); i++) {
+ pw.println("User: " + mAppWidgetServices.keyAt(i));
+ ipw.increaseIndent();
+ AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+ service.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
}
}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index e77f8cf..41617c8 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -87,6 +87,8 @@ class AppWidgetServiceImpl {
private static final String SETTINGS_FILENAME = "appwidgets.xml";
private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes
+ private static boolean DBG = false;
+
/*
* When identifying a Host or Provider based on the calling process, use the uid field. When
* identifying a Host or Provider based on a package manager broadcast, use the package given.
@@ -208,7 +210,12 @@ class AppWidgetServiceImpl {
}
}
+ private void log(String msg) {
+ Slog.i(TAG, "u=" + mUserId + ": " + msg);
+ }
+
void onConfigurationChanged() {
+ if (DBG) log("Got onConfigurationChanged()");
Locale revised = Locale.getDefault();
if (revised == null || mLocale == null || !(revised.equals(mLocale))) {
mLocale = revised;
@@ -235,6 +242,7 @@ class AppWidgetServiceImpl {
}
void onBroadcastReceived(Intent intent) {
+ if (DBG) log("onBroadcast " + intent);
final String action = intent.getAction();
boolean added = false;
boolean changed = false;
@@ -425,7 +433,8 @@ class AppWidgetServiceImpl {
mAppWidgetIds.add(id);
saveStateLocked();
-
+ if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId
+ + " id=" + appWidgetId);
return appWidgetId;
}
}
@@ -518,6 +527,7 @@ class AppWidgetServiceImpl {
}
void cancelBroadcasts(Provider p) {
+ if (DBG) log("cancelBroadcasts for " + p);
if (p.broadcast != null) {
mAlarmManager.cancel(p.broadcast);
long token = Binder.clearCallingIdentity();
@@ -531,6 +541,8 @@ class AppWidgetServiceImpl {
}
private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) {
+ if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId
+ + " provider=" + provider);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mAppWidgetIds) {
@@ -825,12 +837,14 @@ class AppWidgetServiceImpl {
}
public RemoteViews getAppWidgetViews(int appWidgetId) {
+ if (DBG) log("getAppWidgetViews id=" + appWidgetId);
synchronized (mAppWidgetIds) {
ensureStateLoadedLocked();
AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId);
if (id != null) {
return cloneIfLocalBinder(id.views);
}
+ if (DBG) log(" couldn't find appwidgetid");
return null;
}
}
@@ -854,7 +868,7 @@ class AppWidgetServiceImpl {
if (appWidgetIds == null) {
return;
}
-
+ if (DBG) log("updateAppWidgetIds views: " + views);
int bitmapMemoryUsage = 0;
if (views != null) {
bitmapMemoryUsage = views.estimateMemoryUsage();
@@ -1280,8 +1294,8 @@ class AppWidgetServiceImpl {
intent.setComponent(p.info.provider);
long token = Binder.clearCallingIdentity();
try {
- p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1353,7 +1367,7 @@ class AppWidgetServiceImpl {
p.uid = activityInfo.applicationInfo.uid;
Resources res = mContext.getPackageManager()
- .getResourcesForApplication(activityInfo.applicationInfo);
+ .getResourcesForApplicationAsUser(activityInfo.packageName, mUserId);
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AppWidgetProviderInfo);
@@ -1597,8 +1611,7 @@ class AppWidgetServiceImpl {
final IPackageManager packageManager = AppGlobals.getPackageManager();
try {
- packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0,
- UserHandle.getCallingUserId());
+ packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId);
} catch (RemoteException e) {
String[] pkgs = mContext.getPackageManager()
.currentToCanonicalPackageNames(new String[] { pkg });
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 40758d3..dbffa97 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.FileUtils;
+import android.os.Handler;
import android.os.IBinder;
import android.os.DropBoxManager;
import android.os.RemoteException;
@@ -66,6 +67,14 @@ import java.io.PrintWriter;
* <p>&quot;temperature&quot; - int, current battery temperature in tenths of
* a degree Centigrade</p>
* <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
+ *
+ * <p>
+ * The battery service may be called by the power manager while holding its locks so
+ * we take care to post all outcalls into the activity manager to a handler.
+ *
+ * FIXME: Ideally the power manager would perform all of its calls into the battery
+ * service asynchronously itself.
+ * </p>
*/
public final class BatteryService extends Binder {
private static final String TAG = BatteryService.class.getSimpleName();
@@ -89,6 +98,7 @@ public final class BatteryService extends Binder {
private final Context mContext;
private final IBatteryStats mBatteryStats;
+ private final Handler mHandler;
private final Object mLock = new Object();
@@ -137,6 +147,7 @@ public final class BatteryService extends Binder {
public BatteryService(Context context, LightsService lights) {
mContext = context;
+ mHandler = new Handler(true /*async*/);
mLed = new Led(context, lights);
mBatteryStats = BatteryStatsService.getService();
@@ -228,12 +239,18 @@ public final class BatteryService extends Binder {
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
- && ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
- intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ }
+ });
}
}
@@ -241,12 +258,18 @@ public final class BatteryService extends Binder {
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mBatteryTemperature > mShutdownBatteryTemperature
- && ActivityManagerNative.isSystemReady()) {
- Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
- intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ if (mBatteryTemperature > mShutdownBatteryTemperature) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (ActivityManagerNative.isSystemReady()) {
+ Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
+ intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ }
+ }
+ });
}
}
@@ -373,25 +396,47 @@ public final class BatteryService extends Binder {
// Separate broadcast is sent for power connected / not connected
// since the standard intent will not wake any applications and some
// applications may want to have smart behavior based on this.
- Intent statusIntent = new Intent();
- statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (mPlugType != 0 && mLastPlugType == 0) {
- statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
else if (mPlugType == 0 && mLastPlugType != 0) {
- statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
if (sendBatteryLow) {
mSentLowBatteryBroadcast = true;
- statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
} else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
- statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
- mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
+ statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
+ }
+ });
}
// Update the battery LED
@@ -416,7 +461,7 @@ public final class BatteryService extends Binder {
private void sendIntentLocked() {
// Pack up the values and broadcast them to everyone
- Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
@@ -446,7 +491,12 @@ public final class BatteryService extends Binder {
", icon:" + icon + ", invalid charger:" + mInvalidCharger);
}
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ }
+ });
}
private void logBatteryStatsLocked() {
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index ce75e35..e7cd279 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -481,7 +481,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
Intent i = new Intent(IBluetooth.class.getName());
if (!mContext.bindService(i, mConnection,
- Context.BIND_AUTO_CREATE)) {
+ Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
}
@@ -717,7 +717,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
- if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE,
+ UserHandle.USER_CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 9607624..a5e26a8 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -46,6 +46,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -401,6 +402,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if ("disable-camera".equals(tag)) {
disableCamera = Boolean.parseBoolean(
parser.getAttributeValue(null, "value"));
+ } else if ("disable-keyguard-features".equals(tag)) {
+ disabledKeyguardFeatures = Integer.parseInt(
+ parser.getAttributeValue(null, "value"));
} else {
Slog.w(TAG, "Unknown admin tag: " + tag);
}
@@ -457,6 +461,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
pw.println(encryptionRequested);
pw.print(prefix); pw.print("disableCamera=");
pw.println(disableCamera);
+ pw.print(prefix); pw.print("disabledKeyguardFeatures=");
+ pw.println(disabledKeyguardFeatures);
}
}
@@ -1827,7 +1833,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
// Ensure the device is locked
- getWindowManager().lockNow();
+ getWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 22fd508..ffbfef6 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -900,7 +900,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ " calling userId = " + userId + ", foreground user id = "
- + mSettings.getCurrentUserId() + ", calling uid = " + Binder.getCallingPid());
+ + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
}
if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
return true;
@@ -2531,7 +2531,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!TextUtils.isEmpty(inputMethodId)) {
intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
}
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
}
private void showConfigureInputMethods() {
@@ -2539,7 +2539,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
}
private boolean isScreenLocked() {
@@ -2673,6 +2673,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mSwitchingDialog.setCanceledOnTouchOutside(true);
mSwitchingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ mSwitchingDialog.getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mSwitchingDialog.getWindow().getAttributes().setTitle("Select input method");
mSwitchingDialog.show();
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index ae95c4c..c5016e6 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -226,7 +226,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
updateProvidersLocked();
}
}
- });
+ }, UserHandle.USER_ALL);
mPackageMonitor.register(mContext, Looper.myLooper(), true);
// listen for user change
@@ -289,7 +289,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mContext,
LocationManager.NETWORK_PROVIDER,
NETWORK_LOCATION_SERVICE_ACTION,
- providerPackageNames, mLocationHandler);
+ providerPackageNames, mLocationHandler, mCurrentUserId);
if (networkProvider != null) {
mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
mProxyProviders.add(networkProvider);
@@ -303,18 +303,20 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
mContext,
LocationManager.FUSED_PROVIDER,
FUSED_LOCATION_SERVICE_ACTION,
- providerPackageNames, mLocationHandler);
+ providerPackageNames, mLocationHandler, mCurrentUserId);
if (fusedLocationProvider != null) {
addProviderLocked(fusedLocationProvider);
mProxyProviders.add(fusedLocationProvider);
mEnabledProviders.add(fusedLocationProvider.getName());
+ mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
} else {
Slog.e(TAG, "no fused location provider found",
new IllegalStateException("Location service needs a fused location provider"));
}
// bind to geocoder provider
- mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames);
+ mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
+ mCurrentUserId);
if (mGeocodeProvider == null) {
Slog.e(TAG, "no geocoder provider found");
}
@@ -325,11 +327,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
* @param userId the new active user's UserId
*/
private void switchUser(int userId) {
- //Log.d("LocationManagerService", "switchUser(" + mCurrentUserId + " -> " + userId + ")"); // TODO: remove this
+ mBlacklist.switchUser(userId);
synchronized (mLock) {
- // TODO: inform previous user's Receivers that they will no longer receive updates
+ mLastLocation.clear();
+ for (LocationProviderInterface p : mProviders) {
+ updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
+ p.switchUser(userId);
+ }
mCurrentUserId = userId;
- // TODO: inform new user's Receivers that they are back on the update train
+ updateProvidersLocked();
}
}
@@ -586,7 +592,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
- private boolean isAllowedBySettingsLocked(String provider) {
+ private boolean isAllowedBySettingsLocked(String provider, int userId) {
+ if (userId != mCurrentUserId) {
+ return false;
+ }
if (mEnabledProviders.contains(provider)) {
return true;
}
@@ -596,7 +605,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Use system settings
ContentResolver resolver = mContext.getContentResolver();
- return Settings.Secure.isLocationProviderEnabled(resolver, provider);
+ return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
}
/**
@@ -639,7 +648,27 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
== PackageManager.PERMISSION_GRANTED) ||
(mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
+ } else {
+ // mock providers
+ LocationProviderInterface lp = mMockProviders.get(provider);
+ if (lp != null) {
+ ProviderProperties properties = lp.getProperties();
+ if (properties != null) {
+ if (properties.mRequiresSatellite) {
+ // provider requiring satellites require FINE permission
+ return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED;
+ } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
+ // provider requiring network and or cell require COARSE or FINE
+ return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) ||
+ (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED);
+ }
+ }
+ }
}
+
return false;
}
@@ -674,24 +703,30 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
ArrayList<String> out;
- synchronized (mLock) {
- out = new ArrayList<String>(mProviders.size());
- for (LocationProviderInterface provider : mProviders) {
- String name = provider.getName();
- if (LocationManager.FUSED_PROVIDER.equals(name)) {
- continue;
- }
- if (isAllowedProviderSafe(name)) {
- if (enabledOnly && !isAllowedBySettingsLocked(name)) {
+ int callingUserId = UserHandle.getCallingUserId();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ out = new ArrayList<String>(mProviders.size());
+ for (LocationProviderInterface provider : mProviders) {
+ String name = provider.getName();
+ if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue;
}
- if (criteria != null && !LocationProvider.propertiesMeetCriteria(
- name, provider.getProperties(), criteria)) {
- continue;
+ if (isAllowedProviderSafe(name)) {
+ if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
+ continue;
+ }
+ if (criteria != null && !LocationProvider.propertiesMeetCriteria(
+ name, provider.getProperties(), criteria)) {
+ continue;
+ }
+ out.add(name);
}
- out.add(name);
}
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
if (D) Log.d(TAG, "getProviders()=" + out);
@@ -757,12 +792,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
LocationProviderInterface p = mProviders.get(i);
boolean isEnabled = p.isEnabled();
String name = p.getName();
- boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
+ boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
if (isEnabled && !shouldBeEnabled) {
- updateProviderListenersLocked(name, false);
+ updateProviderListenersLocked(name, false, mCurrentUserId);
changesMade = true;
} else if (!isEnabled && shouldBeEnabled) {
- updateProviderListenersLocked(name, true);
+ updateProviderListenersLocked(name, true, mCurrentUserId);
changesMade = true;
}
}
@@ -772,7 +807,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- private void updateProviderListenersLocked(String provider, boolean enabled) {
+ private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
int listeners = 0;
LocationProviderInterface p = mProvidersByName.get(provider);
@@ -785,14 +820,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
final int N = records.size();
for (int i = 0; i < N; i++) {
UpdateRecord record = records.get(i);
- // Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<Receiver>();
+ if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
+ // Sends a notification message to the receiver
+ if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ }
+ deadReceivers.add(record.mReceiver);
}
- deadReceivers.add(record.mReceiver);
+ listeners++;
}
- listeners++;
}
}
@@ -822,12 +859,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (records != null) {
for (UpdateRecord record : records) {
- LocationRequest locationRequest = record.mRequest;
-
- providerRequest.locationRequests.add(locationRequest);
- if (locationRequest.getInterval() < providerRequest.interval) {
- providerRequest.reportLocation = true;
- providerRequest.interval = locationRequest.getInterval();
+ if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ LocationRequest locationRequest = record.mRequest;
+ providerRequest.locationRequests.add(locationRequest);
+ if (locationRequest.getInterval() < providerRequest.interval) {
+ providerRequest.reportLocation = true;
+ providerRequest.interval = locationRequest.getInterval();
+ }
}
}
@@ -839,9 +877,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// under that threshold.
long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
for (UpdateRecord record : records) {
- LocationRequest locationRequest = record.mRequest;
- if (locationRequest.getInterval() <= thresholdInterval) {
- worksource.add(record.mReceiver.mUid);
+ if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
+ LocationRequest locationRequest = record.mRequest;
+ if (locationRequest.getInterval() <= thresholdInterval) {
+ worksource.add(record.mReceiver.mUid);
+ }
}
}
}
@@ -1063,7 +1103,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
oldRecord.disposeLocked(false);
}
- boolean isProviderEnabled = isAllowedBySettingsLocked(name);
+ boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
if (isProviderEnabled) {
applyRequirementsLocked(name);
} else {
@@ -1120,7 +1160,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// update provider
for (String provider : providers) {
// If provider is already disabled, don't need to do anything
- if (!isAllowedBySettingsLocked(provider)) {
+ if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
continue;
}
@@ -1135,36 +1175,41 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
String perm = checkPermissionAndRequest(request);
checkPackageName(packageName);
- if (mBlacklist.isBlacklisted(packageName)) {
- if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
- packageName);
- return null;
- }
-
- synchronized (mLock) {
- // Figure out the provider. Either its explicitly request (deprecated API's),
- // or use the fused provider
- String name = request.getProvider();
- if (name == null) name = LocationManager.FUSED_PROVIDER;
- LocationProviderInterface provider = mProvidersByName.get(name);
- if (provider == null) return null;
-
- if (!isAllowedBySettingsLocked(name)) return null;
-
- Location location = mLastLocation.get(name);
- if (location == null) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (mBlacklist.isBlacklisted(packageName)) {
+ if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
+ packageName);
return null;
}
- if (ACCESS_FINE_LOCATION.equals(perm)) {
- return location;
- } else {
- Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
- if (noGPSLocation != null) {
- return mLocationFudger.getOrCreate(noGPSLocation);
+
+ synchronized (mLock) {
+ // Figure out the provider. Either its explicitly request (deprecated API's),
+ // or use the fused provider
+ String name = request.getProvider();
+ if (name == null) name = LocationManager.FUSED_PROVIDER;
+ LocationProviderInterface provider = mProvidersByName.get(name);
+ if (provider == null) return null;
+
+ if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
+
+ Location location = mLastLocation.get(name);
+ if (location == null) {
+ return null;
+ }
+ if (ACCESS_FINE_LOCATION.equals(perm)) {
+ return location;
+ } else {
+ Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation != null) {
+ return mLocationFudger.getOrCreate(noGPSLocation);
+ }
}
}
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return null;
}
@Override
@@ -1292,14 +1337,24 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override
public boolean isProviderEnabled(String provider) {
- checkPermission();
+ String perms = checkPermission();
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+ if (ACCESS_COARSE_LOCATION.equals(perms) &&
+ !isProviderAllowedByCoarsePermission(provider)) {
+ throw new SecurityException("The \"" + provider +
+ "\" provider requires ACCESS_FINE_LOCATION permission");
+ }
- synchronized (mLock) {
- LocationProviderInterface p = mProvidersByName.get(provider);
- if (p == null) return false;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) return false;
- return isAllowedBySettingsLocked(provider);
+ return isAllowedBySettingsLocked(provider, mCurrentUserId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
@@ -1388,9 +1443,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
long now = SystemClock.elapsedRealtime();
String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
- if (records == null || records.size() == 0) return;
+ // Skip if the provider is unknown.
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) return;
@@ -1411,6 +1465,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
lastLocation.set(location);
+ // Skip if there are no UpdateRecords for this provider.
+ ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
+ if (records == null || records.size() == 0) return;
+
// Fetch coarse location
Location coarseLocation = null;
if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
@@ -1432,6 +1490,16 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
+ int receiverUserId = UserHandle.getUserId(receiver.mUid);
+ if (receiverUserId != mCurrentUserId) {
+ if (D) {
+ Log.d(TAG, "skipping loc update for background user " + receiverUserId +
+ " (current user: " + mCurrentUserId + ", app: " +
+ receiver.mPackageName + ")");
+ }
+ continue;
+ }
+
if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
receiver.mPackageName);
@@ -1522,7 +1590,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
synchronized (mLock) {
- if (isAllowedBySettingsLocked(provider)) {
+ if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
handleLocationChangedLocked(location, passive);
}
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 5d5f8d3..85b488c 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1029,11 +1029,20 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ final int currentUser;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ currentUser = ActivityManager.getCurrentUser();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
// If we're not supposed to beep, vibrate, etc. then don't.
if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
- && (r.userId == UserHandle.USER_ALL || r.userId == userId)
+ && (r.userId == UserHandle.USER_ALL ||
+ (r.userId == userId && r.userId == currentUser))
&& mSystemReady) {
final AudioManager audioManager = (AudioManager) mContext
@@ -1240,7 +1249,7 @@ public class NotificationManagerService extends INotificationManager.Stub
if ((r.notification.flags & mustNotHaveFlags) != 0) {
continue;
}
- if (!r.pkg.equals(pkg)) {
+ if (pkg != null && !r.pkg.equals(pkg)) {
continue;
}
canceledSomething = true;
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index e99949b..5598b0a 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -27,6 +27,7 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.os.Handler;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.Log;
import com.android.internal.content.PackageMonitor;
@@ -58,15 +59,17 @@ public class ServiceWatcher implements ServiceConnection {
private IBinder mBinder; // connected service
private String mPackageName; // current best package
private int mVersion; // current best version
+ private int mCurrentUserId;
public ServiceWatcher(Context context, String logTag, String action,
- List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
+ List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
mContext = context;
mTag = logTag;
mAction = action;
mPm = mContext.getPackageManager();
mNewServiceWork = newServiceWork;
mHandler = handler;
+ mCurrentUserId = userId;
mSignatureSets = new ArrayList<HashSet<Signature>>();
for (int i=0; i < initialPackageNames.size(); i++) {
@@ -85,9 +88,11 @@ public class ServiceWatcher implements ServiceConnection {
}
public boolean start() {
- if (!bindBestPackage(null)) return false;
+ synchronized (mLock) {
+ if (!bindBestPackageLocked(null)) return false;
+ }
- mPackageMonitor.register(mContext, null, true);
+ mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
return true;
}
@@ -98,13 +103,13 @@ public class ServiceWatcher implements ServiceConnection {
* is null.
* Return true if a new package was found to bind to.
*/
- private boolean bindBestPackage(String justCheckThisPackage) {
+ private boolean bindBestPackageLocked(String justCheckThisPackage) {
Intent intent = new Intent(mAction);
if (justCheckThisPackage != null) {
intent.setPackage(justCheckThisPackage);
}
- List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction),
- PackageManager.GET_META_DATA);
+ List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(new Intent(mAction),
+ PackageManager.GET_META_DATA, mCurrentUserId);
int bestVersion = Integer.MIN_VALUE;
String bestPackage = null;
for (ResolveInfo rInfo : rInfos) {
@@ -141,36 +146,32 @@ public class ServiceWatcher implements ServiceConnection {
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
if (bestPackage != null) {
- bindToPackage(bestPackage, bestVersion);
+ bindToPackageLocked(bestPackage, bestVersion);
return true;
}
return false;
}
- private void unbind() {
+ private void unbindLocked() {
String pkg;
- synchronized (mLock) {
- pkg = mPackageName;
- mPackageName = null;
- mVersion = Integer.MIN_VALUE;
- }
+ pkg = mPackageName;
+ mPackageName = null;
+ mVersion = Integer.MIN_VALUE;
if (pkg != null) {
if (D) Log.d(mTag, "unbinding " + pkg);
mContext.unbindService(this);
}
}
- private void bindToPackage(String packageName, int version) {
- unbind();
+ private void bindToPackageLocked(String packageName, int version) {
+ unbindLocked();
Intent intent = new Intent(mAction);
intent.setPackage(packageName);
- synchronized (mLock) {
- mPackageName = packageName;
- mVersion = version;
- }
+ mPackageName = packageName;
+ mVersion = version;
if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")");
mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
- | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE);
+ | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
}
private boolean isSignatureMatch(Signature[] signatures) {
@@ -197,31 +198,37 @@ public class ServiceWatcher implements ServiceConnection {
*/
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbind();
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ // package updated, make sure to rebind
+ unbindLocked();
+ }
+ // check the updated package in case it is better
+ bindBestPackageLocked(packageName);
}
- // check the updated package in case it is better
- bindBestPackage(packageName);
}
@Override
public void onPackageAdded(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- // package updated, make sure to rebind
- unbind();
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ // package updated, make sure to rebind
+ unbindLocked();
+ }
+ // check the new package is case it is better
+ bindBestPackageLocked(packageName);
}
- // check the new package is case it is better
- bindBestPackage(packageName);
}
@Override
public void onPackageRemoved(String packageName, int uid) {
- if (packageName.equals(mPackageName)) {
- unbind();
- // the currently bound package was removed,
- // need to search for a new package
- bindBestPackage(null);
+ synchronized (mLock) {
+ if (packageName.equals(mPackageName)) {
+ unbindLocked();
+ // the currently bound package was removed,
+ // need to search for a new package
+ bindBestPackageLocked(null);
+ }
}
}
};
@@ -271,4 +278,12 @@ public class ServiceWatcher implements ServiceConnection {
return mBinder;
}
}
+
+ public void switchUser(int userId) {
+ synchronized (mLock) {
+ unbindLocked();
+ mCurrentUserId = userId;
+ bindBestPackageLocked(null);
+ }
+ }
}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 5d9441b..439eebe 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -544,7 +544,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub
int i;
for (i=0; i<N; i++) {
DisableRecord t = mDisableRecords.get(i);
- if (t.token == token) {
+ if (t.token == token && t.userId == userId) {
tok = t;
break;
}
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index c74dd00..d0d8428 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -25,17 +25,25 @@ import com.android.internal.textservice.ITextServicesSessionListener;
import org.xmlpull.v1.XmlPullParserException;
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.app.IUserSwitchObserver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
@@ -66,6 +74,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>();
private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups =
new HashMap<String, SpellCheckerBindGroup>();
+ private final TextServicesSettings mSettings;
public void systemReady() {
if (!mSystemReady) {
@@ -76,11 +85,43 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
public TextServicesManagerService(Context context) {
mSystemReady = false;
mContext = context;
+ int userId = UserHandle.USER_OWNER;
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ synchronized(mSpellCheckerMap) {
+ switchUserLocked(newUserId);
+ }
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ }
+ });
+ userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
+ }
mMonitor = new TextServicesMonitor();
mMonitor.register(context, null, true);
- synchronized (mSpellCheckerMap) {
- buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
- }
+ mSettings = new TextServicesSettings(context.getContentResolver(), userId);
+
+ // "switchUserLocked" initializes the states for the foreground user
+ switchUserLocked(userId);
+ }
+
+ private void switchUserLocked(int userId) {
+ mSettings.setCurrentUserId(userId);
+ unbindServiceLocked();
+ buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null) {
sci = findAvailSpellCheckerLocked(null, null);
@@ -94,10 +135,23 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
private class TextServicesMonitor extends PackageMonitor {
+ private boolean isChangingPackagesOfCurrentUser() {
+ final int userId = getChangingUserId();
+ final boolean retval = userId == mSettings.getCurrentUserId();
+ if (DBG) {
+ Slog.d(TAG, "--- ignore this call back from a background user: " + userId);
+ }
+ return retval;
+ }
+
@Override
public void onSomePackagesChanged() {
+ if (!isChangingPackagesOfCurrentUser()) {
+ return;
+ }
synchronized (mSpellCheckerMap) {
- buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap);
+ buildSpellCheckerMapLocked(
+ mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
// TODO: Update for each locale
SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null) return;
@@ -117,12 +171,14 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
private static void buildSpellCheckerMapLocked(Context context,
- ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) {
+ ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map,
+ TextServicesSettings settings) {
list.clear();
map.clear();
final PackageManager pm = context.getPackageManager();
- List<ResolveInfo> services = pm.queryIntentServices(
- new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA);
+ final List<ResolveInfo> services = pm.queryIntentServicesAsUser(
+ new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA,
+ settings.getCurrentUserId());
final int N = services.size();
for (int i = 0; i < N; ++i) {
final ResolveInfo ri = services.get(i);
@@ -155,6 +211,53 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
+ // ---------------------------------------------------------------------------------------
+ // Check whether or not this is a valid IPC. Assumes an IPC is valid when either
+ // 1) it comes from the system process
+ // 2) the calling process' user id is identical to the current user id TSMS thinks.
+ private boolean calledFromValidUser() {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (DBG) {
+ Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ + " calling userId = " + userId + ", foreground user id = "
+ + mSettings.getCurrentUserId());
+ try {
+ final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+ for (int i = 0; i < packageNames.length; ++i) {
+ if (DBG) {
+ Slog.d(TAG, "--- process name for "+ uid + " = " + packageNames[i]);
+ }
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
+ if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
+ return true;
+ } else {
+ Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
+ return false;
+ }
+ }
+
+ private boolean bindCurrentSpellCheckerService(
+ Intent service, ServiceConnection conn, int flags) {
+ if (service == null || conn == null) {
+ Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn);
+ return false;
+ }
+ return mContext.bindService(service, conn, flags, mSettings.getCurrentUserId());
+ }
+
+ private void unbindServiceLocked() {
+ for (SpellCheckerBindGroup scbg : mSpellCheckerBindGroups.values()) {
+ scbg.removeAll();
+ }
+ mSpellCheckerBindGroups.clear();
+ }
+
// TODO: find an appropriate spell checker for specified locale
private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) {
final int spellCheckersCount = mSpellCheckerList.size();
@@ -183,10 +286,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
// checker is saved.
@Override
public SpellCheckerInfo getCurrentSpellChecker(String locale) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
synchronized (mSpellCheckerMap) {
- final String curSpellCheckerId =
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER);
+ final String curSpellCheckerId = mSettings.getSelectedSpellChecker();
if (DBG) {
Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId);
}
@@ -202,10 +307,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(
String locale, boolean allowImplicitlySelectedSubtype) {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
synchronized (mSpellCheckerMap) {
- final String subtypeHashCodeStr =
- Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
+ final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype();
if (DBG) {
Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
}
@@ -280,6 +387,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
public void getSpellCheckerService(String sciId, String locale,
ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
Bundle bundle) {
+ if (!calledFromValidUser()) {
+ return;
+ }
if (!mSystemReady) {
return;
}
@@ -346,6 +456,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public boolean isSpellCheckerEnabled() {
+ if (!calledFromValidUser()) {
+ return false;
+ }
synchronized(mSpellCheckerMap) {
return isSpellCheckerEnabledLocked();
}
@@ -365,7 +478,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (DBG) {
Slog.w(TAG, "bind service: " + info.getId());
}
- if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
+ if (!bindCurrentSpellCheckerService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
Slog.e(TAG, "Failed to get a spell checker service.");
return;
}
@@ -376,6 +489,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public SpellCheckerInfo[] getEnabledSpellCheckers() {
+ // TODO: Make this work even for non-current users?
+ if (!calledFromValidUser()) {
+ return null;
+ }
if (DBG) {
Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size());
for (int i = 0; i < mSpellCheckerList.size(); ++i) {
@@ -387,6 +504,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public void finishSpellCheckerService(ISpellCheckerSessionListener listener) {
+ if (!calledFromValidUser()) {
+ return;
+ }
if (DBG) {
Slog.d(TAG, "FinishSpellCheckerService");
}
@@ -407,6 +527,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public void setCurrentSpellChecker(String locale, String sciId) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -421,6 +544,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public void setCurrentSpellCheckerSubtype(String locale, int hashCode) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -435,6 +561,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public void setSpellCheckerEnabled(boolean enabled) {
+ if (!calledFromValidUser()) {
+ return;
+ }
synchronized(mSpellCheckerMap) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -459,8 +588,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
+ mSettings.putSelectedSpellChecker(sciId);
setCurrentSpellCheckerSubtypeLocked(0);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -481,8 +609,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(tempHashCode));
+ mSettings.putSelectedSpellCheckerSubtype(tempHashCode);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -494,8 +621,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
final long ident = Binder.clearCallingIdentity();
try {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0);
+ mSettings.setSpellCheckerEnabled(enabled);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -504,8 +630,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
private boolean isSpellCheckerEnabledLocked() {
final long ident = Binder.clearCallingIdentity();
try {
- final boolean retval = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SPELL_CHECKER_ENABLED, 1) == 1;
+ final boolean retval = mSettings.isSpellCheckerEnabled();
if (DBG) {
Slog.w(TAG, "getSpellCheckerEnabled: " + retval);
}
@@ -729,14 +854,19 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized(mSpellCheckerMap) {
- if (DBG) {
- Slog.w(TAG, "onServiceConnected: " + name);
- }
- ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
- final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
- if (group != null && this == group.mInternalConnection) {
- group.onServiceConnected(spellChecker);
- }
+ onServiceConnectedInnerLocked(name, service);
+ }
+ }
+
+ private void onServiceConnectedInnerLocked(ComponentName name, IBinder service) {
+ if (DBG) {
+ Slog.w(TAG, "onServiceConnected: " + name);
+ }
+ final ISpellCheckerService spellChecker =
+ ISpellCheckerService.Stub.asInterface(service);
+ final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
+ if (group != null && this == group.mInternalConnection) {
+ group.onServiceConnected(spellChecker);
}
}
@@ -778,4 +908,73 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
mGroup.removeListener(mScListener);
}
}
+
+ private static class TextServicesSettings {
+ private final ContentResolver mResolver;
+ private int mCurrentUserId;
+ public TextServicesSettings(ContentResolver resolver, int userId) {
+ mResolver = resolver;
+ mCurrentUserId = userId;
+ }
+
+ public void setCurrentUserId(int userId) {
+ if (DBG) {
+ Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
+ + userId + ", new ime = " + getSelectedSpellChecker());
+ }
+ // TSMS settings are kept per user, so keep track of current user
+ mCurrentUserId = userId;
+ }
+
+ public int getCurrentUserId() {
+ return mCurrentUserId;
+ }
+
+ public void putSelectedSpellChecker(String sciId) {
+ Settings.Secure.putStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId);
+ }
+
+ public void putSelectedSpellCheckerSubtype(int hashCode) {
+ Settings.Secure.putStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode),
+ mCurrentUserId);
+ }
+
+ public void setSpellCheckerEnabled(boolean enabled) {
+ Settings.Secure.putIntForUser(mResolver,
+ Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId);
+ }
+
+ public String getSelectedSpellChecker() {
+ return Settings.Secure.getStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId);
+ }
+
+ public String getSelectedSpellCheckerSubtype() {
+ return Settings.Secure.getStringForUser(mResolver,
+ Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId);
+ }
+
+ public boolean isSpellCheckerEnabled() {
+ return Settings.Secure.getIntForUser(mResolver,
+ Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Utilities for debug
+ private static String getStackTrace() {
+ final StringBuilder sb = new StringBuilder();
+ try {
+ throw new RuntimeException();
+ } catch (RuntimeException e) {
+ final StackTraceElement[] frames = e.getStackTrace();
+ // Start at 1 because the first frame is here and we don't care about it
+ for (int j = 1; j < frames.length; ++j) {
+ sb.append(frames[j].toString() + "\n");
+ }
+ }
+ return sb.toString();
+ }
}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index d1af2b0..e9e3163 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -37,6 +37,7 @@ import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamService;
@@ -90,6 +91,8 @@ class UiModeManagerService extends IUiModeManager.Stub {
private NotificationManager mNotificationManager;
private StatusBarManager mStatusBarManager;
+
+ private final PowerManager mPowerManager;
private final PowerManager.WakeLock mWakeLock;
static Intent buildHomeIntent(String category) {
@@ -163,8 +166,8 @@ class UiModeManagerService extends IUiModeManager.Stub {
mContext.registerReceiver(mBatteryReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
+ mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
mConfiguration.setToDefaults();
@@ -502,7 +505,17 @@ class UiModeManagerService extends IUiModeManager.Stub {
try {
IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
- dreamManagerService.dream();
+ if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+ // Wake up.
+ // The power manager will wake up the system when it starts receiving power
+ // but there is a race between that happening and the UI mode manager
+ // starting a dream. We want the system to already be awake
+ // by the time this happens. Otherwise the dream may not start.
+ mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
+ // Dream.
+ dreamManagerService.dream();
+ }
} catch (RemoteException ex) {
Slog.e(TAG, "Could not start dream when docked.", ex);
}
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4225913..e0f3814 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -38,6 +38,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
@@ -53,6 +54,7 @@ import android.os.SELinux;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
@@ -97,6 +99,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
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.
+ */
+ static final ComponentName IMAGE_WALLPAPER = new ComponentName("com.android.systemui",
+ "com.android.systemui.ImageWallpaper");
+
+ /**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
* that the wallpaper has changed. The CREATE is triggered when there is no
* wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
@@ -136,7 +145,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (event == CLOSE_WRITE) {
mWallpaper.imageWallpaperPending = false;
}
- bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+ bindWallpaperComponentLocked(IMAGE_WALLPAPER, true,
false, mWallpaper, null);
saveSettingsLocked(mWallpaper);
}
@@ -181,13 +190,6 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
*/
ComponentName nextWallpaperComponent;
- /**
- * Name of the component used to display bitmap wallpapers from either the gallery or
- * built-in wallpapers.
- */
- ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
- "com.android.systemui.ImageWallpaper");
-
WallpaperConnection connection;
long lastDiedTime;
boolean wallpaperUpdating;
@@ -511,6 +513,9 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaper = new WallpaperData(userId);
mWallpaperMap.put(userId, wallpaper);
loadSettingsLocked(userId);
+ }
+ // Not started watching yet, in case wallpaper data was loaded for other reasons.
+ if (wallpaper.wallpaperObserver == null) {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
}
@@ -554,7 +559,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaper.imageWallpaperPending = false;
if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
- ? wallpaper.imageWallpaperComponent
+ ? IMAGE_WALLPAPER
: null, true, false, wallpaper, reply)) {
return;
}
@@ -580,9 +585,21 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public boolean hasNamedWallpaper(String name) {
synchronized (mLock) {
- for (int i=0; i<mWallpaperMap.size(); i++) {
- WallpaperData wd = mWallpaperMap.valueAt(i);
- if (name.equals(wd.name)) {
+ List<UserInfo> users;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ for (UserInfo user: users) {
+ WallpaperData wd = mWallpaperMap.get(user.id);
+ if (wd == null) {
+ // User hasn't started yet, so load her settings to peek at the wallpaper
+ loadSettingsLocked(user.id);
+ wd = mWallpaperMap.get(user.id);
+ }
+ if (wd != null && name.equals(wd.name)) {
return true;
}
}
@@ -775,7 +792,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
if (componentName == null) {
// Fall back to static image wallpaper
- componentName = wallpaper.imageWallpaperComponent;
+ componentName = IMAGE_WALLPAPER;
//clearWallpaperComponentLocked();
//return;
if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -798,7 +815,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
+ if (componentName != null && !componentName.equals(IMAGE_WALLPAPER)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris =
mIPackageManager.queryIntentServices(intent,
@@ -973,7 +990,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
out.attribute(null, "height", Integer.toString(wallpaper.height));
out.attribute(null, "name", wallpaper.name);
if (wallpaper.wallpaperComponent != null
- && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ && !wallpaper.wallpaperComponent.equals(IMAGE_WALLPAPER)) {
out.attribute(null, "component",
wallpaper.wallpaperComponent.flattenToShortString());
}
@@ -1045,7 +1062,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (wallpaper.nextWallpaperComponent == null
|| "android".equals(wallpaper.nextWallpaperComponent
.getPackageName())) {
- wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
+ wallpaper.nextWallpaperComponent = IMAGE_WALLPAPER;
}
if (DEBUG) {
@@ -1107,7 +1124,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
loadSettingsLocked(0);
wallpaper = mWallpaperMap.get(0);
if (wallpaper.nextWallpaperComponent != null
- && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ && !wallpaper.nextWallpaperComponent.equals(IMAGE_WALLPAPER)) {
if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
wallpaper, null)) {
// No such live wallpaper or other failure; fall back to the default
diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/java/com/android/server/WiredAccessoryManager.java
index 63e8895..d5c9c8f 100644
--- a/services/java/com/android/server/WiredAccessoryManager.java
+++ b/services/java/com/android/server/WiredAccessoryManager.java
@@ -152,7 +152,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks {
break;
}
- updateLocked(NAME_H2W, headset);
+ updateLocked(NAME_H2W, (mHeadsetState & ~(BIT_HEADSET | BIT_HEADSET_NO_MIC)) | headset);
}
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5e9e223..3d77b3a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -643,6 +643,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return mSecurityPolicy.mActiveWindowId;
}
+ void onTouchInteractionEnd() {
+ mSecurityPolicy.onTouchInteractionEnd();
+ }
+
private void switchUser(int userId) {
synchronized (mLock) {
// The user switched so we do not need to restore the current user
@@ -1119,7 +1123,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
R.string.enable_explore_by_touch_warning_message, label))
.create();
mEnableTouchExplorationDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags
+ |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true);
mEnableTouchExplorationDialog.show();
}
@@ -2178,16 +2184,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
mActiveWindowId = windowId;
}
} break;
- case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
- case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: {
+ case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
mActiveWindowId = windowId;
} break;
- case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: {
- mActiveWindowId = getFocusedWindowId();
- } break;
}
}
+ public void onTouchInteractionEnd() {
+ // We want to set the active window to be current immediately
+ // after the user has stopped touching the screen since if the
+ // user types with the IME he should get a feedback for the
+ // letter typed in the text view which is in the input focused
+ // window. Note that we always deliver hover accessibility events
+ // (they are a result of user touching the screen) so change of
+ // the active window before all hover accessibility events from
+ // the touched window are delivered is fine.
+ mActiveWindowId = getFocusedWindowId();
+ }
+
public int getRetrievalAllowingWindowLocked() {
return mActiveWindowId;
}
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index 14762a1..51ccd47 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -846,7 +846,6 @@ public final class ScreenMagnifier implements EventStreamTransformation {
private static final class DisplayContentObserver {
private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1;
- private static final int MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS = 2;
private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
@@ -892,7 +891,9 @@ public final class ScreenMagnifier implements EventStreamTransformation {
|| info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
&& (transition == WindowManagerPolicy.TRANSIT_EXIT
|| transition == WindowManagerPolicy.TRANSIT_HIDE)) {
- mHandler.sendMessageDelayed(message, mLongAnimationDuration);
+ final long delay = (long) (2 * mLongAnimationDuration
+ * mWindowAnimationScale);
+ mHandler.sendMessageDelayed(message, delay);
} else {
message.sendToTarget();
}
@@ -1009,7 +1010,8 @@ public final class ScreenMagnifier implements EventStreamTransformation {
case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
- case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
+ case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+ case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
Rect magnifiedRegionBounds = mMagnificationController
.getMagnifiedRegionBounds();
Rect touchableRegion = info.touchableRegion;
@@ -1169,10 +1171,6 @@ public final class ScreenMagnifier implements EventStreamTransformation {
case MESSAGE_SHOW_VIEWPORT_FRAME: {
mViewport.setFrameShown(true, true);
} break;
- case MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS: {
- final boolean animate = message.arg1 == 1;
- mViewport.recomputeBounds(animate);
- } break;
case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
SomeArgs args = (SomeArgs) message.obj;
try {
@@ -1525,8 +1523,10 @@ public final class ScreenMagnifier implements EventStreamTransformation {
Rect magnifiedFrame = mTempRect1;
magnifiedFrame.set(0, 0, 0, 0);
- Rect notMagnifiedFrame = mTempRect2;
- notMagnifiedFrame.set(0, 0, 0, 0);
+ DisplayInfo displayInfo = mDisplayProvider.getDisplayInfo();
+
+ Rect availableFrame = mTempRect2;
+ availableFrame.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
ArrayList<WindowInfo> infos = mTempWindowInfoList;
infos.clear();
@@ -1541,18 +1541,16 @@ public final class ScreenMagnifier implements EventStreamTransformation {
if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
continue;
}
+ Rect windowFrame = mTempRect3;
+ windowFrame.set(info.touchableRegion);
if (isWindowMagnified(info.type)) {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, notMagnifiedFrame);
- magnifiedFrame.union(clippedFrame);
+ magnifiedFrame.union(windowFrame);
+ magnifiedFrame.intersect(availableFrame);
} else {
- Rect clippedFrame = mTempRect3;
- clippedFrame.set(info.touchableRegion);
- subtract(clippedFrame, magnifiedFrame);
- notMagnifiedFrame.union(clippedFrame);
+ subtract(windowFrame, magnifiedFrame);
+ subtract(availableFrame, windowFrame);
}
- if (magnifiedFrame.bottom >= notMagnifiedFrame.top) {
+ if (availableFrame.equals(magnifiedFrame)) {
break;
}
}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 2d81b6c..2688776 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -102,10 +102,6 @@ class TouchExplorer implements EventStreamTransformation {
// The timeout after which we are no longer trying to detect a gesture.
private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000;
- // The timeout to send interaction end events in case we did not
- // receive the expected hover exit event due to a misbehaving app.
- private static final int SEND_INTERACTION_END_EVENTS_TIMEOUT = 200;
-
// Temporary array for storing pointer IDs.
private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
@@ -139,8 +135,11 @@ class TouchExplorer implements EventStreamTransformation {
// Command for delayed sending of a hover exit event.
private final SendHoverDelayed mSendHoverExitDelayed;
- // Command for delayed sending of interaction ending events.
- private final SendInteractionEndEventsDelayed mSendInteractionEndEventsDelayed;
+ // Command for delayed sending of touch exploration end events.
+ private final SendAccessibilityEventDelayed mSendTouchExplorationEndDelayed;
+
+ // Command for delayed sending of touch interaction end events.
+ private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;
// Command for delayed sending of a long press.
private final PerformLongPressDelayed mPerformLongPressDelayed;
@@ -209,11 +208,8 @@ class TouchExplorer implements EventStreamTransformation {
// The id of the last touch explored window.
private int mLastTouchedWindowId;
- // Whether touch exploration gesture has ended.
- private boolean mTouchExplorationGestureEnded;
-
- // Whether touch interaction has ended.
- private boolean mTouchInteractionEnded;
+ // Whether touch exploration is in progress.
+ private boolean mTouchExplorationInProgress;
/**
* Creates a new instance.
@@ -240,7 +236,12 @@ class TouchExplorer implements EventStreamTransformation {
mGestureLibrary.load();
mSendHoverEnterDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_ENTER, true);
mSendHoverExitDelayed = new SendHoverDelayed(MotionEvent.ACTION_HOVER_EXIT, false);
- mSendInteractionEndEventsDelayed = new SendInteractionEndEventsDelayed();
+ mSendTouchExplorationEndDelayed = new SendAccessibilityEventDelayed(
+ AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END,
+ mDetermineUserIntentTimeout);
+ mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
+ AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
+ mDetermineUserIntentTimeout);
mDoubleTapDetector = new DoubleTapDetector();
final float density = context.getResources().getDisplayMetrics().density;
mScaledMinPointerDistanceToUseMiddleLocation =
@@ -265,7 +266,7 @@ class TouchExplorer implements EventStreamTransformation {
switch (mCurrentState) {
case STATE_TOUCH_EXPLORING: {
// If a touch exploration gesture is in progress send events for its end.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
} break;
case STATE_DRAGGING: {
mDraggingPointerId = INVALID_POINTER_ID;
@@ -286,7 +287,8 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove();
mExitGestureDetectionModeDelayed.remove();
- mSendInteractionEndEventsDelayed.remove();
+ mSendTouchExplorationEndDelayed.remove();
+ mSendTouchInteractionEndDelayed.remove();
// Reset the pointer trackers.
mReceivedPointerTracker.clear();
mInjectedPointerTracker.clear();
@@ -301,6 +303,8 @@ class TouchExplorer implements EventStreamTransformation {
if (mNext != null) {
mNext.clear();
}
+ mTouchExplorationInProgress = false;
+ mAms.onTouchInteractionEnd();
}
@Override
@@ -341,19 +345,17 @@ class TouchExplorer implements EventStreamTransformation {
// The event for gesture end should be strictly after the
// last hover exit event.
- if (mTouchExplorationGestureEnded
+ if (mSendTouchExplorationEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
- mSendInteractionEndEventsDelayed.remove();
- mTouchExplorationGestureEnded = false;
+ mSendTouchExplorationEndDelayed.remove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
}
// The event for touch interaction end should be strictly after the
// last hover exit and the touch exploration gesture end events.
- if (mTouchInteractionEnded
+ if (mSendTouchInteractionEndDelayed.isPending()
&& eventType == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
- mSendInteractionEndEventsDelayed.remove();
- mTouchInteractionEnded = false;
+ mSendTouchInteractionEndDelayed.remove();
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
}
@@ -396,15 +398,6 @@ class TouchExplorer implements EventStreamTransformation {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- // The delayed enter not delivered implies that we have delivered
- // TYPE_TOUCH_INTERACTION_START and not TYPE_TOUCH_INTERACTION_END,
- // therefore we need to deliver the interaction end event here.
- if (mSendHoverEnterDelayed.isPending()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- }
- // Announce the start of a new touch interaction.
- sendAccessibilityEvent(
- AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
// Pre-feed the motion events to the gesture detector since we
// have a distance slop before getting into gesture detection
// mode and not using the points within this slop significantly
@@ -426,8 +419,20 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove();
}
- if (mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.forceSendAndRemove();
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.forceSendAndRemove();
+ }
+
+ // Every pointer that goes down is active until it moves or
+ // another one goes down. Hence, having more than one pointer
+ // down we have already send the interaction start event.
+ if (event.getPointerCount() == 1) {
+ sendAccessibilityEvent(
+ AccessibilityEvent.TYPE_TOUCH_INTERACTION_START);
}
mPerformLongPressDelayed.remove();
@@ -443,11 +448,13 @@ class TouchExplorer implements EventStreamTransformation {
mPerformLongPressDelayed.post(event, policyFlags);
break;
}
- // Deliver hover enter with a delay to have a chance
- // to detect what the user is trying to do.
- final int pointerId = receivedTracker.getPrimaryActivePointerId();
- final int pointerIdBits = (1 << pointerId);
- mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
+ if (!mTouchExplorationInProgress) {
+ // Deliver hover enter with a delay to have a chance
+ // to detect what the user is trying to do.
+ final int pointerId = receivedTracker.getPrimaryActivePointerId();
+ final int pointerIdBits = (1 << pointerId);
+ mSendHoverEnterDelayed.post(event, true, pointerIdBits, policyFlags);
+ }
} break;
default: {
/* do nothing - let the code for ACTION_MOVE decide what to do */
@@ -512,12 +519,27 @@ class TouchExplorer implements EventStreamTransformation {
break;
}
} else {
+ // Cancel the long press if pending and the user
+ // moved more than the slop.
+ if (mPerformLongPressDelayed.isPending()) {
+ final float deltaX =
+ receivedTracker.getReceivedPointerDownX(pointerId)
+ - rawEvent.getX(pointerIndex);
+ final float deltaY =
+ receivedTracker.getReceivedPointerDownY(pointerId)
+ - rawEvent.getY(pointerIndex);
+ final double moveDelta = Math.hypot(deltaX, deltaY);
+ // The user has moved enough for us to decide.
+ if (moveDelta > mTouchSlop) {
+ mPerformLongPressDelayed.remove();
+ }
+ }
// The user is wither double tapping or performing long
// press so do not send move events yet.
if (mDoubleTapDetector.firstTapDetected()) {
break;
}
- sendEnterEventsIfNeeded(policyFlags);
+ sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
policyFlags);
}
@@ -548,7 +570,7 @@ class TouchExplorer implements EventStreamTransformation {
}
// We are sending events so send exit and gesture
// end since we transition to another state.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// We know that a new state transition is to happen and the
@@ -583,7 +605,7 @@ class TouchExplorer implements EventStreamTransformation {
mPerformLongPressDelayed.remove();
// We are sending events so send exit and gesture
// end since we transition to another state.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
}
// More than two pointers are delegated to the view hierarchy.
@@ -594,6 +616,7 @@ class TouchExplorer implements EventStreamTransformation {
}
} break;
case MotionEvent.ACTION_UP:
+ mAms.onTouchInteractionEnd();
// We know that we do not need the pre-fed gesture points are not
// needed anymore since the last pointer just went up.
mStrokeBuffer.clear();
@@ -612,11 +635,14 @@ class TouchExplorer implements EventStreamTransformation {
// If we have not delivered the enter schedule exit.
if (mSendHoverEnterDelayed.isPending()) {
- mSendHoverEnterDelayed.mTouchExplorationInProgress = false;
mSendHoverExitDelayed.post(event, false, pointerIdBits, policyFlags);
} else {
// The user is touch exploring so we send events for end.
- sendExitEventsIfNeeded(policyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+ }
+
+ if (!mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.post();
}
} break;
}
@@ -713,6 +739,7 @@ class TouchExplorer implements EventStreamTransformation {
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of a new touch interaction.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
@@ -758,6 +785,7 @@ class TouchExplorer implements EventStreamTransformation {
AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
//$FALL-THROUGH$
case MotionEvent.ACTION_POINTER_UP: {
+ mAms.onTouchInteractionEnd();
mLongPressingPointerId = -1;
mLongPressingPointerDeltaX = 0;
mLongPressingPointerDeltaY = 0;
@@ -795,6 +823,7 @@ class TouchExplorer implements EventStreamTransformation {
}
} break;
case MotionEvent.ACTION_UP: {
+ mAms.onTouchInteractionEnd();
// Announce the end of gesture recognition.
sendAccessibilityEvent(
AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
@@ -846,6 +875,14 @@ class TouchExplorer implements EventStreamTransformation {
if (accessibilityManager.isEnabled()) {
AccessibilityEvent event = AccessibilityEvent.obtain(type);
accessibilityManager.sendAccessibilityEvent(event);
+ switch (type) {
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: {
+ mTouchExplorationInProgress = true;
+ } break;
+ case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: {
+ mTouchExplorationInProgress = false;
+ } break;
+ }
}
}
@@ -893,14 +930,12 @@ class TouchExplorer implements EventStreamTransformation {
*
* @param policyFlags The policy flags associated with the event.
*/
- private void sendExitEventsIfNeeded(int policyFlags) {
+ private void sendHoverExitAndTouchExplorationGestureEndIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() != MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
- mTouchExplorationGestureEnded = true;
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
+ if (!mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.post();
}
sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
}
@@ -912,10 +947,11 @@ class TouchExplorer implements EventStreamTransformation {
*
* @param policyFlags The policy flags associated with the event.
*/
- private void sendEnterEventsIfNeeded(int policyFlags) {
+ private void sendTouchExplorationGestureStartAndHoverEnterIfNeeded(int policyFlags) {
MotionEvent event = mInjectedPointerTracker.getLastInjectedHoverEvent();
if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
final int pointerIdBits = event.getPointerIdBits();
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
}
}
@@ -1181,8 +1217,12 @@ class TouchExplorer implements EventStreamTransformation {
mSendHoverExitDelayed.remove();
mPerformLongPressDelayed.remove();
- // The touch interaction has ended since we will send a click.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+ if (mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.forceSendAndRemove();
+ }
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.forceSendAndRemove();
+ }
int clickLocationX;
int clickLocationY;
@@ -1416,7 +1456,7 @@ class TouchExplorer implements EventStreamTransformation {
mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocationX;
mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocationY;
- sendExitEventsIfNeeded(mPolicyFlags);
+ sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
mCurrentState = STATE_DELEGATING;
sendDownForAllActiveNotInjectedPointers(mEvent, mPolicyFlags);
@@ -1445,7 +1485,6 @@ class TouchExplorer implements EventStreamTransformation {
private MotionEvent mPrototype;
private int mPointerIdBits;
private int mPolicyFlags;
- private boolean mTouchExplorationInProgress;
public SendHoverDelayed(int hoverAction, boolean gestureStarted) {
mHoverAction = hoverAction;
@@ -1456,7 +1495,6 @@ class TouchExplorer implements EventStreamTransformation {
int pointerIdBits, int policyFlags) {
remove();
mPrototype = MotionEvent.obtain(prototype);
- mTouchExplorationInProgress = touchExplorationInProgress;
mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -1493,7 +1531,6 @@ class TouchExplorer implements EventStreamTransformation {
mPrototype = null;
mPointerIdBits = -1;
mPolicyFlags = 0;
- mTouchExplorationInProgress = false;
}
public void forceSendAndRemove() {
@@ -1510,22 +1547,15 @@ class TouchExplorer implements EventStreamTransformation {
Slog.d(LOG_TAG_SEND_HOVER_DELAYED, mGestureStarted ?
"touchExplorationGestureStarted" : "touchExplorationGestureEnded");
}
- if (mTouchExplorationInProgress) {
- if (mGestureStarted) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
- } else {
- mTouchExplorationGestureEnded = true;
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
- }
- }
+ if (mGestureStarted) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
} else {
- if (!mGestureStarted) {
- mTouchInteractionEnded = true;
- if (!mSendInteractionEndEventsDelayed.isPending()) {
- mSendInteractionEndEventsDelayed.post();
- }
+ if (!mSendTouchExplorationEndDelayed.isPending()) {
+ mSendTouchExplorationEndDelayed.post();
+ }
+ if (mSendTouchInteractionEndDelayed.isPending()) {
+ mSendTouchInteractionEndDelayed.remove();
+ mSendTouchInteractionEndDelayed.post();
}
}
sendMotionEvent(mPrototype, mHoverAction, mPointerIdBits, mPolicyFlags);
@@ -1533,14 +1563,21 @@ class TouchExplorer implements EventStreamTransformation {
}
}
- private class SendInteractionEndEventsDelayed implements Runnable {
+ private class SendAccessibilityEventDelayed implements Runnable {
+ private final int mEventType;
+ private final int mDelay;
+
+ public SendAccessibilityEventDelayed(int eventType, int delay) {
+ mEventType = eventType;
+ mDelay = delay;
+ }
public void remove() {
mHandler.removeCallbacks(this);
}
public void post() {
- mHandler.postDelayed(this, SEND_INTERACTION_END_EVENTS_TIMEOUT);
+ mHandler.postDelayed(this, mDelay);
}
public boolean isPending() {
@@ -1556,14 +1593,7 @@ class TouchExplorer implements EventStreamTransformation {
@Override
public void run() {
- if (mTouchExplorationGestureEnded) {
- mTouchExplorationGestureEnded = false;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END);
- }
- if (mTouchInteractionEnded) {
- mTouchInteractionEnded = false;
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- }
+ sendAccessibilityEvent(mEventType);
}
}
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 1269433..35999ea 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -248,8 +248,9 @@ public class ActiveServices {
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
- if (!bringUpServiceLocked(r, service.getFlags(), false)) {
- return new ComponentName("!", "Service process is bad");
+ String error = bringUpServiceLocked(r, service.getFlags(), false);
+ if (error != null) {
+ return new ComponentName("!!", error);
}
return r.name;
}
@@ -518,7 +519,7 @@ public class ActiveServices {
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
- if (!bringUpServiceLocked(s, service.getFlags(), false)) {
+ if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
return 0;
}
}
@@ -964,19 +965,19 @@ public class ActiveServices {
return true;
}
- private final boolean bringUpServiceLocked(ServiceRecord r,
+ private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean whileRestarting) {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, false);
- return true;
+ return null;
}
if (!whileRestarting && r.restartDelay > 0) {
// If waiting for a restart, then do nothing.
- return true;
+ return null;
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
@@ -988,12 +989,13 @@ public class ActiveServices {
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
if (mAm.mStartedUsers.get(r.userId) == null) {
- Slog.w(TAG, "Unable to launch app "
+ String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
- + r.intent.getIntent() + ": user " + r.userId + " is stopped");
+ + r.intent.getIntent() + ": user " + r.userId + " is stopped";
+ Slog.w(TAG, msg);
bringDownServiceLocked(r, true);
- return false;
+ return msg;
}
// Service is now being launched, its package can't be stopped.
@@ -1018,7 +1020,7 @@ public class ActiveServices {
try {
app.addPackage(r.appInfo.packageName);
realStartServiceLocked(r, app);
- return true;
+ return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
@@ -1041,12 +1043,13 @@ public class ActiveServices {
if (app == null) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated)) == null) {
- Slog.w(TAG, "Unable to launch app "
+ String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
- + r.intent.getIntent() + ": process is bad");
+ + r.intent.getIntent() + ": process is bad";
+ Slog.w(TAG, msg);
bringDownServiceLocked(r, true);
- return false;
+ return msg;
}
if (isolated) {
r.isolatedProc = app;
@@ -1057,7 +1060,7 @@ public class ActiveServices {
mPendingServices.add(r);
}
- return true;
+ return null;
}
private final void requestServiceBindingsLocked(ServiceRecord r) {
@@ -1850,7 +1853,7 @@ public class ActiveServices {
}
if (anrMessage != null) {
- mAm.appNotResponding(proc, null, null, anrMessage);
+ mAm.appNotResponding(proc, null, null, false, anrMessage);
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e90eef9..daed0a2 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
@@ -970,7 +971,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mShowDialogs) {
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
- mContext, proc, (ActivityRecord)data.get("activity"));
+ mContext, proc, (ActivityRecord)data.get("activity"),
+ msg.arg1 != 0);
d.show();
proc.anrDialog = d;
} else {
@@ -3247,7 +3249,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
- ActivityRecord parent, final String annotation) {
+ ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
@@ -3388,6 +3390,7 @@ public final class ActivityManagerService extends ActivityManagerNative
HashMap map = new HashMap();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
+ msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
@@ -3582,7 +3585,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "Failed trying to unstop package "
+ packageName + ": " + e);
}
- if (isUserRunningLocked(user)) {
+ if (isUserRunningLocked(user, false)) {
forceStopPackageLocked(packageName, pkgUid);
}
}
@@ -7340,6 +7343,51 @@ public final class ActivityManagerService extends ActivityManagerNative
SystemProperties.set("ctl.start", "bugreport");
}
+ public long inputDispatchingTimedOut(int pid, boolean aboveSystem) {
+ if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.FILTER_EVENTS);
+ }
+
+ ProcessRecord proc;
+
+ // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut().
+ synchronized (this) {
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(pid);
+ }
+ if (proc != null) {
+ if (proc.debugging) {
+ return -1;
+ }
+
+ if (mDidDexOpt) {
+ // Give more time since we were dexopting.
+ mDidDexOpt = false;
+ return -1;
+ }
+
+ if (proc.instrumentationClass != null) {
+ Bundle info = new Bundle();
+ info.putString("shortMsg", "keyDispatchingTimedOut");
+ info.putString("longMsg", "Timed out while dispatching key event");
+ finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
+ proc = null;
+ }
+ }
+ }
+
+ if (proc != null) {
+ appNotResponding(proc, null, null, aboveSystem, "keyDispatchingTimedOut");
+ if (proc.instrumentationClass != null || proc.usingWrapper) {
+ return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
+ }
+ }
+
+ return KEY_DISPATCHING_TIMEOUT;
+ }
+
public void registerProcessObserver(IProcessObserver observer) {
enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
"registerProcessObserver()");
@@ -7406,6 +7454,7 @@ public final class ActivityManagerService extends ActivityManagerNative
lp.format = v.getBackground().getOpacity();
lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
((WindowManager)mContext.getSystemService(
Context.WINDOW_SERVICE)).addView(v, lp);
}
@@ -7856,6 +7905,19 @@ public final class ActivityManagerService extends ActivityManagerNative
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
+ intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ }
+ }, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -8831,7 +8893,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(" [-a] [-c] [-h] [cmd] ...");
pw.println(" cmd may be one of:");
pw.println(" a[ctivities]: activity stack state");
- pw.println(" b[roadcasts] [PACKAGE_NAME]: broadcast state");
+ pw.println(" b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state");
pw.println(" i[ntents] [PACKAGE_NAME]: pending intent state");
pw.println(" p[rocesses] [PACKAGE_NAME]: process state");
pw.println(" o[om]: out of memory management");
@@ -9290,6 +9352,12 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" User #"); pw.print(uss.mHandle.getIdentifier());
pw.print(": "); uss.dump("", pw);
}
+ pw.print(" mStartedUserArray: [");
+ for (int i=0; i<mStartedUserArray.length; i++) {
+ if (i > 0) pw.print(", ");
+ pw.print(mStartedUserArray[i]);
+ }
+ pw.println("]");
pw.print(" mUserLru: [");
for (int i=0; i<mUserLru.size(); i++) {
if (i > 0) pw.print(", ");
@@ -9659,6 +9727,9 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean onlyHistory = false;
if ("history".equals(dumpPackage)) {
+ if (opti < args.length && "-s".equals(args[opti])) {
+ dumpAll = false;
+ }
onlyHistory = true;
dumpPackage = null;
}
@@ -14055,15 +14126,17 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
- mWindowManager.lockNow();
mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
R.anim.screen_user_enter);
+ boolean needStart = false;
+
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
updateStartedUserArrayLocked();
+ needStart = true;
}
mCurrentUserId = userId;
@@ -14074,25 +14147,48 @@ public final class ActivityManagerService extends ActivityManagerNative
mWindowManager.setCurrentUser(userId);
+ // Once the internal notion of the active user has switched, we lock the device
+ // with the option to show the user switcher on the keyguard.
+ mWindowManager.lockNow(LockPatternUtils.USER_SWITCH_LOCK_OPTIONS);
+
final UserStartedState uss = mStartedUsers.get(userId);
+ // Make sure user is in the started state. If it is currently
+ // stopping, we need to knock that off.
+ if (uss.mState == UserStartedState.STATE_STOPPING) {
+ // If we are stopping, we haven't sent ACTION_SHUTDOWN,
+ // so we can just fairly silently bring the user back from
+ // the almost-dead.
+ uss.mState = UserStartedState.STATE_RUNNING;
+ updateStartedUserArrayLocked();
+ needStart = true;
+ } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {
+ // This means ACTION_SHUTDOWN has been sent, so we will
+ // need to treat this as a new boot of the user.
+ uss.mState = UserStartedState.STATE_BOOTING;
+ updateStartedUserArrayLocked();
+ needStart = true;
+ }
+
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
- Intent intent = new Intent(Intent.ACTION_USER_STARTED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- | Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- broadcastIntentLocked(null, null, intent,
- null, null, 0, null, null, null,
- false, false, MY_PID, Process.SYSTEM_UID, userId);
+ if (needStart) {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, userId);
+ }
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
if (userId != 0) {
- intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@@ -14116,6 +14212,21 @@ public final class ActivityManagerService extends ActivityManagerNative
getUserManagerLocked().userForeground(userId);
sendUserSwitchBroadcastsLocked(oldUserId, userId);
+ if (needStart) {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null, null, intent,
+ null, new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+ throws RemoteException {
+ }
+ }, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -14263,7 +14374,8 @@ public final class ActivityManagerService extends ActivityManagerNative
num--;
continue;
}
- if (oldUss.mState == UserStartedState.STATE_STOPPING) {
+ if (oldUss.mState == UserStartedState.STATE_STOPPING
+ || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
// This user is already stopping, doesn't count.
num--;
i++;
@@ -14328,23 +14440,51 @@ public final class ActivityManagerService extends ActivityManagerNative
uss.mStopCallbacks.add(callback);
}
- if (uss.mState != UserStartedState.STATE_STOPPING) {
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
uss.mState = UserStartedState.STATE_STOPPING;
+ updateStartedUserArrayLocked();
long ident = Binder.clearCallingIdentity();
try {
- // Inform of user switch
- Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() {
+ // We are going to broadcast ACTION_USER_STOPPING and then
+ // once that is down send a final ACTION_SHUTDOWN and then
+ // stop the user.
+ final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
+ stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+ // This is the result receiver for the final shutdown broadcast.
+ final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
finishUserStop(uss);
}
};
- broadcastIntentLocked(null, null, intent,
- null, resultReceiver, 0, null, null, null,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
+ // This is the result receiver for the initial stopping broadcast.
+ final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data,
+ Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+ // On to the next.
+ synchronized (ActivityManagerService.this) {
+ if (uss.mState != UserStartedState.STATE_STOPPING) {
+ // Whoops, we are being started back up. Abort, abort!
+ return;
+ }
+ uss.mState = UserStartedState.STATE_SHUTDOWN;
+ }
+ broadcastIntentLocked(null, null, shutdownIntent,
+ null, shutdownReceiver, 0, null, null, null,
+ true, false, MY_PID, Process.SYSTEM_UID, userId);
+ }
+ };
+ // Kick things off.
+ broadcastIntentLocked(null, null, stoppingIntent,
+ null, stoppingReceiver, 0, null, null,
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -14359,8 +14499,9 @@ public final class ActivityManagerService extends ActivityManagerNative
ArrayList<IStopUserCallback> callbacks;
synchronized (this) {
callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);
- if (uss.mState != UserStartedState.STATE_STOPPING
- || mStartedUsers.get(userId) != uss) {
+ if (mStartedUsers.get(userId) != uss) {
+ stopped = false;
+ } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {
stopped = false;
} else {
stopped = true;
@@ -14407,7 +14548,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
- public boolean isUserRunning(int userId) {
+ public boolean isUserRunning(int userId, boolean orStopped) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: isUserRunning() from pid="
@@ -14418,13 +14559,20 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
synchronized (this) {
- return isUserRunningLocked(userId);
+ return isUserRunningLocked(userId, orStopped);
}
}
- boolean isUserRunningLocked(int userId) {
+ boolean isUserRunningLocked(int userId, boolean orStopped) {
UserStartedState state = mStartedUsers.get(userId);
- return state != null && state.mState != UserStartedState.STATE_STOPPING;
+ if (state == null) {
+ return false;
+ }
+ if (orStopped) {
+ return true;
+ }
+ return state.mState != UserStartedState.STATE_STOPPING
+ && state.mState != UserStartedState.STATE_SHUTDOWN;
}
@Override
@@ -14444,9 +14592,24 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private void updateStartedUserArrayLocked() {
- mStartedUserArray = new int[mStartedUsers.size()];
+ int num = 0;
+ for (int i=0; i<mStartedUsers.size(); i++) {
+ UserStartedState uss = mStartedUsers.valueAt(i);
+ // This list does not include stopping users.
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ num++;
+ }
+ }
+ mStartedUserArray = new int[num];
+ num = 0;
for (int i=0; i<mStartedUsers.size(); i++) {
- mStartedUserArray[i] = mStartedUsers.keyAt(i);
+ UserStartedState uss = mStartedUsers.valueAt(i);
+ if (uss.mState != UserStartedState.STATE_STOPPING
+ && uss.mState != UserStartedState.STATE_SHUTDOWN) {
+ mStartedUserArray[num] = mStartedUsers.keyAt(i);
+ num++;
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 6cd86fd..b9f5b5b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -841,6 +841,7 @@ final class ActivityRecord {
}
public boolean keyDispatchingTimedOut() {
+ // TODO: Unify this code with ActivityManagerService.inputDispatchingTimedOut().
ActivityRecord r;
ProcessRecord anrApp = null;
synchronized(service) {
@@ -869,8 +870,7 @@ final class ActivityRecord {
}
if (anrApp != null) {
- service.appNotResponding(anrApp, r, this,
- "keyDispatchingTimedOut");
+ service.appNotResponding(anrApp, r, this, false, "keyDispatchingTimedOut");
}
return true;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 90a7abc..4bcb339 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -420,12 +420,17 @@ final class ActivityStack {
mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
mLaunchingActivity.setReferenceCounted(false);
}
-
+
+ private boolean okToShow(ActivityRecord r) {
+ return r.userId == mCurrentUser
+ || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
+ }
+
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -437,7 +442,7 @@ final class ActivityStack {
int i = mHistory.size()-1;
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
- if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
+ if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
return r;
}
i--;
@@ -460,7 +465,7 @@ final class ActivityStack {
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
- && r.userId == mCurrentUser) {
+ && okToShow(r)) {
return r;
}
i--;
@@ -1806,7 +1811,8 @@ final class ActivityStack {
mHistory.add(addPos, r);
r.putInHistory();
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
@@ -1870,7 +1876,8 @@ final class ActivityStack {
}
r.updateOptionsLocked(options);
mService.mWindowManager.addAppToken(
- addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+ addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1908,7 +1915,8 @@ final class ActivityStack {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
- r.info.screenOrientation, r.fullscreen);
+ r.info.screenOrientation, r.fullscreen,
+ (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
ActivityOptions.abort(options);
}
if (VALIDATE_TOKENS) {
@@ -2436,8 +2444,8 @@ final class ActivityStack {
if (err == ActivityManager.START_SUCCESS) {
final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
- Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
- + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+ Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
}
ActivityRecord sourceRecord = null;
@@ -2616,7 +2624,6 @@ final class ActivityStack {
Bundle options) {
final Intent intent = r.intent;
final int callingUid = r.launchedFromUid;
- final int userId = r.userId;
int launchFlags = intent.getFlags();
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java
index 0ebbe3b..ffa1e92 100644
--- a/services/java/com/android/server/am/AppErrorDialog.java
+++ b/services/java/com/android/server/am/AppErrorDialog.java
@@ -23,12 +23,9 @@ import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
-import android.util.Slog;
import android.view.WindowManager;
class AppErrorDialog extends BaseErrorDialog {
- private final static String TAG = "AppErrorDialog";
-
private final ActivityManagerService mService;
private final AppErrorResult mResult;
private final ProcessRecord mProc;
@@ -76,7 +73,10 @@ class AppErrorDialog extends BaseErrorDialog {
setTitle(res.getText(com.android.internal.R.string.aerr_title));
getWindow().addFlags(FLAG_SYSTEM_ERROR);
- getWindow().setTitle("Application Error: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Application Error: " + app.info.processName);
+ attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
if (app.persistent) {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
}
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java
index b546ae7..af61c9b 100644
--- a/services/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/java/com/android/server/am/AppNotRespondingDialog.java
@@ -25,8 +25,8 @@ import android.content.Intent;
import android.content.res.Resources;
import android.os.Handler;
import android.os.Message;
-import android.os.Process;
import android.util.Slog;
+import android.view.WindowManager;
class AppNotRespondingDialog extends BaseErrorDialog {
private static final String TAG = "AppNotRespondingDialog";
@@ -40,7 +40,7 @@ class AppNotRespondingDialog extends BaseErrorDialog {
private final ProcessRecord mProc;
public AppNotRespondingDialog(ActivityManagerService service, Context context,
- ProcessRecord app, ActivityRecord activity) {
+ ProcessRecord app, ActivityRecord activity, boolean aboveSystem) {
super(context);
mService = service;
@@ -91,8 +91,14 @@ class AppNotRespondingDialog extends BaseErrorDialog {
}
setTitle(res.getText(com.android.internal.R.string.anr_title));
+ if (aboveSystem) {
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+ }
getWindow().addFlags(FLAG_SYSTEM_ERROR);
- getWindow().setTitle("Application Not Responding: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Application Not Responding: " + app.info.processName);
+ attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
index 9fb48b3..d08bb10 100644
--- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
+++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager;
class AppWaitingForDebuggerDialog extends BaseErrorDialog {
final ActivityManagerService mService;
@@ -52,7 +53,9 @@ class AppWaitingForDebuggerDialog extends BaseErrorDialog {
setMessage(text.toString());
setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app));
setTitle("Waiting For Debugger");
- getWindow().setTitle("Waiting For Debugger: " + app.info.processName);
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Waiting For Debugger: " + app.info.processName);
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java
index d1e89bc..6ede8f8 100644
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -33,7 +33,9 @@ class BaseErrorDialog extends AlertDialog {
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
- getWindow().setTitle("Error Dialog");
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Error Dialog");
+ getWindow().setAttributes(attrs);
setIconAttribute(R.attr.alertDialogIcon);
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 9f27994..f9630ae 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -54,6 +54,7 @@ public class BroadcastQueue {
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
static final int MAX_BROADCAST_HISTORY = 25;
+ static final int MAX_BROADCAST_SUMMARY_HISTORY = 100;
final ActivityManagerService mService;
@@ -93,6 +94,12 @@ public class BroadcastQueue {
= new BroadcastRecord[MAX_BROADCAST_HISTORY];
/**
+ * Summary of historical data of past broadcasts, for debugging.
+ */
+ final Intent[] mBroadcastSummaryHistory
+ = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+
+ /**
* Set when we current have a BROADCAST_INTENT_MSG in flight.
*/
boolean mBroadcastsScheduled = false;
@@ -151,7 +158,7 @@ public class BroadcastQueue {
@Override
public void run() {
- mService.appNotResponding(mApp, null, null, mAnnotation);
+ mService.appNotResponding(mApp, null, null, false, mAnnotation);
}
}
@@ -922,6 +929,9 @@ public class BroadcastQueue {
MAX_BROADCAST_HISTORY-1);
r.finishTime = SystemClock.uptimeMillis();
mBroadcastHistory[0] = r;
+ System.arraycopy(mBroadcastSummaryHistory, 0, mBroadcastSummaryHistory, 1,
+ MAX_BROADCAST_SUMMARY_HISTORY-1);
+ mBroadcastSummaryHistory[0] = r.intent;
}
final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
@@ -1006,8 +1016,9 @@ public class BroadcastQueue {
}
}
+ int i;
boolean printed = false;
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ for (i=0; i<MAX_BROADCAST_HISTORY; i++) {
BroadcastRecord r = mBroadcastHistory[i];
if (r == null) {
break;
@@ -1028,11 +1039,44 @@ public class BroadcastQueue {
pw.print(i); pw.println(":");
r.dump(pw, " ");
} else {
- if (i >= 50) {
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ pw.print(" ");
+ pw.println(r.intent.toShortString(false, true, true, false));
+ Bundle bundle = r.intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
+ }
+ }
+
+ if (dumpPackage == null) {
+ if (dumpAll) {
+ i = 0;
+ printed = false;
+ }
+ for (; i<MAX_BROADCAST_SUMMARY_HISTORY; i++) {
+ Intent intent = mBroadcastSummaryHistory[i];
+ if (intent == null) {
+ break;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts summary [" + mQueueName + "]:");
+ printed = true;
+ }
+ if (!dumpAll && i >= 50) {
pw.println(" ...");
break;
}
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.println(intent.toShortString(false, true, true, false));
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ pw.print(" extras: "); pw.println(bundle.toString());
+ }
}
}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 85ec328..1cf5b9c 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -81,12 +81,10 @@ class BroadcastRecord extends Binder {
final long now = SystemClock.uptimeMillis();
pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
- pw.print(prefix); pw.println(intent);
- if (sticky) {
- Bundle bundle = intent.getExtras();
- if (bundle != null) {
- pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
- }
+ pw.print(prefix); pw.println(intent.toInsecureString());
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ pw.print(prefix); pw.print("extras: "); pw.println(bundle.toString());
}
pw.print(prefix); pw.print("caller="); pw.print(callerPackage); pw.print(" ");
pw.print(callerApp != null ? callerApp.toShortString() : "null");
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java
index b19bb5c..0ffb588 100644
--- a/services/java/com/android/server/am/FactoryErrorDialog.java
+++ b/services/java/com/android/server/am/FactoryErrorDialog.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager;
class FactoryErrorDialog extends BaseErrorDialog {
public FactoryErrorDialog(Context context, CharSequence msg) {
@@ -30,7 +31,9 @@ class FactoryErrorDialog extends BaseErrorDialog {
setButton(DialogInterface.BUTTON_POSITIVE,
context.getText(com.android.internal.R.string.factorytest_reboot),
mHandler.obtainMessage(0));
- getWindow().setTitle("Factory Error");
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.setTitle("Factory Error");
+ getWindow().setAttributes(attrs);
}
public void onStop() {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 652fdb5..7fbab04 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -407,7 +407,7 @@ class ProcessRecord {
sb.append('u');
sb.append(userId);
sb.append('a');
- sb.append(info.uid%Process.FIRST_APPLICATION_UID);
+ sb.append(UserHandle.getAppId(info.uid));
if (uid != info.uid) {
sb.append('i');
sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/java/com/android/server/am/UserStartedState.java
index 50c8553..0e71f81 100644
--- a/services/java/com/android/server/am/UserStartedState.java
+++ b/services/java/com/android/server/am/UserStartedState.java
@@ -23,9 +23,14 @@ import android.app.IStopUserCallback;
import android.os.UserHandle;
public class UserStartedState {
+ // User is first coming up.
public final static int STATE_BOOTING = 0;
+ // User is in the normal running state.
public final static int STATE_RUNNING = 1;
+ // User is in the initial process of being stopped.
public final static int STATE_STOPPING = 2;
+ // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
+ public final static int STATE_SHUTDOWN = 3;
public final UserHandle mHandle;
public final ArrayList<IStopUserCallback> mStopCallbacks
@@ -40,7 +45,14 @@ public class UserStartedState {
}
void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mState="); pw.print(mState);
+ pw.print(prefix); pw.print("mState=");
+ switch (mState) {
+ case STATE_BOOTING: pw.print("BOOTING"); break;
+ case STATE_RUNNING: pw.print("RUNNING"); break;
+ case STATE_STOPPING: pw.print("STOPPING"); break;
+ case STATE_SHUTDOWN: pw.print("SHUTDOWN"); break;
+ default: pw.print(mState); break;
+ }
if (switching) pw.print(" SWITCHING");
if (initializing) pw.print(" INITIALIZING");
pw.println();
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index b38d617..e4a7ead 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -454,7 +454,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (mTetheredNotification.icon == icon) {
return;
}
- notificationManager.cancel(mTetheredNotification.icon);
+ notificationManager.cancelAsUser(null, mTetheredNotification.icon,
+ UserHandle.ALL);
}
Intent intent = new Intent();
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index f5aa3d4..a3ab3c1 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -105,6 +105,18 @@ abstract class DisplayDevice {
}
/**
+ * Blanks the display, if supported.
+ */
+ public void blankLocked() {
+ }
+
+ /**
+ * Unblanks the display, if supported.
+ */
+ public void unblankLocked() {
+ }
+
+ /**
* Sets the display layer stack while in a transaction.
*/
public final void setLayerStackInTransactionLocked(int layerStack) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index b8c6cd5..0a42528 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -103,6 +103,10 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
private static final int MSG_REQUEST_TRAVERSAL = 4;
private static final int MSG_UPDATE_VIEWPORT = 5;
+ private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
+ private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
+ private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
+
private final Context mContext;
private final boolean mHeadless;
private final DisplayManagerHandler mHandler;
@@ -141,6 +145,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+ // Set to true if all displays have been blanked by the power manager.
+ private int mAllDisplayBlankStateFromPowerManager;
+
// Set to true when there are pending display changes that have yet to be applied
// to the surface flinger state.
private boolean mPendingTraversal;
@@ -286,6 +293,40 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
/**
+ * Called by the power manager to blank all displays.
+ */
+ public void blankAllDisplaysFromPowerManager() {
+ synchronized (mSyncRoot) {
+ if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
+ mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
+
+ final int count = mDisplayDevices.size();
+ for (int i = 0; i < count; i++) {
+ DisplayDevice device = mDisplayDevices.get(i);
+ device.blankLocked();
+ }
+ }
+ }
+ }
+
+ /**
+ * Called by the power manager to unblank all displays.
+ */
+ public void unblankAllDisplaysFromPowerManager() {
+ synchronized (mSyncRoot) {
+ if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
+ mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
+
+ final int count = mDisplayDevices.size();
+ for (int i = 0; i < count; i++) {
+ DisplayDevice device = mDisplayDevices.get(i);
+ device.unblankLocked();
+ }
+ }
+ }
+ }
+
+ /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
@@ -528,6 +569,17 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
mDisplayDevices.add(device);
addLogicalDisplayLocked(device);
scheduleTraversalLocked(false);
+
+ // Blank or unblank the display immediately to match the state requested
+ // by the power manager (if known).
+ switch (mAllDisplayBlankStateFromPowerManager) {
+ case DISPLAY_BLANK_STATE_BLANKED:
+ device.blankLocked();
+ break;
+ case DISPLAY_BLANK_STATE_UNBLANKED:
+ device.unblankLocked();
+ break;
+ }
}
}
@@ -788,9 +840,18 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
pw.println("DISPLAY MANAGER (dumpsys display)");
- pw.println(" mHeadless=" + mHeadless);
synchronized (mSyncRoot) {
+ pw.println(" mHeadless=" + mHeadless);
+ pw.println(" mOnlyCode=" + mOnlyCore);
+ pw.println(" mSafeMode=" + mSafeMode);
+ pw.println(" mPendingTraversal=" + mPendingTraversal);
+ pw.println(" mAllDisplayBlankStateFromPowerManager="
+ + mAllDisplayBlankStateFromPowerManager);
+ pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
+ pw.println(" mDefaultViewport=" + mDefaultViewport);
+ pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
+
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
@@ -817,10 +878,6 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw);
}
-
- pw.println();
- pw.println("Default viewport: " + mDefaultViewport);
- pw.println("External touch viewport: " + mExternalTouchViewport);
}
}
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 679a67e..d780006 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -92,6 +92,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
+ private boolean mBlanked;
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
PhysicalDisplayInfo phys) {
@@ -150,10 +151,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void blankLocked() {
+ mBlanked = true;
+ Surface.blankDisplay(getDisplayTokenLocked());
+ }
+
+ @Override
+ public void unblankLocked() {
+ mBlanked = false;
+ Surface.unblankDisplay(getDisplayTokenLocked());
+ }
+
+ @Override
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
pw.println("mPhys=" + mPhys);
+ pw.println("mBlanked=" + mBlanked);
}
}
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java
index 6db495a..bfb60bb 100644
--- a/services/java/com/android/server/dreams/DreamController.java
+++ b/services/java/com/android/server/dreams/DreamController.java
@@ -132,8 +132,15 @@ final class DreamController {
}
if (oldDream.mService != null) {
- // TODO: It would be nice to tell the dream that it's being stopped so that
- // it can shut down nicely before we yank its window token out from under it.
+ // Tell the dream that it's being stopped so that
+ // it can shut down nicely before we yank its window token out from
+ // under it.
+ try {
+ oldDream.mService.detach();
+ } catch (RemoteException ex) {
+ // we don't care; this thing is on the way out
+ }
+
try {
oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
} catch (NoSuchElementException ex) {
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index 7d030e9..f5cc59f 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -21,6 +21,7 @@ import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import com.android.server.ServiceWatcher;
@@ -38,8 +39,8 @@ public class GeocoderProxy {
private final ServiceWatcher mServiceWatcher;
public static GeocoderProxy createAndBind(Context context,
- List<String> initialPackageNames) {
- GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames);
+ List<String> initialPackageNames, int userId) {
+ GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames, userId);
if (proxy.bind()) {
return proxy;
} else {
@@ -47,11 +48,11 @@ public class GeocoderProxy {
}
}
- public GeocoderProxy(Context context, List<String> initialPackageNames) {
+ public GeocoderProxy(Context context, List<String> initialPackageNames, int userId) {
mContext = context;
mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, initialPackageNames,
- null, null);
+ null, null, userId);
}
private boolean bind () {
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java
index 26d9c15..d04d2f3 100644
--- a/services/java/com/android/server/location/GeofenceManager.java
+++ b/services/java/com/android/server/location/GeofenceManager.java
@@ -58,7 +58,6 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
private Object mLock = new Object();
// access to members below is synchronized on mLock
- private Location mLastLocation;
private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
public GeofenceManager(Context context, LocationBlacklist blacklist) {
@@ -77,7 +76,8 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent, int uid,
String packageName) {
- GeofenceState state = new GeofenceState(geofence, mLastLocation,
+ Location lastLocation = mLocationManager.getLastLocation();
+ GeofenceState state = new GeofenceState(geofence, lastLocation,
request.getExpireAt(), packageName, intent);
synchronized (mLock) {
@@ -146,8 +146,6 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
List<PendingIntent> exitIntents = new LinkedList<PendingIntent>();
synchronized (mLock) {
- mLastLocation = location;
-
removeExpiredFencesLocked();
for (GeofenceState state : mFences) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index a254d74..c272da4 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -783,6 +783,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
}
+ @Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
private void handleSetRequest(ProviderRequest request, WorkSource source) {
if (DEBUG) Log.d(TAG, "setRequest " + request);
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
index 6ad1a92..2437a37 100644
--- a/services/java/com/android/server/location/LocationBlacklist.java
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -20,6 +20,7 @@ package com.android.server.location;
import android.content.Context;
import android.database.ContentObserver;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
@@ -48,6 +49,8 @@ public final class LocationBlacklist extends ContentObserver {
// all fields below synchronized on mLock
private String[] mWhitelist = new String[0];
private String[] mBlacklist = new String[0];
+
+ private int mCurrentUserId = UserHandle.USER_OWNER;
public LocationBlacklist(Context context, Handler handler) {
super(handler);
@@ -56,20 +59,22 @@ public final class LocationBlacklist extends ContentObserver {
public void init() {
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
- BLACKLIST_CONFIG_NAME), false, this);
+ BLACKLIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
// mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
-// WHITELIST_CONFIG_NAME), false, this);
+// WHITELIST_CONFIG_NAME), false, this, UserHandle.USER_ALL);
reloadBlacklist();
}
+ private void reloadBlacklistLocked() {
+ mWhitelist = getStringArrayLocked(WHITELIST_CONFIG_NAME);
+ Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+ mBlacklist = getStringArrayLocked(BLACKLIST_CONFIG_NAME);
+ Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ }
+
private void reloadBlacklist() {
- String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
- String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
synchronized (mLock) {
- mWhitelist = whitelist;
- Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
- mBlacklist = blacklist;
- Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+ reloadBlacklistLocked();
}
}
@@ -78,7 +83,6 @@ public final class LocationBlacklist extends ContentObserver {
* (package name matches blacklist, and does not match whitelist)
*/
public boolean isBlacklisted(String packageName) {
- /*
synchronized (mLock) {
for (String black : mBlacklist) {
if (packageName.startsWith(black)) {
@@ -92,7 +96,6 @@ public final class LocationBlacklist extends ContentObserver {
}
}
}
- */
return false;
}
@@ -113,8 +116,19 @@ public final class LocationBlacklist extends ContentObserver {
reloadBlacklist();
}
- private String[] getStringArray(String key) {
- String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
+ public void switchUser(int userId) {
+ synchronized(mLock) {
+ mCurrentUserId = userId;
+ reloadBlacklistLocked();
+ }
+ }
+
+ private String[] getStringArrayLocked(String key) {
+ String flatString;
+ synchronized(mLock) {
+ flatString = Settings.Secure.getStringForUser(mContext.getContentResolver(), key,
+ mCurrentUserId);
+ }
if (flatString == null) {
return new String[0];
}
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index 6f09232..80e71f1 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -38,6 +38,8 @@ public interface LocationProviderInterface {
public boolean isEnabled();
public void setRequest(ProviderRequest request, WorkSource source);
+ public void switchUser(int userId);
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args);
// --- deprecated (but still supported) ---
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 7faf72c..dd2e71c 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -25,6 +25,7 @@ import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;
@@ -54,9 +55,9 @@ public class LocationProviderProxy implements LocationProviderInterface {
private WorkSource mWorksource = new WorkSource();
public static LocationProviderProxy createAndBind(Context context, String name, String action,
- List<String> initialPackageNames, Handler handler) {
+ List<String> initialPackageNames, Handler handler, int userId) {
LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
- initialPackageNames, handler);
+ initialPackageNames, handler, userId);
if (proxy.bind()) {
return proxy;
} else {
@@ -65,11 +66,11 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
private LocationProviderProxy(Context context, String name, String action,
- List<String> initialPackageNames, Handler handler) {
+ List<String> initialPackageNames, Handler handler, int userId) {
mContext = context;
mName = name;
mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames,
- mNewServiceWork, handler);
+ mNewServiceWork, handler, userId);
}
private boolean bind () {
@@ -211,6 +212,11 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
@Override
+ public void switchUser(int userId) {
+ mServiceWatcher.switchUser(userId);
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("REMOTE SERVICE");
pw.append(" name=").append(mName);
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index 36c43ff..1194cbc 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -156,6 +156,11 @@ public class MockProvider implements LocationProviderInterface {
public void setRequest(ProviderRequest request, WorkSource source) { }
@Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
+ @Override
public boolean sendExtraCommand(String command, Bundle extras) {
return false;
}
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 71bae07..734c572 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -96,6 +96,11 @@ public class PassiveProvider implements LocationProviderInterface {
mReportLocation = request.reportLocation;
}
+ @Override
+ public void switchUser(int userId) {
+ // nothing to do here
+ }
+
public void updateLocation(Location location) {
if (mReportLocation) {
try {
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0f3dc92..b8d7286 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1300,27 +1300,6 @@ public class PackageManagerService extends IPackageManager.Stub {
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
- // Verify that all of the preferred activity components actually
- // exist. It is possible for applications to be updated and at
- // that point remove a previously declared activity component that
- // had been set as a preferred activity. We try to clean this up
- // the next time we encounter that preferred activity, but it is
- // possible for the user flow to never be able to return to that
- // situation so here we do a sanity check to make sure we haven't
- // left any junk around.
- ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
- for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
- if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
- removed.add(pa);
- }
- }
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
- }
-
// can downgrade to reader
mSettings.writeLPr();
@@ -2504,9 +2483,11 @@ public class PackageManagerService extends IPackageManager.Stub {
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
- List<PreferredActivity> prefs =
- mSettings.mPreferredActivities.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ List<PreferredActivity> prefs = pir != null
+ ? pir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
+ : null;
if (prefs != null && prefs.size() > 0) {
// First figure out how good the original match set is.
// We will only allow preferred activities that came
@@ -2537,9 +2518,6 @@ public class PackageManagerService extends IPackageManager.Stub {
final int M = prefs.size();
for (int i=0; i<M; i++) {
final PreferredActivity pa = prefs.get(i);
- if (pa.mUserId != userId) {
- continue;
- }
if (pa.mPref.mMatch != match) {
continue;
}
@@ -2560,7 +2538,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// it from the preferred activities list, and skip it.
Slog.w(TAG, "Removing dangling preferred activity: "
+ pa.mPref.mComponent);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
continue;
}
for (int j=0; j<N; j++) {
@@ -2580,7 +2558,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!pa.mPref.sameSet(query, priority)) {
Slog.i(TAG, "Result set changed, dropping preferred activity for "
+ intent + " type " + resolvedType);
- mSettings.mPreferredActivities.removeFilter(pa);
+ pir.removeFilter(pa);
return null;
}
@@ -6396,12 +6374,22 @@ public class PackageManagerService extends IPackageManager.Stub {
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
+ /*
+ * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
+ * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
+ */
+ int userIdentifier = getUser().getIdentifier();
+ if (userIdentifier == UserHandle.USER_ALL
+ && ((flags & PackageManager.INSTALL_FROM_ADB) != 0)) {
+ userIdentifier = UserHandle.USER_OWNER;
+ }
+
/*
* Determine if we have any installed package verifiers. If we
* do, then we'll defer to them to verify the packages.
*/
final int requiredUid = mRequiredVerifierPackage == null ? -1
- : getPackageUid(mRequiredVerifierPackage, getUser().getIdentifier());
+ : getPackageUid(mRequiredVerifierPackage, userIdentifier);
if (requiredUid != -1 && isVerificationEnabled(flags)) {
final Intent verification = new Intent(
Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
@@ -8682,9 +8670,9 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- mSettings.mPreferredActivities.addFilter(
- new PreferredActivity(filter, match, set, activity, userId));
- scheduleWriteSettingsLocked();
+ mSettings.editPreferredActivitiesLPw(userId).addFilter(
+ new PreferredActivity(filter, match, set, activity));
+ mSettings.writePackageRestrictionsLPr(userId);
}
}
@@ -8722,25 +8710,27 @@ public class PackageManagerService extends IPackageManager.Stub {
final int callingUserId = UserHandle.getCallingUserId();
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- String action = filter.getAction(0);
- String category = filter.getCategory(0);
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (pa.mUserId != callingUserId) continue;
- if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
+ if (pir != null) {
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ String action = filter.getAction(0);
+ String category = filter.getCategory(0);
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
+ Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- removed.add(pa);
- Log.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- }
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
+ if (removed != null) {
+ for (int i=0; i<removed.size(); i++) {
+ PreferredActivity pa = removed.get(i);
+ pir.removeFilter(pa);
+ }
}
}
addPreferredActivity(filter, match, set, activity, callingUserId);
@@ -8776,27 +8766,33 @@ public class PackageManagerService extends IPackageManager.Stub {
/** This method takes a specific user id as well as UserHandle.USER_ALL. */
boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
ArrayList<PreferredActivity> removed = null;
- Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- PreferredActivity pa = it.next();
- if (userId != UserHandle.USER_ALL && pa.mUserId != userId) {
+ boolean changed = false;
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ final int thisUserId = mSettings.mPreferredActivities.keyAt(i);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ if (userId != UserHandle.USER_ALL && userId != thisUserId) {
continue;
}
- if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (removed == null) {
- removed = new ArrayList<PreferredActivity>();
+ Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ PreferredActivity pa = it.next();
+ if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<PreferredActivity>();
+ }
+ removed.add(pa);
}
- removed.add(pa);
}
- }
- if (removed != null) {
- for (int i=0; i<removed.size(); i++) {
- PreferredActivity pa = removed.get(i);
- mSettings.mPreferredActivities.removeFilter(pa);
+ if (removed != null) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(j);
+ pir.removeFilter(pa);
+ }
+ changed = true;
+ mSettings.writePackageRestrictionsLPr(thisUserId);
}
- return true;
}
- return false;
+ return changed;
}
public int getPreferredActivities(List<IntentFilter> outFilters,
@@ -8806,19 +8802,19 @@ public class PackageManagerService extends IPackageManager.Stub {
final int userId = UserHandle.getCallingUserId();
// reader
synchronized (mPackages) {
- final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
- while (it.hasNext()) {
- final PreferredActivity pa = it.next();
- if (pa.mUserId != userId) {
- continue;
- }
- if (packageName == null
- || pa.mPref.mComponent.getPackageName().equals(packageName)) {
- if (outFilters != null) {
- outFilters.add(new IntentFilter(pa));
- }
- if (outActivities != null) {
- outActivities.add(pa.mPref.mComponent);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+ if (pir != null) {
+ final Iterator<PreferredActivity> it = pir.filterIterator();
+ while (it.hasNext()) {
+ final PreferredActivity pa = it.next();
+ if (packageName == null
+ || pa.mPref.mComponent.getPackageName().equals(packageName)) {
+ if (outFilters != null) {
+ outFilters.add(new IntentFilter(pa));
+ }
+ if (outActivities != null) {
+ outActivities.add(pa.mPref.mComponent);
+ }
}
}
}
@@ -9041,6 +9037,39 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
+
+ synchronized (mPackages) {
+ // Verify that all of the preferred activity components actually
+ // exist. It is possible for applications to be updated and at
+ // that point remove a previously declared activity component that
+ // had been set as a preferred activity. We try to clean this up
+ // the next time we encounter that preferred activity, but it is
+ // possible for the user flow to never be able to return to that
+ // situation so here we do a sanity check to make sure we haven't
+ // left any junk around.
+ ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ removed.clear();
+ for (PreferredActivity pa : pir.filterSet()) {
+ if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
+ removed.add(pa);
+ }
+ }
+ if (removed.size() > 0) {
+ for (int j=0; j<removed.size(); j++) {
+ PreferredActivity pa = removed.get(i);
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent, here);
+ pir.removeFilter(pa);
+ }
+ mSettings.writePackageRestrictionsLPr(
+ mSettings.mPreferredActivities.keyAt(i));
+ }
+ }
+ }
}
public boolean isSafeMode() {
@@ -9281,11 +9310,16 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- if (mSettings.mPreferredActivities.dump(pw,
- dumpState.getTitlePrinted() ? "\nPreferred Activities:"
- : "Preferred Activities:", " ",
- packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
- dumpState.setTitlePrinted(true);
+ for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
+ int user = mSettings.mPreferredActivities.keyAt(i);
+ if (pir.dump(pw,
+ dumpState.getTitlePrinted()
+ ? "\nPreferred Activities User " + user + ":"
+ : "Preferred Activities User " + user + ":", " ",
+ packageName, dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
+ dumpState.setTitlePrinted(true);
+ }
}
}
@@ -9299,7 +9333,7 @@ public class PackageManagerService extends IPackageManager.Stub {
serializer.startDocument(null, true);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
- mSettings.writePreferredActivitiesLPr(serializer);
+ mSettings.writePreferredActivitiesLPr(serializer, 0);
serializer.endDocument();
serializer.flush();
} catch (IllegalArgumentException e) {
@@ -10045,11 +10079,6 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Called by UserManagerService */
void cleanUpUserLILPw(int userHandle) {
- // Disable all the packages for the user first
- Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userHandle);
- }
if (mDirtyUsers.remove(userHandle));
mSettings.removeUserLPr(userHandle);
if (mInstaller != null) {
@@ -10063,17 +10092,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Called by UserManagerService */
void createNewUserLILPw(int userHandle, File path) {
if (mInstaller != null) {
- path.mkdir();
- FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
- for (PackageSetting ps : mSettings.mPackages.values()) {
- // Only system apps are initially installed.
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
- // Need to create a data directory for all apps under this user.
- mInstaller.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle);
- }
- mSettings.writePackageRestrictionsLPr(userHandle);
+ mSettings.createNewUserLILPw(mInstaller, userHandle, path);
}
}
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index 5539e84..dbf56ef 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -36,32 +36,17 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb
static final String ATTR_USER_ID = "userId";
final PreferredComponent mPref;
- final int mUserId;
PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
- this(filter, match, set, activity, 0);
- }
-
- PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
- int userId) {
super(filter);
- mUserId = userId;
mPref = new PreferredComponent(this, match, set, activity);
}
PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
- String userIdString = parser.getAttributeValue(null, ATTR_USER_ID);
- if (userIdString != null && userIdString.length() > 0) {
- mUserId = Integer.parseInt(userIdString);
- } else {
- // Old format with no userId specified - assume primary user
- mUserId = 0;
- }
mPref = new PreferredComponent(this, parser);
}
public void writeToXml(XmlSerializer serializer) throws IOException {
- serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId));
mPref.writeToXml(serializer);
serializer.startTag(null, "filter");
super.writeToXml(serializer);
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/java/com/android/server/pm/PreferredIntentResolver.java
new file mode 100644
index 0000000..3f1e50c
--- /dev/null
+++ b/services/java/com/android/server/pm/PreferredIntentResolver.java
@@ -0,0 +1,38 @@
+/*
+ * 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.pm;
+
+import java.io.PrintWriter;
+
+import com.android.server.IntentResolver;
+
+public class PreferredIntentResolver
+ extends IntentResolver<PreferredActivity, PreferredActivity> {
+ @Override
+ protected PreferredActivity[] newArray(int size) {
+ return new PreferredActivity[size];
+ }
+ @Override
+ protected String packageForFilter(PreferredActivity filter) {
+ return filter.mPref.mComponent.getPackageName();
+ }
+ @Override
+ protected void dumpFilter(PrintWriter out, String prefix,
+ PreferredActivity filter) {
+ filter.mPref.dump(out, prefix, filter);
+ }
+}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index bdf5044..3a54514 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -70,6 +70,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
import libcore.io.IoUtils;
@@ -123,22 +125,9 @@ final class Settings {
// The user's preferred activities associated with particular intent
// filters.
- final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities =
- new IntentResolver<PreferredActivity, PreferredActivity>() {
- @Override
- protected PreferredActivity[] newArray(int size) {
- return new PreferredActivity[size];
- }
- @Override
- protected String packageForFilter(PreferredActivity filter) {
- return filter.mPref.mComponent.getPackageName();
- }
- @Override
- protected void dumpFilter(PrintWriter out, String prefix,
- PreferredActivity filter) {
- filter.mPref.dump(out, prefix, filter);
- }
- };
+ final SparseArray<PreferredIntentResolver> mPreferredActivities =
+ new SparseArray<PreferredIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -745,6 +734,15 @@ final class Settings {
}
}
+ PreferredIntentResolver editPreferredActivitiesLPw(int userId) {
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir == null) {
+ pir = new PreferredIntentResolver();
+ mPreferredActivities.put(userId, pir);
+ }
+ return pir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -775,6 +773,35 @@ final class Settings {
}
}
+ private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PreferredActivity pa = new PreferredActivity(parser);
+ if (pa.mPref.getParseError() == null) {
+ editPreferredActivitiesLPw(userId).addFilter(pa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: <preferred-activity> "
+ + pa.mPref.getParseError() + " at "
+ + parser.getPositionDescription());
+ }
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -893,6 +920,8 @@ final class Settings {
ps.setUserState(userId, enabled, installed, stopped, notLaunched,
enabledComponents, disabledComponents);
+ } else if (tagName.equals("preferred-activities")) {
+ readPreferredActivitiesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -942,6 +971,20 @@ final class Settings {
return components;
}
+ void writePreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "preferred-activities");
+ PreferredIntentResolver pir = mPreferredActivities.get(userId);
+ if (pir != null) {
+ for (final PreferredActivity pa : pir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ pa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "preferred-activities");
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1028,6 +1071,8 @@ final class Settings {
}
}
+ writePreferredActivitiesLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1237,8 +1282,6 @@ final class Settings {
writeDisabledSysPackageLPr(serializer, pkg);
}
- writePreferredActivitiesLPr(serializer);
-
for (final SharedUserSetting usr : mSharedUsers.values()) {
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
@@ -1366,17 +1409,6 @@ final class Settings {
//Debug.stopMethodTracing();
}
- void writePreferredActivitiesLPr(XmlSerializer serializer)
- throws IllegalArgumentException, IllegalStateException, IOException {
- serializer.startTag(null, "preferred-activities");
- for (final PreferredActivity pa : mPreferredActivities.filterSet()) {
- serializer.startTag(null, TAG_ITEM);
- pa.writeToXml(serializer);
- serializer.endTag(null, TAG_ITEM);
- }
- serializer.endTag(null, "preferred-activities");
- }
-
void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "updated-package");
@@ -1554,7 +1586,7 @@ final class Settings {
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
- readDefaultPreferredAppsLPw();
+ readDefaultPreferredAppsLPw(0);
return false;
}
str = new FileInputStream(mSettingsFilename);
@@ -1596,7 +1628,9 @@ final class Settings {
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
- readPreferredActivitiesLPw(parser);
+ // Upgrading from old single-user implementation;
+ // these are the preferred activities for user 0.
+ readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
@@ -1733,7 +1767,7 @@ final class Settings {
return true;
}
- private void readDefaultPreferredAppsLPw() {
+ private void readDefaultPreferredAppsLPw(int userId) {
// Read preferred apps from .../etc/preferred-apps directory.
File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@@ -1776,7 +1810,7 @@ final class Settings {
+ " does not start with 'preferred-activities'");
continue;
}
- readPreferredActivitiesLPw(parser);
+ readPreferredActivitiesLPw(parser, userId);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Error reading apps file " + f, e);
} catch (IOException e) {
@@ -2291,36 +2325,27 @@ final class Settings {
}
}
- private void readPreferredActivitiesLPw(XmlPullParser parser) throws XmlPullParserException,
- IOException {
- int outerDepth = parser.getDepth();
- int type;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
- continue;
- }
-
- String tagName = parser.getName();
- if (tagName.equals(TAG_ITEM)) {
- PreferredActivity pa = new PreferredActivity(parser);
- if (pa.mPref.getParseError() == null) {
- mPreferredActivities.addFilter(pa);
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Error in package manager settings: <preferred-activity> "
- + pa.mPref.getParseError() + " at "
- + parser.getPositionDescription());
- }
- } else {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Unknown element under <preferred-activities>: " + parser.getName());
- XmlUtils.skipCurrentTag(parser);
- }
+ void createNewUserLILPw(Installer installer, int userHandle, File path) {
+ path.mkdir();
+ FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+ | FileUtils.S_IXOTH, -1, -1);
+ for (PackageSetting ps : mPackages.values()) {
+ // Only system apps are initially installed.
+ ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
+ // Need to create a data directory for all apps under this user.
+ installer.createUserData(ps.name,
+ UserHandle.getUid(userHandle, ps.appId), userHandle);
}
+ readDefaultPreferredAppsLPw(userHandle);
+ writePackageRestrictionsLPr(userHandle);
}
void removeUserLPr(int userId) {
+ Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();
+ for (Entry<String, PackageSetting> entry : entries) {
+ entry.getValue().removeUser(userId);
+ }
+ mPreferredActivities.remove(userId);
File file = getUserPackagesStateFile(userId);
file.delete();
file = getUserPackagesStateBackupFile(userId);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index a0326c5..4f9375a 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -78,6 +78,8 @@ public class UserManagerService extends IUserManager.Stub {
private static final String USER_LIST_FILENAME = "userlist.xml";
private static final String USER_PHOTO_FILENAME = "photo.png";
+ private static final int MIN_USER_ID = 10;
+
private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
private final Context mContext;
@@ -459,6 +461,7 @@ public class UserManagerService extends IUserManager.Stub {
UserInfo primary = new UserInfo(0, "Primary", null,
UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
mUsers.put(0, primary);
+ mNextSerialNumber = MIN_USER_ID;
updateUserIdsLocked();
writeUserListLocked();
@@ -832,7 +835,7 @@ public class UserManagerService extends IUserManager.Stub {
*/
private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
- int i = 10;
+ int i = MIN_USER_ID;
while (i < Integer.MAX_VALUE) {
if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
break;
@@ -862,7 +865,7 @@ public class UserManagerService extends IUserManager.Stub {
for (int i = 0; i < mUsers.size(); i++) {
UserInfo user = mUsers.valueAt(i);
if (user == null) continue;
- pw.print(" "); pw.print(user);
+ pw.print(" "); pw.print(user); pw.print(" serialNo="); pw.print(user.serialNumber);
if (mRemovingUserIds.contains(mUsers.keyAt(i))) pw.print(" <removing> ");
if (user.partial) pw.print(" <partial>");
pw.println();
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/java/com/android/server/power/DisplayBlanker.java
new file mode 100644
index 0000000..6072053
--- /dev/null
+++ b/services/java/com/android/server/power/DisplayBlanker.java
@@ -0,0 +1,25 @@
+/*
+ * 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.power;
+
+/**
+ * Blanks or unblanks all displays.
+ */
+interface DisplayBlanker {
+ public void blankAllDisplays();
+ public void unblankAllDisplays();
+}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 4f8cdde..6a57372 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -89,6 +89,9 @@ final class DisplayPowerController {
// auto-brightness adjustment setting.
private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+ // The minimum reduction in brightness when dimmed.
+ private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
+
// If true, enables the use of the current time as an auto-brightness adjustment.
// The basic idea here is to expand the dynamic range of auto-brightness
// when it is especially dark outside. The light sensor tends to perform
@@ -117,8 +120,9 @@ final class DisplayPowerController {
private static final int PROXIMITY_NEGATIVE = 0;
private static final int PROXIMITY_POSITIVE = 1;
- // Proximity sensor debounce delay in milliseconds.
- private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250;
+ // Proximity sensor debounce delay in milliseconds for positive or negative transitions.
+ private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0;
+ private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 500;
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
@@ -155,6 +159,9 @@ final class DisplayPowerController {
// A suspend blocker.
private final SuspendBlocker mSuspendBlocker;
+ // The display blanker.
+ private final DisplayBlanker mDisplayBlanker;
+
// Our handler.
private final DisplayControllerHandler mHandler;
@@ -184,6 +191,12 @@ final class DisplayPowerController {
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
+ // The minimum allowed brightness.
+ private final int mScreenBrightnessRangeMinimum;
+
+ // The maximum allowed brightness.
+ private final int mScreenBrightnessRangeMaximum;
+
// True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
@@ -196,6 +209,10 @@ final class DisplayPowerController {
// May be 0 if no warm-up is required.
private int mLightSensorWarmUpTimeConfig;
+ // True if we should fade the screen while turning it off, false if we should play
+ // a stylish electron beam animation instead.
+ private boolean mElectronBeamFadesConfig;
+
// The pending power request.
// Initially null until the first call to requestPowerState.
// Guarded by mLock.
@@ -255,6 +272,12 @@ final class DisplayPowerController {
// When the screen turns on again, we report user activity to the power manager.
private boolean mScreenOffBecauseOfProximity;
+ // True if the screen on is being blocked.
+ private boolean mScreenOnWasBlocked;
+
+ // The elapsed real time when the screen on was blocked.
+ private long mScreenOnBlockStartRealTime;
+
// Set to true if the light sensor is enabled.
private boolean mLightSensorEnabled;
@@ -323,10 +346,12 @@ final class DisplayPowerController {
*/
public DisplayPowerController(Looper looper, Context context, Notifier notifier,
LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
+ DisplayBlanker displayBlanker,
Callbacks callbacks, Handler callbackHandler) {
mHandler = new DisplayControllerHandler(looper);
mNotifier = notifier;
mSuspendBlocker = suspendBlocker;
+ mDisplayBlanker = displayBlanker;
mCallbacks = callbacks;
mCallbackHandler = callbackHandler;
@@ -336,8 +361,14 @@ final class DisplayPowerController {
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
final Resources resources = context.getResources();
- mScreenBrightnessDimConfig = resources.getInteger(
- com.android.internal.R.integer.config_screenBrightnessDim);
+
+ mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDim));
+
+ int screenBrightnessMinimum = Math.min(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
+ mScreenBrightnessDimConfig);
+
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
if (mUseSoftwareAutoBrightnessConfig) {
@@ -355,12 +386,22 @@ final class DisplayPowerController {
+ "which must be strictly increasing. "
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
+ } else {
+ if (screenBrightness[0] < screenBrightnessMinimum) {
+ screenBrightnessMinimum = screenBrightness[0];
+ }
}
mLightSensorWarmUpTimeConfig = resources.getInteger(
com.android.internal.R.integer.config_lightSensorWarmupTime);
}
+ mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
+ mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+
+ mElectronBeamFadesConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_animateScreenLights);
+
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
if (mProximitySensor != null) {
@@ -384,14 +425,14 @@ final class DisplayPowerController {
final int n = brightness.length;
float[] x = new float[n];
float[] y = new float[n];
- y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
+ y[0] = normalizeAbsoluteBrightness(brightness[0]);
for (int i = 1; i < n; i++) {
x[i] = lux[i - 1];
- y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
+ y[i] = normalizeAbsoluteBrightness(brightness[i]);
}
Spline spline = Spline.createMonotoneCubicSpline(x, y);
- if (false) {
+ if (DEBUG) {
Slog.d(TAG, "Auto-brightness spline: " + spline);
for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
@@ -480,10 +521,12 @@ final class DisplayPowerController {
private void initialize() {
final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
Display display = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
- mPowerState = new DisplayPowerState(new ElectronBeam(display),
+ mPowerState = new DisplayPowerState(
+ new ElectronBeam(display),
new PhotonicModulator(executor,
mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
- mSuspendBlocker));
+ mSuspendBlocker),
+ mDisplayBlanker);
mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -562,6 +605,7 @@ final class DisplayPowerController {
if (!mScreenOffBecauseOfProximity
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
+ sendOnProximityPositive();
setScreenOn(false);
}
} else if (mWaitingForNegativeProximity
@@ -576,7 +620,6 @@ final class DisplayPowerController {
if (mScreenOffBecauseOfProximity
&& mProximity != PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = false;
- setScreenOn(true);
sendOnProximityNegative();
}
} else {
@@ -590,30 +633,31 @@ final class DisplayPowerController {
}
// Set the screen brightness.
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
- // Screen is dimmed. Overrides everything else.
- animateScreenBrightness(
- clampScreenBrightness(mScreenBrightnessDimConfig),
- BRIGHTNESS_RAMP_RATE_FAST);
- mUsingScreenAutoBrightness = false;
- } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
+ if (wantScreenOn(mPowerRequest.screenState)) {
+ int target;
+ boolean slow;
if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
// Use current auto-brightness value.
- animateScreenBrightness(
- clampScreenBrightness(mScreenAutoBrightness),
- mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mScreenAutoBrightness;
+ slow = mUsingScreenAutoBrightness;
mUsingScreenAutoBrightness = true;
} else {
// Light sensor is disabled or not ready yet.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
- animateScreenBrightness(
- clampScreenBrightness(mPowerRequest.screenBrightness),
- BRIGHTNESS_RAMP_RATE_FAST);
+ target = mPowerRequest.screenBrightness;
+ slow = false;
mUsingScreenAutoBrightness = false;
}
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ // Screen is dimmed. Sets an upper bound on everything else.
+ target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
+ mScreenBrightnessDimConfig);
+ slow = false;
+ }
+ animateScreenBrightness(clampScreenBrightness(target),
+ slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
} else {
// Screen is off. Don't bother changing the brightness.
mUsingScreenAutoBrightness = false;
@@ -627,20 +671,33 @@ final class DisplayPowerController {
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
if (!mElectronBeamOffAnimator.isStarted()) {
+ // Turn the screen on. The contents of the screen may not yet
+ // be visible if the electron beam has not been dismissed because
+ // its last frame of animation is solid black.
setScreenOn(true);
- if (USE_ELECTRON_BEAM_ON_ANIMATION) {
- if (!mElectronBeamOnAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 1.0f) {
- mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(true)) {
- mElectronBeamOnAnimator.start();
- } else {
- mElectronBeamOnAnimator.end();
+
+ if (mPowerRequest.blockScreenOn
+ && mPowerState.getElectronBeamLevel() == 0.0f) {
+ blockScreenOn();
+ } else {
+ unblockScreenOn();
+ if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+ if (!mElectronBeamOnAnimator.isStarted()) {
+ if (mPowerState.getElectronBeamLevel() == 1.0f) {
+ mPowerState.dismissElectronBeam();
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_WARM_UP)) {
+ mElectronBeamOnAnimator.start();
+ } else {
+ mElectronBeamOnAnimator.end();
+ }
}
+ } else {
+ mPowerState.setElectronBeamLevel(1.0f);
+ mPowerState.dismissElectronBeam();
}
- } else {
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
}
}
} else {
@@ -650,7 +707,10 @@ final class DisplayPowerController {
if (!mElectronBeamOffAnimator.isStarted()) {
if (mPowerState.getElectronBeamLevel() == 0.0f) {
setScreenOn(false);
- } else if (mPowerState.prepareElectronBeam(false)
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_COOL_DOWN)
&& mPowerState.isScreenOn()) {
mElectronBeamOffAnimator.start();
} else {
@@ -665,18 +725,43 @@ final class DisplayPowerController {
// We mostly care about the screen state here, ignoring brightness changes
// which will be handled asynchronously.
if (mustNotify
+ && !mScreenOnWasBlocked
&& !mElectronBeamOnAnimator.isStarted()
&& !mElectronBeamOffAnimator.isStarted()
&& mPowerState.waitUntilClean(mCleanListener)) {
synchronized (mLock) {
if (!mPendingRequestChangedLocked) {
mDisplayReadyLocked = true;
+
+ if (DEBUG) {
+ Slog.d(TAG, "Display ready!");
+ }
}
}
sendOnStateChanged();
}
}
+ private void blockScreenOn() {
+ if (!mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = true;
+ if (DEBUG) {
+ Slog.d(TAG, "Blocked screen on.");
+ mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
+ }
+ }
+ }
+
+ private void unblockScreenOn() {
+ if (mScreenOnWasBlocked) {
+ mScreenOnWasBlocked = false;
+ if (DEBUG) {
+ Slog.d(TAG, "Unblocked screen on after " +
+ (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
+ }
+ }
+ }
+
private void setScreenOn(boolean on) {
if (!mPowerState.isScreenOn() == on) {
mPowerState.setScreenOn(on);
@@ -689,7 +774,25 @@ final class DisplayPowerController {
}
private int clampScreenBrightness(int value) {
- return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+ return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+ }
+
+ private static int clampAbsoluteBrightness(int value) {
+ return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
+ }
+
+ private static int clamp(int value, int min, int max) {
+ if (value <= min) {
+ return min;
+ }
+ if (value >= max) {
+ return max;
+ }
+ return value;
+ }
+
+ private static float normalizeAbsoluteBrightness(int value) {
+ return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
}
private void animateScreenBrightness(int target, int rate) {
@@ -734,8 +837,13 @@ final class DisplayPowerController {
// Only accept a proximity sensor reading if it remains
// stable for the entire debounce delay.
mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
- mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE;
- mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY;
+ if (positive) {
+ mPendingProximity = PROXIMITY_POSITIVE;
+ mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY;
+ } else {
+ mPendingProximity = PROXIMITY_NEGATIVE;
+ mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY;
+ }
debounceProximitySensor();
}
@@ -973,6 +1081,17 @@ final class DisplayPowerController {
}
};
+ private void sendOnProximityPositive() {
+ mCallbackHandler.post(mOnProximityPositiveRunnable);
+ }
+
+ private final Runnable mOnProximityPositiveRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mCallbacks.onProximityPositive();
+ }
+ };
+
private void sendOnProximityNegative() {
mCallbackHandler.post(mOnProximityNegativeRunnable);
}
@@ -999,6 +1118,8 @@ final class DisplayPowerController {
pw.println();
pw.println("Display Controller Configuration:");
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+ pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
+ pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig="
+ mUseSoftwareAutoBrightnessConfig);
pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
@@ -1090,6 +1211,7 @@ final class DisplayPowerController {
*/
public interface Callbacks {
void onStateChanged();
+ void onProximityPositive();
void onProximityNegative();
}
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
index 2d74292..22f17d7 100644
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -52,12 +52,23 @@ final class DisplayPowerRequest {
// If true, enables automatic brightness control.
public boolean useAutoBrightness;
+ // If true, prevents the screen from completely turning on if it is currently off.
+ // The display does not enter a "ready" state if this flag is true and screen on is
+ // blocked. The window manager policy blocks screen on while it prepares the keyguard to
+ // prevent the user from seeing intermediate updates.
+ //
+ // Technically, we may not block the screen itself from turning on (because that introduces
+ // extra unnecessary latency) but we do prevent content on screen from becoming
+ // visible to the user.
+ public boolean blockScreenOn;
+
public DisplayPowerRequest() {
screenState = SCREEN_STATE_BRIGHT;
useProximitySensor = false;
screenBrightness = PowerManager.BRIGHTNESS_ON;
screenAutoBrightnessAdjustment = 0.0f;
useAutoBrightness = false;
+ blockScreenOn = false;
}
public DisplayPowerRequest(DisplayPowerRequest other) {
@@ -70,6 +81,7 @@ final class DisplayPowerRequest {
screenBrightness = other.screenBrightness;
screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
useAutoBrightness = other.useAutoBrightness;
+ blockScreenOn = other.blockScreenOn;
}
@Override
@@ -84,7 +96,8 @@ final class DisplayPowerRequest {
&& useProximitySensor == other.useProximitySensor
&& screenBrightness == other.screenBrightness
&& screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
- && useAutoBrightness == other.useAutoBrightness;
+ && useAutoBrightness == other.useAutoBrightness
+ && blockScreenOn == other.blockScreenOn;
}
@Override
@@ -98,6 +111,7 @@ final class DisplayPowerRequest {
+ ", useProximitySensor=" + useProximitySensor
+ ", screenBrightness=" + screenBrightness
+ ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
- + ", useAutoBrightness=" + useAutoBrightness;
+ + ", useAutoBrightness=" + useAutoBrightness
+ + ", blockScreenOn=" + blockScreenOn;
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index 1bd7811..fdfcacc 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -51,7 +51,8 @@ final class DisplayPowerState {
private final Choreographer mChoreographer;
private final ElectronBeam mElectronBeam;
- private final PhotonicModulator mScreenBrightnessModulator;
+ private final PhotonicModulator mPhotonicModulator;
+ private final DisplayBlanker mDisplayBlanker;
private int mDirty;
private boolean mScreenOn;
@@ -61,10 +62,11 @@ final class DisplayPowerState {
private Runnable mCleanListener;
public DisplayPowerState(ElectronBeam electronBean,
- PhotonicModulator screenBrightnessModulator) {
+ PhotonicModulator photonicModulator, DisplayBlanker displayBlanker) {
mChoreographer = Choreographer.getInstance();
mElectronBeam = electronBean;
- mScreenBrightnessModulator = screenBrightnessModulator;
+ mPhotonicModulator = photonicModulator;
+ mDisplayBlanker = displayBlanker;
// At boot time, we know that the screen is on and the electron beam
// animation is not playing. We don't know the screen's brightness though,
@@ -130,13 +132,12 @@ final class DisplayPowerState {
* This method should be called before starting an animation because it
* can take a fair amount of time to prepare the electron beam surface.
*
- * @param warmUp True if the electron beam should start warming up.
+ * @param mode The electron beam animation mode to prepare.
* @return True if the electron beam was prepared.
*/
- public boolean prepareElectronBeam(boolean warmUp) {
- boolean success = mElectronBeam.prepare(warmUp);
+ public boolean prepareElectronBeam(int mode) {
invalidate(DIRTY_ELECTRON_BEAM);
- return success;
+ return mElectronBeam.prepare(mode);
}
/**
@@ -239,8 +240,8 @@ final class DisplayPowerState {
private void apply() {
if (mDirty != 0) {
if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
- mScreenBrightnessModulator.setBrightness(0, true /*sync*/);
- PowerManagerService.nativeSetScreenState(false);
+ mPhotonicModulator.setBrightness(0, true /*sync*/);
+ mDisplayBlanker.blankAllDisplays();
}
if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
@@ -248,12 +249,12 @@ final class DisplayPowerState {
}
if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
- PowerManagerService.nativeSetScreenState(true);
+ mDisplayBlanker.unblankAllDisplays();
}
if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0
&& mScreenOn) {
- mScreenBrightnessModulator.setBrightness(
+ mPhotonicModulator.setBrightness(
(int)(mScreenBrightness * mElectronBeamLevel), false /*sync*/);
}
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
index 0c68997..6a567ba 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -26,7 +26,6 @@ import android.opengl.EGLSurface;
import android.opengl.GLES10;
import android.opengl.GLUtils;
import android.os.Looper;
-import android.os.Process;
import android.util.FloatMath;
import android.util.Slog;
import android.view.Display;
@@ -41,12 +40,13 @@ import java.nio.FloatBuffer;
/**
* Bzzzoooop! *crackle*
- *
+ * <p>
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
- *
+ * </p><p>
* This component must only be created or accessed by the {@link Looper} thread
* that belongs to the {@link DisplayPowerController}.
+ * </p>
*/
final class ElectronBeam {
private static final String TAG = "ElectronBeam";
@@ -65,7 +65,7 @@ final class ElectronBeam {
// Set to true when the animation context has been fully prepared.
private boolean mPrepared;
- private boolean mWarmUp;
+ private int mMode;
private final Display mDisplay;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -80,6 +80,7 @@ final class ElectronBeam {
private EGLContext mEglContext;
private EGLSurface mEglSurface;
private boolean mSurfaceVisible;
+ private float mSurfaceAlpha;
// Texture names. We only use one texture, which contains the screenshot.
private final int[] mTexNames = new int[1];
@@ -90,6 +91,21 @@ final class ElectronBeam {
private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+ /**
+ * Animates an electron beam warming up.
+ */
+ public static final int MODE_WARM_UP = 0;
+
+ /**
+ * Animates an electron beam shutting off.
+ */
+ public static final int MODE_COOL_DOWN = 1;
+
+ /**
+ * Animates a simple dim layer to fade the contents of the screen in or out progressively.
+ */
+ public static final int MODE_FADE = 2;
+
public ElectronBeam(Display display) {
mDisplay = display;
}
@@ -98,16 +114,15 @@ final class ElectronBeam {
* Warms up the electron beam in preparation for turning on or off.
* This method prepares a GL context, and captures a screen shot.
*
- * @param warmUp True if the electron beam is about to be turned on, false if
- * it is about to be turned off.
+ * @param mode The desired mode for the upcoming animation.
* @return True if the electron beam is ready, false if it is uncontrollable.
*/
- public boolean prepare(boolean warmUp) {
+ public boolean prepare(int mode) {
if (DEBUG) {
- Slog.d(TAG, "prepare: warmUp=" + warmUp);
+ Slog.d(TAG, "prepare: mode=" + mode);
}
- mWarmUp = warmUp;
+ mMode = mode;
// Get the display size and adjust it for rotation.
mDisplay.getDisplayInfo(mDisplayInfo);
@@ -123,17 +138,28 @@ final class ElectronBeam {
}
// Prepare the surface for drawing.
- if (!createEglContext()
- || !createEglSurface()
- || !captureScreenshotTextureAndSetViewport()) {
+ if (!tryPrepare()) {
dismiss();
return false;
}
+ // Done.
mPrepared = true;
return true;
}
+ private boolean tryPrepare() {
+ if (createSurface()) {
+ if (mMode == MODE_FADE) {
+ return true;
+ }
+ return createEglContext()
+ && createEglSurface()
+ && captureScreenshotTextureAndSetViewport();
+ }
+ return false;
+ }
+
/**
* Dismisses the electron beam animation surface and cleans up.
*
@@ -148,6 +174,7 @@ final class ElectronBeam {
destroyScreenshotTexture();
destroyEglSurface();
+ destroySurface();
mPrepared = false;
}
@@ -163,6 +190,14 @@ final class ElectronBeam {
Slog.d(TAG, "drawFrame: level=" + level);
}
+ if (!mPrepared) {
+ return false;
+ }
+
+ if (mMode == MODE_FADE) {
+ return showSurface(1.0f - level);
+ }
+
if (!attachEglContext()) {
return false;
}
@@ -185,8 +220,7 @@ final class ElectronBeam {
} finally {
detachEglContext();
}
-
- return showEglSurface();
+ return showSurface(1.0f);
}
/**
@@ -217,7 +251,7 @@ final class ElectronBeam {
// bind texture and set blending for drawing planes
GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
- mWarmUp ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
+ mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
@@ -251,7 +285,7 @@ final class ElectronBeam {
GLES10.glColorMask(true, true, true, true);
// draw the white highlight (we use the last vertices)
- if (!mWarmUp) {
+ if (mMode == MODE_COOL_DOWN) {
GLES10.glColor4f(ag, ag, ag, 1.0f);
GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
}
@@ -472,7 +506,7 @@ final class ElectronBeam {
}
}*/
- private boolean createEglSurface() {
+ private boolean createSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
}
@@ -481,9 +515,15 @@ final class ElectronBeam {
try {
if (mSurface == null) {
try {
+ int flags;
+ if (mMode == MODE_FADE) {
+ flags = Surface.FX_SURFACE_DIM | Surface.HIDDEN;
+ } else {
+ flags = Surface.OPAQUE | Surface.HIDDEN;
+ }
mSurface = new Surface(mSurfaceSession,
"ElectronBeam", mDisplayWidth, mDisplayHeight,
- PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
+ PixelFormat.OPAQUE, flags);
} catch (Surface.OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
return false;
@@ -514,7 +554,10 @@ final class ElectronBeam {
} finally {
Surface.closeTransaction();
}
+ return true;
+ }
+ private boolean createEglSurface() {
if (mEglSurface == null) {
int[] eglSurfaceAttribList = new int[] {
EGL14.EGL_NONE
@@ -536,7 +579,9 @@ final class ElectronBeam {
}
mEglSurface = null;
}
+ }
+ private void destroySurface() {
if (mSurface != null) {
Surface.openTransaction();
try {
@@ -546,19 +591,22 @@ final class ElectronBeam {
}
mSurface = null;
mSurfaceVisible = false;
+ mSurfaceAlpha = 0f;
}
}
- private boolean showEglSurface() {
- if (!mSurfaceVisible) {
+ private boolean showSurface(float alpha) {
+ if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
Surface.openTransaction();
try {
mSurface.setLayer(ELECTRON_BEAM_LAYER);
+ mSurface.setAlpha(alpha);
mSurface.show();
} finally {
Surface.closeTransaction();
}
mSurfaceVisible = true;
+ mSurfaceAlpha = alpha;
}
return true;
}
@@ -643,11 +691,12 @@ final class ElectronBeam {
pw.println();
pw.println("Electron Beam State:");
pw.println(" mPrepared=" + mPrepared);
- pw.println(" mWarmUp=" + mWarmUp);
+ pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
pw.println(" mDisplayRotation=" + mDisplayRotation);
pw.println(" mDisplayWidth=" + mDisplayWidth);
pw.println(" mDisplayHeight=" + mDisplayHeight);
pw.println(" mSurfaceVisible=" + mSurfaceVisible);
+ pw.println(" mSurfaceAlpha=" + mSurfaceAlpha);
}
}
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index ce1e147..5e05693 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -35,21 +35,23 @@ import android.os.WorkSource;
import android.util.EventLog;
import android.util.Slog;
import android.view.WindowManagerPolicy;
-import android.view.WindowManagerPolicy.ScreenOnListener;
/**
* Sends broadcasts about important power state changes.
- *
+ * <p>
* This methods of this class may be called by the power manager service while
* its lock is being held. Internally it takes care of sending broadcasts to
* notify other components of the system or applications asynchronously.
- *
+ * </p><p>
* The notifier is designed to collapse unnecessary broadcasts when it is not
* possible for the system to have observed an intermediate state.
- *
- * For example, if the device wakes up, goes to sleep and wakes up again immediately
- * before the go to sleep broadcast has been sent, then no broadcast will be
- * sent about the system going to sleep and waking up.
+ * </p><p>
+ * For example, if the device wakes up, goes to sleep, wakes up again and goes to
+ * sleep again before the wake up notification is sent, then the system will
+ * be told about only one wake up and sleep. However, we always notify the
+ * fact that at least one transition occurred. It is especially important to
+ * tell the system when we go to sleep so that it can lock the keyguard if needed.
+ * </p>
*/
final class Notifier {
private static final String TAG = "PowerManagerNotifier";
@@ -68,8 +70,8 @@ final class Notifier {
private final Context mContext;
private final IBatteryStats mBatteryStats;
private final SuspendBlocker mSuspendBlocker;
+ private final ScreenOnBlocker mScreenOnBlocker;
private final WindowManagerPolicy mPolicy;
- private final ScreenOnListener mScreenOnListener;
private final NotifierHandler mHandler;
private final Intent mScreenOnIntent;
@@ -79,6 +81,10 @@ final class Notifier {
private int mActualPowerState;
private int mLastGoToSleepReason;
+ // True if there is a pending transition that needs to be reported.
+ private boolean mPendingWakeUpBroadcast;
+ private boolean mPendingGoToSleepBroadcast;
+
// The currently broadcasted power state. This reflects what other parts of the
// system have observed.
private int mBroadcastedPowerState;
@@ -88,14 +94,17 @@ final class Notifier {
// True if a user activity message should be sent.
private boolean mUserActivityPending;
+ // True if the screen on blocker has been acquired.
+ private boolean mScreenOnBlockerAcquired;
+
public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
- SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
- ScreenOnListener screenOnListener) {
+ SuspendBlocker suspendBlocker, ScreenOnBlocker screenOnBlocker,
+ WindowManagerPolicy policy) {
mContext = context;
mBatteryStats = batteryStats;
mSuspendBlocker = suspendBlocker;
+ mScreenOnBlocker = screenOnBlocker;
mPolicy = policy;
- mScreenOnListener = screenOnListener;
mHandler = new NotifierHandler(looper);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -219,6 +228,11 @@ final class Notifier {
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_AWAKE) {
mActualPowerState = POWER_STATE_AWAKE;
+ mPendingWakeUpBroadcast = true;
+ if (!mScreenOnBlockerAcquired) {
+ mScreenOnBlockerAcquired = true;
+ mScreenOnBlocker.acquire();
+ }
updatePendingBroadcastLocked();
}
}
@@ -264,6 +278,7 @@ final class Notifier {
synchronized (mLock) {
if (mActualPowerState != POWER_STATE_ASLEEP) {
mActualPowerState = POWER_STATE_ASLEEP;
+ mPendingGoToSleepBroadcast = true;
if (mUserActivityPending) {
mUserActivityPending = false;
mHandler.removeMessages(MSG_USER_ACTIVITY);
@@ -300,7 +315,8 @@ final class Notifier {
private void updatePendingBroadcastLocked() {
if (!mBroadcastInProgress
&& mActualPowerState != POWER_STATE_UNKNOWN
- && mActualPowerState != mBroadcastedPowerState) {
+ && (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState != mBroadcastedPowerState)) {
mBroadcastInProgress = true;
mSuspendBlocker.acquire();
Message msg = mHandler.obtainMessage(MSG_BROADCAST);
@@ -309,6 +325,11 @@ final class Notifier {
}
}
+ private void finishPendingBroadcastLocked() {
+ mBroadcastInProgress = false;
+ mSuspendBlocker.release();
+ }
+
private void sendUserActivity() {
synchronized (mLock) {
if (!mUserActivityPending) {
@@ -324,18 +345,35 @@ final class Notifier {
final int powerState;
final int goToSleepReason;
synchronized (mLock) {
- if (mActualPowerState == POWER_STATE_UNKNOWN
- || mActualPowerState == mBroadcastedPowerState) {
- mBroadcastInProgress = false;
- mSuspendBlocker.release();
- return;
+ if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
+ // Broadcasted power state is unknown. Send wake up.
+ mPendingWakeUpBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_AWAKE;
+ } else if (mBroadcastedPowerState == POWER_STATE_AWAKE) {
+ // Broadcasted power state is awake. Send asleep if needed.
+ if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState == POWER_STATE_ASLEEP) {
+ mPendingGoToSleepBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_ASLEEP;
+ } else {
+ finishPendingBroadcastLocked();
+ return;
+ }
+ } else {
+ // Broadcasted power state is asleep. Send awake if needed.
+ if (mPendingWakeUpBroadcast || mPendingGoToSleepBroadcast
+ || mActualPowerState == POWER_STATE_AWAKE) {
+ mPendingWakeUpBroadcast = false;
+ mBroadcastedPowerState = POWER_STATE_AWAKE;
+ } else {
+ finishPendingBroadcastLocked();
+ return;
+ }
}
- powerState = mActualPowerState;
- goToSleepReason = mLastGoToSleepReason;
-
- mBroadcastedPowerState = powerState;
mBroadcastStartTime = SystemClock.uptimeMillis();
+ powerState = mBroadcastedPowerState;
+ goToSleepReason = mLastGoToSleepReason;
}
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
@@ -355,6 +393,7 @@ final class Notifier {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
mPolicy.screenTurningOn(mScreenOnListener);
+
try {
ActivityManagerNative.getDefault().wakingUp();
} catch (RemoteException e) {
@@ -370,6 +409,19 @@ final class Notifier {
}
}
+ private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
+ new WindowManagerPolicy.ScreenOnListener() {
+ @Override
+ public void onScreenOn() {
+ synchronized (mLock) {
+ if (mScreenOnBlockerAcquired && !mPendingWakeUpBroadcast) {
+ mScreenOnBlockerAcquired = false;
+ mScreenOnBlocker.release();
+ }
+ }
+ }
+ };
+
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 9a01022..b9085a4 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -79,6 +79,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
// Message: Sent when the device enters or exits a napping or dreaming state.
private static final int MSG_SANDMAN = 2;
+ // Message: Sent when the screen on blocker is released.
+ private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -98,6 +100,10 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int DIRTY_STAY_ON = 1 << 7;
// Dirty bit: battery state changed
private static final int DIRTY_BATTERY_STATE = 1 << 8;
+ // Dirty bit: proximity state changed
+ private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
+ // Dirty bit: screen on blocker state became held or unheld
+ private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
@@ -121,6 +127,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private static final int WAKE_LOCK_SCREEN_DIM = 1 << 2;
private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
+ private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -149,6 +156,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private Context mContext;
private LightsService mLightsService;
private BatteryService mBatteryService;
+ private DisplayManagerService mDisplayManagerService;
private IBatteryStats mBatteryStats;
private HandlerThread mHandlerThread;
private PowerManagerHandler mHandler;
@@ -220,6 +228,13 @@ public final class PowerManagerService extends IPowerManager.Stub
// The suspend blocker used to keep the CPU alive when wake locks have been acquired.
private final SuspendBlocker mWakeLockSuspendBlocker;
+ // The screen on blocker used to keep the screen from turning on while the lock
+ // screen is coming up.
+ private final ScreenOnBlockerImpl mScreenOnBlocker;
+
+ // The display blanker used to turn the screen on or off.
+ private final DisplayBlankerImpl mDisplayBlanker;
+
// True if systemReady() has been called.
private boolean mSystemReady;
@@ -258,6 +273,9 @@ public final class PowerManagerService extends IPowerManager.Stub
// True if the device should stay on.
private boolean mStayOn;
+ // True if the proximity sensor reads a positive result.
+ private boolean mProximityPositive;
+
// Screen brightness setting limits.
private int mScreenBrightnessSettingMinimum;
private int mScreenBrightnessSettingMaximum;
@@ -306,13 +324,15 @@ public final class PowerManagerService extends IPowerManager.Stub
private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
private static native void nativeAcquireSuspendBlocker(String name);
private static native void nativeReleaseSuspendBlocker(String name);
-
- static native void nativeSetScreenState(boolean on);
+ private static native void nativeSetInteractive(boolean enable);
+ private static native void nativeSetAutoSuspend(boolean enable);
public PowerManagerService() {
synchronized (mLock) {
mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
mWakeLockSuspendBlocker.acquire();
+ mScreenOnBlocker = new ScreenOnBlockerImpl();
+ mDisplayBlanker = new DisplayBlankerImpl();
mHoldingWakeLockSuspendBlocker = true;
mWakefulness = WAKEFULNESS_AWAKE;
}
@@ -328,23 +348,24 @@ public final class PowerManagerService extends IPowerManager.Stub
public void init(Context context, LightsService ls,
ActivityManagerService am, BatteryService bs, IBatteryStats bss,
DisplayManagerService dm) {
- // Forcibly turn the screen on at boot so that it is in a known power state.
- // We do this in init() rather than in the constructor because setting the
- // screen state requires a call into surface flinger which then needs to call back
- // into the activity manager to check permissions. Unfortunately the
- // activity manager is not running when the constructor is called, so we
- // have to defer setting the screen state until this point.
- nativeSetScreenState(true);
-
mContext = context;
mLightsService = ls;
mBatteryService = bs;
mBatteryStats = bss;
+ mDisplayManagerService = dm;
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addMonitor(this);
+
+ // Forcibly turn the screen on at boot so that it is in a known power state.
+ // We do this in init() rather than in the constructor because setting the
+ // screen state requires a call into surface flinger which then needs to call back
+ // into the activity manager to check permissions. Unfortunately the
+ // activity manager is not running when the constructor is called, so we
+ // have to defer setting the screen state until this point.
+ mDisplayBlanker.unblankAllDisplays();
}
public void setPolicy(WindowManagerPolicy policy) {
@@ -363,13 +384,18 @@ public final class PowerManagerService extends IPowerManager.Stub
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
- mNotifier = new Notifier(mHandler.getLooper(), mContext, mBatteryStats,
+ // The notifier runs on the system server's main looper so as not to interfere
+ // with the animations and other critical functions of the power manager.
+ mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
- mPolicy, mScreenOnListener);
+ mScreenOnBlocker, mPolicy);
+
+ // The display power controller runs on the power manager service's
+ // own handler thread.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
mContext, mNotifier, mLightsService, twilight,
createSuspendBlockerLocked("PowerManagerService.Display"),
- mDisplayPowerControllerCallbacks, mHandler);
+ mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
@@ -823,9 +849,9 @@ public final class PowerManagerService extends IPowerManager.Stub
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep...");
+ sendPendingNotificationsLocked();
mNotifier.onWakeUpStarted();
mSendWakeUpFinishedNotificationWhenReady = true;
- mSendGoToSleepFinishedNotificationWhenReady = false;
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream...");
@@ -896,12 +922,13 @@ public final class PowerManagerService extends IPowerManager.Stub
break;
}
+ sendPendingNotificationsLocked();
+ mNotifier.onGoToSleepStarted(reason);
+ mSendGoToSleepFinishedNotificationWhenReady = true;
+
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
mWakefulness = WAKEFULNESS_ASLEEP;
- mNotifier.onGoToSleepStarted(reason);
- mSendGoToSleepFinishedNotificationWhenReady = true;
- mSendWakeUpFinishedNotificationWhenReady = false;
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -1000,7 +1027,9 @@ public final class PowerManagerService extends IPowerManager.Stub
updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: Send notifications, if needed.
- sendPendingNotificationsLocked();
+ if (mDisplayReady) {
+ sendPendingNotificationsLocked();
+ }
// Phase 4: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
@@ -1009,15 +1038,13 @@ public final class PowerManagerService extends IPowerManager.Stub
}
private void sendPendingNotificationsLocked() {
- if (mDisplayReady) {
- if (mSendWakeUpFinishedNotificationWhenReady) {
- mSendWakeUpFinishedNotificationWhenReady = false;
- mNotifier.onWakeUpFinished();
- }
- if (mSendGoToSleepFinishedNotificationWhenReady) {
- mSendGoToSleepFinishedNotificationWhenReady = false;
- mNotifier.onGoToSleepFinished();
- }
+ if (mSendWakeUpFinishedNotificationWhenReady) {
+ mSendWakeUpFinishedNotificationWhenReady = false;
+ mNotifier.onWakeUpFinished();
+ }
+ if (mSendGoToSleepFinishedNotificationWhenReady) {
+ mSendGoToSleepFinishedNotificationWhenReady = false;
+ mNotifier.onGoToSleepFinished();
}
}
@@ -1058,41 +1085,51 @@ public final class PowerManagerService extends IPowerManager.Stub
}
private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(boolean wasPowered, int oldPlugType) {
- if (mWakeUpWhenPluggedOrUnpluggedConfig) {
- // FIXME: Need more accurate detection of wireless chargers.
- //
- // We are unable to accurately detect whether the device is resting on the
- // charger unless it is actually receiving power. This causes us some grief
- // because the device might not appear to be plugged into the wireless charger
- // unless it actually charging.
- //
- // To avoid spuriously waking the screen, we apply a special policy to
- // wireless chargers.
- //
- // 1. Don't wake the device when unplugged from wireless charger because
- // it might be that the device is still resting on the wireless charger
- // but is not receiving power anymore because the battery is full.
- //
- // 2. Don't wake the device when plugged into a wireless charger if the
- // battery already appears to be mostly full. This situation may indicate
- // that the device was resting on the charger the whole time and simply
- // wasn't receiving power because the battery was full. We can't tell
- // whether the device was just placed on the charger or whether it has
- // been there for half of the night slowly discharging until it hit
- // the point where it needed to start charging again.
- if (wasPowered && !mIsPowered
- && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
- return false;
- }
- if (!wasPowered && mIsPowered
- && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
- && mBatteryService.getBatteryLevel() >=
- WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
- return false;
- }
- return true;
+ // Don't wake when powered unless configured to do so.
+ if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
+ return false;
}
- return false;
+
+ // FIXME: Need more accurate detection of wireless chargers.
+ //
+ // We are unable to accurately detect whether the device is resting on the
+ // charger unless it is actually receiving power. This causes us some grief
+ // because the device might not appear to be plugged into the wireless charger
+ // unless it actually charging.
+ //
+ // To avoid spuriously waking the screen, we apply a special policy to
+ // wireless chargers.
+ //
+ // 1. Don't wake the device when unplugged from wireless charger because
+ // it might be that the device is still resting on the wireless charger
+ // but is not receiving power anymore because the battery is full.
+ //
+ // 2. Don't wake the device when plugged into a wireless charger if the
+ // battery already appears to be mostly full. This situation may indicate
+ // that the device was resting on the charger the whole time and simply
+ // wasn't receiving power because the battery was full. We can't tell
+ // whether the device was just placed on the charger or whether it has
+ // been there for half of the night slowly discharging until it hit
+ // the point where it needed to start charging again.
+ if (wasPowered && !mIsPowered
+ && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+ return false;
+ }
+ if (!wasPowered && mIsPowered
+ && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
+ && mBatteryService.getBatteryLevel() >=
+ WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+ return false;
+ }
+
+ // If already dreaming and becoming powered, then don't wake.
+ if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
+ || mWakefulness == WAKEFULNESS_DREAMING)) {
+ return false;
+ }
+
+ // Otherwise wake up!
+ return true;
}
/**
@@ -1101,12 +1138,17 @@ public final class PowerManagerService extends IPowerManager.Stub
*/
private void updateStayOnLocked(int dirty) {
if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
+ final boolean wasStayOn = mStayOn;
if (mStayOnWhilePluggedInSetting != 0
&& !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
mStayOn = mBatteryService.isPowered(mStayOnWhilePluggedInSetting);
} else {
mStayOn = false;
}
+
+ if (mStayOn != wasStayOn) {
+ mDirty |= DIRTY_STAY_ON;
+ }
}
}
@@ -1131,16 +1173,25 @@ public final class PowerManagerService extends IPowerManager.Stub
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU
| WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
if (mWakefulness != WAKEFULNESS_ASLEEP) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
+ }
}
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -1265,7 +1316,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private boolean updateWakefulnessLocked(int dirty) {
boolean changed = false;
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
- | DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
+ | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
@@ -1288,17 +1339,17 @@ public final class PowerManagerService extends IPowerManager.Stub
* to being fully awake or else go to sleep for good.
*/
private boolean isItBedTimeYetLocked() {
- return mBootCompleted && !isScreenBeingKeptOnLocked();
+ return mBootCompleted && !isBeingKeptAwakeLocked();
}
/**
- * Returns true if the screen is being kept on by a wake lock, user activity
+ * Returns true if the device is being kept awake by a wake lock, user activity
* or the stay on while powered setting.
*/
- private boolean isScreenBeingKeptOnLocked() {
+ private boolean isBeingKeptAwakeLocked() {
return mStayOn
- || (mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
- | WAKE_LOCK_PROXIMITY_SCREEN_OFF)) != 0
+ || mProximityPositive
+ || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0
|| (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT
| USER_ACTIVITY_SCREEN_DIM)) != 0;
}
@@ -1314,6 +1365,7 @@ public final class PowerManagerService extends IPowerManager.Stub
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
+ | DIRTY_PROXIMITY_POSITIVE
| DIRTY_BATTERY_STATE)) != 0) {
scheduleSandmanLocked();
}
@@ -1401,7 +1453,7 @@ public final class PowerManagerService extends IPowerManager.Stub
&& mDreamsEnabledSetting
&& mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
&& mBootCompleted
- && (mIsPowered || isScreenBeingKeptOnLocked());
+ && (mIsPowered || isBeingKeptAwakeLocked());
}
/**
@@ -1421,6 +1473,13 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
+ private void handleScreenOnBlockerReleased() {
+ synchronized (mLock) {
+ mDirty |= DIRTY_SCREEN_ON_BLOCKER_RELEASED;
+ updatePowerStateLocked();
+ }
+ }
+
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
@@ -1432,8 +1491,8 @@ public final class PowerManagerService extends IPowerManager.Stub
private void updateDisplayPowerStateLocked(int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
- | DIRTY_SETTINGS)) != 0) {
- int newScreenState = getDesiredScreenPowerState();
+ | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
+ int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
&& mDisplayPowerRequest.screenState
@@ -1481,12 +1540,14 @@ public final class PowerManagerService extends IPowerManager.Stub
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+ mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
+
mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
if (DEBUG_SPEW) {
- Slog.d(TAG, "updateScreenStateLocked: displayReady=" + mDisplayReady
+ Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
+ ", newScreenState=" + newScreenState
+ ", mWakefulness=" + mWakefulness
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
@@ -1505,7 +1566,7 @@ public final class PowerManagerService extends IPowerManager.Stub
return value >= -1.0f && value <= 1.0f;
}
- private int getDesiredScreenPowerState() {
+ private int getDesiredScreenPowerStateLocked() {
if (mWakefulness == WAKEFULNESS_ASLEEP) {
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
@@ -1528,7 +1589,16 @@ public final class PowerManagerService extends IPowerManager.Stub
}
@Override
+ public void onProximityPositive() {
+ mProximityPositive = true;
+ mDirty |= DIRTY_PROXIMITY_POSITIVE;
+ updatePowerStateLocked();
+ }
+
+ @Override
public void onProximityNegative() {
+ mProximityPositive = false;
+ mDirty |= DIRTY_PROXIMITY_POSITIVE;
userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
updatePowerStateLocked();
@@ -1986,6 +2056,7 @@ public final class PowerManagerService extends IPowerManager.Stub
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
pw.println(" mStayOn=" + mStayOn);
+ pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
@@ -2048,6 +2119,12 @@ public final class PowerManagerService extends IPowerManager.Stub
pw.println(" " + sb);
}
+ pw.println();
+ pw.println("Screen On Blocker: " + mScreenOnBlocker);
+
+ pw.println();
+ pw.println("Display Blanker: " + mDisplayBlanker);
+
dpc = mDisplayPowerController;
}
@@ -2130,13 +2207,6 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
- private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
- new WindowManagerPolicy.ScreenOnListener() {
- @Override
- public void onScreenOn() {
- }
- };
-
/**
* Handler for asynchronous operations performed by the power manager.
*/
@@ -2154,6 +2224,9 @@ public final class PowerManagerService extends IPowerManager.Stub
case MSG_SANDMAN:
handleSandman();
break;
+ case MSG_SCREEN_ON_BLOCKER_RELEASED:
+ handleScreenOnBlockerReleased();
+ break;
}
}
}
@@ -2299,4 +2372,80 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
}
+
+ private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
+ private int mNestCount;
+
+ public boolean isHeld() {
+ synchronized (this) {
+ return mNestCount != 0;
+ }
+ }
+
+ @Override
+ public void acquire() {
+ synchronized (this) {
+ mNestCount += 1;
+ if (DEBUG) {
+ Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
+ }
+ }
+ }
+
+ @Override
+ public void release() {
+ synchronized (this) {
+ mNestCount -= 1;
+ if (mNestCount < 0) {
+ Log.wtf(TAG, "Screen on blocker was released without being acquired!",
+ new Throwable());
+ mNestCount = 0;
+ }
+ if (mNestCount == 0) {
+ mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (this) {
+ return "held=" + (mNestCount != 0) + ", mNestCount=" + mNestCount;
+ }
+ }
+ }
+
+ private final class DisplayBlankerImpl implements DisplayBlanker {
+ private boolean mBlanked;
+
+ @Override
+ public void blankAllDisplays() {
+ synchronized (this) {
+ mBlanked = true;
+ mDisplayManagerService.blankAllDisplaysFromPowerManager();
+ nativeSetInteractive(false);
+ nativeSetAutoSuspend(true);
+ }
+ }
+
+ @Override
+ public void unblankAllDisplays() {
+ synchronized (this) {
+ nativeSetAutoSuspend(false);
+ nativeSetInteractive(true);
+ mDisplayManagerService.unblankAllDisplaysFromPowerManager();
+ mBlanked = false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ synchronized (this) {
+ return "blanked=" + mBlanked;
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/java/com/android/server/power/ScreenOnBlocker.java
new file mode 100644
index 0000000..dbbbc6d
--- /dev/null
+++ b/services/java/com/android/server/power/ScreenOnBlocker.java
@@ -0,0 +1,41 @@
+/*
+ * 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.power;
+
+/**
+ * Low-level screen on blocker mechanism which is used to keep the screen off
+ * or the contents of the screen hidden until the window manager is ready to show new content.
+ */
+interface ScreenOnBlocker {
+ /**
+ * Acquires the screen on blocker.
+ * Prevents the screen from turning on.
+ *
+ * Calls to acquire() nest and must be matched by the same number
+ * of calls to release().
+ */
+ void acquire();
+
+ /**
+ * Releases the screen on blocker.
+ * Allows the screen to turn on.
+ *
+ * It is an error to call release() if the screen on blocker has not been acquired.
+ * The system may crash.
+ */
+ void release();
+}
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 13b072c..7efffe5 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,7 @@ class AppWindowToken extends WindowToken {
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ boolean showWhenLocked;
// The input dispatching timeout for this application token in nanoseconds.
long inputDispatchingTimeoutNanos;
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 61310ca..d966001 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -21,6 +21,7 @@ import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputWindowHandle;
import com.android.server.wm.WindowManagerService.AllWindowsIterator;
+import android.app.ActivityManagerNative;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
@@ -89,8 +90,9 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle) {
AppWindowToken appWindowToken = null;
+ WindowState windowState = null;
+ boolean aboveSystem = false;
synchronized (mService.mWindowMap) {
- WindowState windowState = null;
if (inputWindowHandle != null) {
windowState = (WindowState) inputWindowHandle.windowState;
if (windowState != null) {
@@ -104,6 +106,12 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
if (windowState != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to " + windowState.mAttrs.getTitle());
+ // Figure out whether this window is layered above system windows.
+ // We need to do this here to help the activity manager know how to
+ // layer its ANR dialog.
+ int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw(
+ WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to application " + appWindowToken.stringName);
@@ -126,6 +134,19 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks {
}
} catch (RemoteException ex) {
}
+ } else if (windowState != null) {
+ try {
+ // Notify the activity manager about the timeout and let it decide whether
+ // to abort dispatching or keep waiting.
+ long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
+ windowState.mSession.mPid, aboveSystem);
+ if (timeout >= 0) {
+ // The activity manager declined to abort dispatching.
+ // Wait a bit longer and timeout again later.
+ return timeout;
+ }
+ } catch (RemoteException ex) {
+ }
}
return 0; // abort dispatching
}
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index d84a52b..3b4c1ab 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -30,8 +30,10 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
@@ -69,8 +71,17 @@ final class Session extends IWindowSession.Stub
StringBuilder sb = new StringBuilder();
sb.append("Session{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(" uid ");
- sb.append(mUid);
+ sb.append(" ");
+ sb.append(mPid);
+ if (mUid < Process.FIRST_APPLICATION_UID) {
+ sb.append(":");
+ sb.append(mUid);
+ } else {
+ sb.append(":u");
+ sb.append(UserHandle.getUserId(mUid));
+ sb.append('a');
+ sb.append(UserHandle.getAppId(mUid));
+ }
sb.append("}");
mStringName = sb.toString();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 180579d..037bfde 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -34,6 +34,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
@@ -1209,12 +1210,9 @@ public class WindowManagerService extends IWindowManager.Stub
final WindowState curTarget = mInputMethodTarget;
if (curTarget != null && w != null
&& curTarget.isDisplayedLw()
- && curTarget.mExiting) {
- if (curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) {
- w = curTarget;
- i = windows.indexOf(w);
- if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, switching to: " + w);
- }
+ && (curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) {
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, not changing");
+ return windows.indexOf(curTarget) + 1;
}
if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target="
@@ -2083,6 +2081,7 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState attachedWindow = null;
WindowState win = null;
long origId;
+ final int type = attrs.type;
synchronized(mWindowMap) {
if (!mDisplayReady) {
@@ -2094,7 +2093,7 @@ public class WindowManagerService extends IWindowManager.Stub
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
- if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
+ if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
attachedWindow = windowForClientLocked(null, attrs.token, false);
if (attachedWindow == null) {
Slog.w(TAG, "Attempted to add window with token that is not a window: "
@@ -2112,31 +2111,29 @@ public class WindowManagerService extends IWindowManager.Stub
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
if (token == null) {
- if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
+ if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG, "Attempted to add application window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_INPUT_METHOD) {
+ if (type == TYPE_INPUT_METHOD) {
Slog.w(TAG, "Attempted to add input method window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_WALLPAPER) {
+ if (type == TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- if (attrs.type == TYPE_DREAM) {
+ if (type == TYPE_DREAM) {
Slog.w(TAG, "Attempted to add Dream window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
- } else if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
+ } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
AppWindowToken atoken = token.appWindowToken;
if (atoken == null) {
Slog.w(TAG, "Attempted to add window with non-application token "
@@ -2147,25 +2144,25 @@ public class WindowManagerService extends IWindowManager.Stub
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
- if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
+ if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
// No need for this guy!
if (localLOGV) Slog.v(
TAG, "**** NO NEED TO START: " + attrs.getTitle());
return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
}
- } else if (attrs.type == TYPE_INPUT_METHOD) {
+ } else if (type == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
Slog.w(TAG, "Attempted to add input method window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- } else if (attrs.type == TYPE_WALLPAPER) {
+ } else if (type == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
Slog.w(TAG, "Attempted to add wallpaper window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
- } else if (attrs.type == TYPE_DREAM) {
+ } else if (type == TYPE_DREAM) {
if (token.windowType != TYPE_DREAM) {
Slog.w(TAG, "Attempted to add Dream window with bad token "
+ attrs.token + ". Aborting.");
@@ -2185,6 +2182,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
mPolicy.adjustWindowParamsLw(win.mAttrs);
+ win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
@@ -2213,8 +2211,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.attach();
mWindowMap.put(client.asBinder(), win);
- if (attrs.type == TYPE_APPLICATION_STARTING &&
- token.appWindowToken != null) {
+ if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
token.appWindowToken.startingWindow = win;
if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken
+ " startingWindow=" + win);
@@ -2222,19 +2219,19 @@ public class WindowManagerService extends IWindowManager.Stub
boolean imMayMove = true;
- if (attrs.type == TYPE_INPUT_METHOD) {
+ if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
- } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
+ } else if (type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
adjustInputMethodDialogsLocked();
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
- if (attrs.type == TYPE_WALLPAPER) {
+ if (type == TYPE_WALLPAPER) {
mLastWallpaperTimeoutTime = 0;
adjustWallpaperWindowsLocked();
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
@@ -2752,10 +2749,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- if (DEBUG_LAYOUT
- // TODO: Remove once b/7094175 is fixed
- || ((String)win.mAttrs.getTitle()).contains("Keyguard")
- ) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
@@ -3703,7 +3697,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void addAppToken(int addPos, IApplicationToken token,
- int groupId, int requestedOrientation, boolean fullscreen) {
+ int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3733,6 +3727,7 @@ public class WindowManagerService extends IWindowManager.Stub
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.groupId = groupId;
atoken.appFullscreen = fullscreen;
+ atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " at " + addPos);
@@ -4183,6 +4178,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
public void setAppStartingWindow(IBinder token, String pkg,
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon,
@@ -5404,6 +5400,22 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
mCurrentUserId = newUserId;
mPolicy.setCurrentUserLw(newUserId);
+
+ // Hide windows that should not be seen by the new user.
+ DisplayContentsIterator iterator = new DisplayContentsIterator();
+ while (iterator.hasNext()) {
+ final WindowList windows = iterator.next().getWindowList();
+ for (int i = 0; i < windows.size(); i++) {
+ final WindowState win = windows.get(i);
+ if (win.isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + newUserId + " hiding "
+ + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+ + win.mOwnerUid);
+ win.hideLw(false);
+ }
+ }
+ }
+ performLayoutAndPlaceSurfacesLocked();
}
}
@@ -8221,7 +8233,9 @@ public class WindowManagerService extends IWindowManager.Stub
int seq = mLayoutSeq+1;
if (seq < 0) seq = 0;
mLayoutSeq = seq;
-
+
+ boolean behindDream = false;
+
// First perform layout of any root windows (not attached
// to another window).
int topAttached = -1;
@@ -8231,7 +8245,8 @@ public class WindowManagerService extends IWindowManager.Stub
// Don't do layout of a window if it is not visible, or
// soon won't be visible, to avoid wasting time and funky
// changes while a window is animating away.
- final boolean gone = win.isGoneForLayoutLw();
+ final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
+ || win.isGoneForLayoutLw();
if (DEBUG_LAYOUT && !win.mLayoutAttached) {
Slog.v(TAG, "1ST PASS " + win
@@ -8266,6 +8281,12 @@ public class WindowManagerService extends IWindowManager.Stub
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ behindDream = true;
+ }
win.mLayoutNeeded = false;
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -8290,6 +8311,8 @@ public class WindowManagerService extends IWindowManager.Stub
mAnimator.mUniverseBackground = universeBackground;
}
+ boolean attachedBehindDream = false;
+
// Now perform layout of attached windows, which usually
// depend on the position of the window they are attached to.
// XXX does not deal with windows that are attached to windows
@@ -8307,6 +8330,9 @@ public class WindowManagerService extends IWindowManager.Stub
// if they want. (We do the normal layout for INVISIBLE
// windows, since that means "perform layout as normal,
// just don't display").
+ if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
+ continue;
+ }
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame || win.mLayoutNeeded) {
if (initial) {
@@ -8322,6 +8348,11 @@ public class WindowManagerService extends IWindowManager.Stub
+ win.mContainingFrame + " mDisplayFrame="
+ win.mDisplayFrame);
}
+ } else if (win.mAttrs.type == TYPE_DREAM) {
+ // Don't layout windows behind a dream, so that if it
+ // does stuff like hide the status bar we won't get a
+ // bad transition when it goes away.
+ attachedBehindDream = behindDream;
}
}
@@ -8690,7 +8721,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void updateResizingWindows(final WindowState w) {
final WindowStateAnimator winAnimator = w.mWinAnimator;
- if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
+ if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
w.mContentInsetsChanged |=
!w.mLastContentInsets.equals(w.mContentInsets);
w.mVisibleInsetsChanged |=
@@ -8784,6 +8815,7 @@ public class WindowManagerService extends IWindowManager.Stub
final int type = attrs.type;
if (canBeSeen
&& (type == TYPE_SYSTEM_DIALOG
+ || type == TYPE_RECENTS_OVERLAY
|| type == TYPE_KEYGUARD
|| type == TYPE_SYSTEM_ERROR)) {
mInnerFields.mSyswin = true;
@@ -9224,39 +9256,39 @@ public class WindowManagerService extends IWindowManager.Stub
defaultDisplay.pendingLayoutChanges);
}
- if (!mResizingWindows.isEmpty()) {
- for (i = mResizingWindows.size() - 1; i >= 0; i--) {
- WindowState win = mResizingWindows.get(i);
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- try {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mCompatFrame);
- int diff = 0;
- boolean configChanged = win.isConfigChanged();
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
- // TODO: Remove once b/7094175 is fixed
- || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
- && configChanged) {
- Slog.i(TAG, "Sending new config to window " + win + ": "
- + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
- + " / " + mCurConfiguration + " / 0x"
- + Integer.toHexString(diff));
- }
- win.mConfiguration = mCurConfiguration;
- if (DEBUG_ORIENTATION &&
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
- win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
- winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
- configChanged ? win.mConfiguration : null);
- win.mContentInsetsChanged = false;
- win.mVisibleInsetsChanged = false;
- winAnimator.mSurfaceResized = false;
- } catch (RemoteException e) {
- win.mOrientationChanging = false;
- }
+ for (i = mResizingWindows.size() - 1; i >= 0; i--) {
+ WindowState win = mResizingWindows.get(i);
+ if (win.mAppFreezing) {
+ // Don't remove this window until rotation has completed.
+ continue;
+ }
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ try {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+ "Reporting new frame to " + win + ": " + win.mCompatFrame);
+ int diff = 0;
+ boolean configChanged = win.isConfigChanged();
+ if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
+ && configChanged) {
+ Slog.i(TAG, "Sending new config to window " + win + ": "
+ + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
+ + " / " + mCurConfiguration + " / 0x"
+ + Integer.toHexString(diff));
+ }
+ win.mConfiguration = mCurConfiguration;
+ if (DEBUG_ORIENTATION &&
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
+ TAG, "Resizing " + win + " WITH DRAW PENDING");
+ win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
+ winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
+ configChanged ? win.mConfiguration : null);
+ win.mContentInsetsChanged = false;
+ win.mVisibleInsetsChanged = false;
+ winAnimator.mSurfaceResized = false;
+ } catch (RemoteException e) {
+ win.mOrientationChanging = false;
}
- mResizingWindows.clear();
+ mResizingWindows.remove(i);
}
if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
@@ -9450,18 +9482,22 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
- synchronized (mWindowMap) {
- WindowState win = windowForClientLocked(null, token, true);
- if (win != null) {
- Pair<WindowState, IRemoteCallback> pair =
- new Pair<WindowState, IRemoteCallback>(win, callback);
- Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
- mH.sendMessageDelayed(m, 2000);
- mWaitingForDrawn.add(pair);
- checkDrawnWindowsLocked();
+ public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
+ if (token != null && callback != null) {
+ synchronized (mWindowMap) {
+ WindowState win = windowForClientLocked(null, token, true);
+ if (win != null) {
+ Pair<WindowState, IRemoteCallback> pair =
+ new Pair<WindowState, IRemoteCallback>(win, callback);
+ Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
+ mH.sendMessageDelayed(m, 2000);
+ mWaitingForDrawn.add(pair);
+ checkDrawnWindowsLocked();
+ return true;
+ }
}
}
+ return false;
}
void setHoldScreenLocked(final Session newHoldScreen) {
@@ -9475,10 +9511,10 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean state = mHoldingScreenWakeLock.isHeld();
if (hold != state) {
if (hold) {
- mPolicy.screenOnStartedLw();
mHoldingScreenWakeLock.acquire();
+ mPolicy.keepScreenOnStartedLw();
} else {
- mPolicy.screenOnStoppedLw();
+ mPolicy.keepScreenOnStoppedLw();
mHoldingScreenWakeLock.release();
}
}
@@ -10155,8 +10191,8 @@ public class WindowManagerService extends IWindowManager.Stub
return mPolicy.hasNavigationBar();
}
- public void lockNow() {
- mPolicy.lockNow();
+ public void lockNow(Bundle options) {
+ mPolicy.lockNow(options);
}
void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 9963d14..23892f6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -22,9 +22,6 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import com.android.server.input.InputWindowHandle;
@@ -36,7 +33,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.IBinder;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
@@ -263,7 +259,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
DisplayContent mDisplayContent;
// UserId and appId of the owner. Don't display windows of non-current user.
- final int mOwnerUid;
+ int mOwnerUid;
+
+ /** When true this window can be displayed on screens owther than mOwnerUid's */
+ private boolean mShowToOwnerOnly;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
@@ -654,6 +653,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* surface, or we are in the process of running an exit animation
* that will remove the surface, or its app token has been hidden.
*/
+ @Override
public boolean isVisibleLw() {
final AppWindowToken atoken = mAppToken;
return mHasSurface && mPolicyVisibility && !mAttachedHidden
@@ -669,6 +669,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* for this "hidden behind keyguard" state rather than overloading
* mPolicyVisibility. Ungh.
*/
+ @Override
public boolean isVisibleOrBehindKeyguardLw() {
if (mRootToken.waitingToShow &&
mService.mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -787,18 +788,21 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* Like isOnScreen, but returns false if the surface hasn't yet
* been drawn.
*/
+ @Override
public boolean isDisplayedLw() {
final AppWindowToken atoken = mAppToken;
return isDrawnLw() && mPolicyVisibility
&& ((!mAttachedHidden &&
(atoken == null || !atoken.hiddenRequested))
- || mWinAnimator.mAnimating);
+ || mWinAnimator.mAnimating
+ || (atoken != null && atoken.mAppAnimator.animation != null));
}
/**
* Return true if this window (or a window it is attached to, but not
* considering its app token) is currently animating.
*/
+ @Override
public boolean isAnimatingLw() {
return mWinAnimator.mAnimation != null;
}
@@ -939,8 +943,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
}
boolean showLw(boolean doAnimation, boolean requestAnim) {
- if (isOtherUsersAppWindow()) {
- Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+ if (isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
return false;
}
@@ -1025,15 +1029,23 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mDisplayContent.isDefaultDisplay;
}
- boolean isOtherUsersAppWindow() {
- final int type = mAttrs.type;
- if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
- && (mOwnerUid != Process.SYSTEM_UID)
- && (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW)
- && (type != TYPE_APPLICATION_STARTING)) {
- return true;
+ public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
+ mShowToOwnerOnly = showToOwnerOnly;
+ }
+
+ boolean isHiddenFromUserLocked() {
+ // Save some cycles by not calling getDisplayInfo unless it is an application
+ // window intended for all users.
+ if (mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+ && mAppToken != null && mAppToken.showWhenLocked) {
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+ if (isFullscreen(displayInfo.appWidth, displayInfo.appHeight)) {
+ // Is a fullscreen window, like the clock alarm. Show to everyone.
+ return false;
+ }
}
- return false;
+
+ return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
}
private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
@@ -1072,6 +1084,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
pw.print(" mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
+ pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
+ pw.print(" mShowToOwnerOnly="); pw.println(mShowToOwnerOnly);
pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
pw.print(" h="); pw.print(mRequestedHeight);
@@ -1219,7 +1233,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
mLastTitle = mAttrs.getTitle();
mWasPaused = mToken.paused;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
- + " " + mLastTitle + " paused=" + mWasPaused + "}";
+ + " u" + UserHandle.getUserId(mSession.mUid)
+ + " " + mLastTitle + (mWasPaused ? " PAUSED}" : "}");
}
return mStringNameCache;
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index acf452f..2bfefe1 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1334,8 +1334,8 @@ class WindowStateAnimator {
// This must be called while inside a transaction.
boolean performShowLocked() {
- if (mWin.isOtherUsersAppWindow()) {
- Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+ if (mWin.isHiddenFromUserLocked()) {
+ Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
+ this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
return false;
}
@@ -1500,7 +1500,7 @@ class WindowStateAnimator {
int attr = -1;
Animation a = null;
if (anim != 0) {
- a = AnimationUtils.loadAnimation(mContext, anim);
+ a = anim != -1 ? AnimationUtils.loadAnimation(mContext, anim) : null;
} else {
switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER: