summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt5
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java5
-rw-r--r--core/java/android/app/ActivityManagerNative.java2
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/NotificationManager.java6
-rw-r--r--core/java/android/content/Context.java15
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java40
-rw-r--r--core/java/android/net/Uri.java38
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java33
-rw-r--r--core/java/android/os/IPowerManager.aidl1
-rw-r--r--core/java/android/os/PowerManager.java34
-rw-r--r--core/java/android/os/UserHandle.aidl19
-rw-r--r--core/java/android/service/dreams/Dream.java35
-rw-r--r--core/java/android/service/dreams/IDreamManager.aidl2
-rw-r--r--core/java/android/view/HardwareRenderer.java32
-rw-r--r--core/java/android/view/ScaleGestureDetector.java4
-rw-r--r--core/java/android/view/SurfaceView.java13
-rw-r--r--core/java/android/view/View.java199
-rw-r--r--core/java/android/view/ViewGroup.java82
-rw-r--r--core/java/android/widget/AnalogClock.java4
-rw-r--r--core/java/android/widget/ImageView.java2
-rw-r--r--core/java/android/widget/RemoteViews.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java5
-rwxr-xr-xcore/res/res/values/attrs.xml13
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java15
-rw-r--r--docs/html/about/versions/jelly-bean.jd6
-rw-r--r--docs/html/guide/google/play/services.jd37
-rw-r--r--docs/html/guide/topics/appwidgets/index.jd5
-rw-r--r--graphics/java/android/renderscript/ScriptIntrinsicBlend.java11
-rw-r--r--libs/hwui/Layer.cpp12
-rw-r--r--libs/hwui/Layer.h2
-rw-r--r--libs/hwui/LayerRenderer.cpp8
-rw-r--r--libs/hwui/LayerRenderer.h4
-rw-r--r--libs/hwui/OpenGLRenderer.cpp10
-rw-r--r--libs/hwui/Program.cpp9
-rw-r--r--libs/hwui/Program.h5
-rw-r--r--libs/hwui/ProgramCache.cpp15
-rw-r--r--libs/hwui/Texture.h2
-rw-r--r--media/java/android/media/IRingtonePlayer.aidl3
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/Somnambulator.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java3
-rw-r--r--services/java/com/android/server/DockObserver.java89
-rw-r--r--services/java/com/android/server/DreamController.java217
-rw-r--r--services/java/com/android/server/DreamManagerService.java387
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/java/com/android/server/UiModeManagerService.java220
-rw-r--r--services/java/com/android/server/am/ActiveServices.java16
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java240
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java6
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java26
-rw-r--r--services/java/com/android/server/am/BroadcastFilter.java2
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java14
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java2
-rw-r--r--services/java/com/android/server/am/ConnectionRecord.java9
-rw-r--r--services/java/com/android/server/am/ContentProviderRecord.java3
-rw-r--r--services/java/com/android/server/am/EventLogTags.logtags66
-rw-r--r--services/java/com/android/server/am/ProcessList.java19
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java44
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java1
-rw-r--r--services/java/com/android/server/dreams/DreamController.java243
-rw-r--r--services/java/com/android/server/dreams/DreamManagerService.java383
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java145
-rw-r--r--tests/ActivityTests/AndroidManifest.xml4
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java90
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ServiceUserTarget.java41
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/SingleUserService.java10
-rw-r--r--tests/RenderScriptTests/ImageProcessing/res/layout/main.xml4
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java176
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java26
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java15
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs24
-rw-r--r--tools/aapt/Resource.cpp2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java5
77 files changed, 2047 insertions, 1276 deletions
diff --git a/api/current.txt b/api/current.txt
index d5e585df6802..177b78705968 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12745,14 +12745,12 @@ package android.net {
method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache);
method public java.lang.String[] getDefaultCipherSuites();
method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
- method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, int, android.net.SSLSessionCache);
method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
method public byte[] getNpnSelectedProtocol(java.net.Socket);
method public java.lang.String[] getSupportedCipherSuites();
method public void setHostname(java.net.Socket, java.lang.String);
method public void setKeyManagers(javax.net.ssl.KeyManager[]);
method public void setNpnProtocols(byte[][]);
- method public void setSoWriteTimeout(java.net.Socket, int) throws java.net.SocketException;
method public void setTrustManagers(javax.net.ssl.TrustManager[]);
method public void setUseSessionTickets(java.net.Socket, boolean);
}
@@ -20332,7 +20330,6 @@ package android.service.dreams {
method public boolean isInteractive();
method public boolean isLowProfile();
method public boolean isScreenBright();
- method protected deprecated void lightsOut();
method public void onActionModeFinished(android.view.ActionMode);
method public void onActionModeStarted(android.view.ActionMode);
method public void onAttachedToWindow();
@@ -20360,7 +20357,7 @@ package android.service.dreams {
field public static final java.lang.String ACTION_DREAMING_STARTED = "android.intent.action.DREAMING_STARTED";
field public static final java.lang.String ACTION_DREAMING_STOPPED = "android.intent.action.DREAMING_STOPPED";
field public static final java.lang.String CATEGORY_DREAM = "android.intent.category.DREAM";
- field public static final java.lang.String METADATA_NAME_CONFIG_ACTIVITY = "android.service.dreams.config_activity";
+ field public static final java.lang.String DREAM_META_DATA = "android.service.dream";
}
}
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bc9e74ed4c27..396b32fb7508 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -804,8 +804,9 @@ public class Am {
ParcelFileDescriptor fd = null;
try {
- fd = ParcelFileDescriptor.open(
- new File(heapFile),
+ File file = new File(heapFile);
+ file.delete();
+ fd = ParcelFileDescriptor.open(file,
ParcelFileDescriptor.MODE_CREATE |
ParcelFileDescriptor.MODE_TRUNCATE |
ParcelFileDescriptor.MODE_READ_WRITE);
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 9b08493f0379..9874b0b36caf 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1509,9 +1509,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
case DUMP_HEAP_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String process = data.readString();
+ int userId = data.readInt();
boolean managed = data.readInt() != 0;
String path = data.readString();
- int userId = data.readInt();
ParcelFileDescriptor fd = data.readInt() != 0
? data.readFileDescriptor() : null;
boolean res = dumpHeap(process, userId, managed, path, fd);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index d4b204f8528e..6638433e741a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2711,7 +2711,7 @@ public final class ActivityThread {
r.activity.performResume();
EventLog.writeEvent(LOG_ON_RESUME_CALLED,
- r.activity.getComponentName().getClassName());
+ UserHandle.myUserId(), r.activity.getComponentName().getClassName());
r.paused = false;
r.stopped = false;
@@ -2979,7 +2979,8 @@ public final class ActivityThread {
// Now we are idle.
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
- EventLog.writeEvent(LOG_ON_PAUSE_CALLED, r.activity.getComponentName().getClassName());
+ EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
+ r.activity.getComponentName().getClassName());
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
@@ -3364,7 +3365,7 @@ public final class ActivityThread {
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
- EventLog.writeEvent(LOG_ON_PAUSE_CALLED,
+ EventLog.writeEvent(LOG_ON_PAUSE_CALLED, UserHandle.myUserId(),
r.activity.getComponentName().getClassName());
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c095280e57d4..0acad759501f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -124,6 +124,9 @@ public class NotificationManager
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+ if (notification.sound != null) {
+ notification.sound = notification.sound.getCanonicalUri();
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
@@ -143,6 +146,9 @@ public class NotificationManager
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+ if (notification.sound != null) {
+ notification.sound = notification.sound.getCanonicalUri();
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ac36cf714f11..201b43f43728 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -178,7 +178,7 @@ public abstract class Context {
* Flag for {@link #bindService}: indicates that the client application
* binding to this service considers the service to be more important than
* the app itself. When set, the platform will try to have the out of
- * memory kill the app before it kills the service it is bound to, though
+ * memory killer kill the app before it kills the service it is bound to, though
* this is not guaranteed to be the case.
*/
public static final int BIND_ABOVE_CLIENT = 0x0008;
@@ -219,6 +219,19 @@ public abstract class Context {
public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
/**
+ * @hide An idea that is not yet implemented.
+ * Flag for {@link #bindService}: If binding from an activity, consider
+ * this service to be visible like the binding activity is. That is,
+ * it will be treated as something more important to keep around than
+ * invisible background activities. This will impact the number of
+ * recent activities the user can switch between without having them
+ * restart. There is no guarantee this will be respected, as the system
+ * tries to balance such requests from one app vs. the importantance of
+ * keeping other apps around.
+ */
+ public static final int BIND_VISIBLE = 0x0100;
+
+ /**
* Flag for {@link #bindService}: Don't consider the bound service to be
* visible, even if the caller is visible.
* @hide
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 42fb5c3cd682..846443d6d235 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -90,7 +90,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
private byte[] mNpnProtocols = null;
private final int mHandshakeTimeoutMillis;
- private final int mWriteTimeoutMillis;
private final SSLClientSessionCache mSessionCache;
private final boolean mSecure;
@@ -101,21 +100,12 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
private SSLCertificateSocketFactory(
- int handshakeTimeoutMillis,
- int writeTimeoutMillis,
- SSLSessionCache cache,
- boolean secure) {
+ int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
mHandshakeTimeoutMillis = handshakeTimeoutMillis;
- mWriteTimeoutMillis = writeTimeoutMillis;
mSessionCache = cache == null ? null : cache.mSessionCache;
mSecure = secure;
}
- private SSLCertificateSocketFactory(
- int handshakeTimeoutMillis, SSLSessionCache cache, boolean secure) {
- this(handshakeTimeoutMillis, 0, cache, secure);
- }
-
/**
* Returns a new socket factory instance with an optional handshake timeout.
*
@@ -172,24 +162,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
}
/**
- * Returns a socket factory (also named SSLSocketFactory, but in a different
- * namespace) for use with the Apache HTTP stack.
- *
- * @param handshakeTimeoutMillis to use for SSL connection handshake, or 0
- * for none. The socket timeout is reset to 0 after the handshake.
- * @param writeTimeoutMillis the desired write timeout in milliseconds or 0 for none.
- * @param cache The {@link SSLSessionCache} to use, or null for no cache.
- * @return a new SocketFactory with the specified parameters
- */
- public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(
- int handshakeTimeoutMillis,
- int writeTimeoutMillis,
- SSLSessionCache cache) {
- return new org.apache.http.conn.ssl.SSLSocketFactory(new SSLCertificateSocketFactory(
- handshakeTimeoutMillis, writeTimeoutMillis, cache, true));
- }
-
- /**
* Verify the hostname of the certificate used by the other end of a
* connected socket. You MUST call this if you did not supply a hostname
* to {@link #createSocket()}. It is harmless to call this method
@@ -376,8 +348,10 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
* To take effect, this option must be set before the blocking method was called.
*
* @param socket a socket created by this factory.
- * @param writeTimeoutMilliseconds the desired write timeout in milliseconds.
+ * @param timeout the desired write timeout in milliseconds.
* @throws IllegalArgumentException if the socket was not created by this factory.
+ *
+ * @hide
*/
public void setSoWriteTimeout(Socket socket, int writeTimeoutMilliseconds)
throws SocketException {
@@ -404,7 +378,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
}
@@ -424,7 +397,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
return s;
}
@@ -442,7 +414,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
addr, port, localAddr, localPort);
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
return s;
}
@@ -458,7 +429,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
return s;
}
@@ -475,7 +445,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
host, port, localAddr, localPort);
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
}
@@ -493,7 +462,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
- s.setSoWriteTimeout(mWriteTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3b990e3f937d..cc6903dbacad 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,10 +16,13 @@
package android.net;
+import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Environment.UserEnvironment;
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charsets;
@@ -2288,4 +2291,39 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
builder = builder.appendEncodedPath(pathSegment);
return builder.build();
}
+
+ /**
+ * If this {@link Uri} is {@code file://}, then resolve and return its
+ * canonical path. Also fixes legacy emulated storage paths so they are
+ * usable across user boundaries. Should always be called from the app
+ * process before sending elsewhere.
+ *
+ * @hide
+ */
+ public Uri getCanonicalUri() {
+ if ("file".equals(getScheme())) {
+ final String canonicalPath;
+ try {
+ canonicalPath = new File(getPath()).getCanonicalPath();
+ } catch (IOException e) {
+ return this;
+ }
+
+ if (Environment.isExternalStorageEmulated()) {
+ final String legacyPath = Environment.getLegacyExternalStorageDirectory()
+ .toString();
+
+ // Splice in user-specific path when legacy path is found
+ if (canonicalPath.startsWith(legacyPath)) {
+ return Uri.fromFile(new File(
+ Environment.getExternalStorageDirectory().toString(),
+ canonicalPath.substring(legacyPath.length() + 1)));
+ }
+ }
+
+ return Uri.fromFile(new File(canonicalPath));
+ } else {
+ return this;
+ }
+ }
}
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 8169a943c206..c534e58f37e1 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -16,16 +16,7 @@
package android.net.http;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.SSLCertificateSocketFactory;
-import android.net.SSLSessionCache;
-import android.os.Looper;
-import android.util.Base64;
-import android.util.Log;
-
import com.android.internal.http.HttpDateTime;
-
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
@@ -34,18 +25,18 @@ import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
+import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
@@ -53,17 +44,25 @@ import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
-import java.net.URI;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
+import java.net.URI;
+
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.SSLCertificateSocketFactory;
+import android.net.SSLSessionCache;
+import android.os.Looper;
+import android.util.Base64;
+import android.util.Log;
/**
* Implementation of the Apache {@link DefaultHttpClient} that is configured with
@@ -135,7 +134,7 @@ public final class AndroidHttpClient implements HttpClient {
PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https",
SSLCertificateSocketFactory.getHttpSocketFactory(
- SOCKET_OPERATION_TIMEOUT, SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
+ SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 7aee64440ef7..eec19cb8c3b9 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -34,6 +34,7 @@ interface IPowerManager
void userActivity(long time, int event, int flags);
void wakeUp(long time);
void goToSleep(long time, int reason);
+ void nap(long time);
boolean isScreenOn();
void reboot(String reason);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cc2c002e4e0a..58372f4ebe70 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -426,7 +426,7 @@ public final class PowerManager {
* </p>
*
* @param when The time of the user activity, in the {@link SystemClock#uptimeMillis()}
- * time base. This timestamp is used to correctly order the user activity with
+ * time base. This timestamp is used to correctly order the user activity request with
* other power management functions. It should be set
* to the timestamp of the input event that caused the user activity.
* @param noChangeLights If true, does not cause the keyboard backlight to turn on
@@ -457,7 +457,7 @@ public final class PowerManager {
*
* @param time The time when the request to go to sleep was issued, in the
* {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
- * order the user activity with other power management functions. It should be set
+ * order the go to sleep request with other power management functions. It should be set
* to the timestamp of the input event that caused the request to go to sleep.
*
* @see #userActivity
@@ -481,7 +481,7 @@ public final class PowerManager {
*
* @param time The time when the request to wake up was issued, in the
* {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
- * order the user activity with other power management functions. It should be set
+ * order the wake up request with other power management functions. It should be set
* to the timestamp of the input event that caused the request to wake up.
*
* @see #userActivity
@@ -495,6 +495,34 @@ public final class PowerManager {
}
/**
+ * Forces the device to start napping.
+ * <p>
+ * If the device is currently awake, starts dreaming, otherwise does nothing.
+ * When the dream ends or if the dream cannot be started, the device will
+ * either wake up or go to sleep depending on whether there has been recent
+ * user activity.
+ * </p><p>
+ * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+ * </p>
+ *
+ * @param time The time when the request to nap was issued, in the
+ * {@link SystemClock#uptimeMillis()} time base. This timestamp is used to correctly
+ * order the nap request with other power management functions. It should be set
+ * to the timestamp of the input event that caused the request to nap.
+ *
+ * @see #wakeUp
+ * @see #goToSleep
+ *
+ * @hide
+ */
+ public void nap(long time) {
+ try {
+ mService.nap(time);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Sets the brightness of the backlights (screen, keyboard, button).
* <p>
* Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/core/java/android/os/UserHandle.aidl b/core/java/android/os/UserHandle.aidl
new file mode 100644
index 000000000000..4892d322b2d6
--- /dev/null
+++ b/core/java/android/os/UserHandle.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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 android.os;
+
+parcelable UserHandle;
diff --git a/core/java/android/service/dreams/Dream.java b/core/java/android/service/dreams/Dream.java
index dedfb0cc5561..590acfad680c 100644
--- a/core/java/android/service/dreams/Dream.java
+++ b/core/java/android/service/dreams/Dream.java
@@ -59,10 +59,10 @@ import com.android.internal.policy.PolicyManager;
* <category android:name="android.intent.category.DREAM" />
* </intent-filter>
*
- * <!-- Point to configuration activity for this dream (optional) -->
+ * <!-- Point to additional information for this dream (optional) -->
* <meta-data
- * android:name="android.service.dreams.config_activity"
- * android:value="com.example.mypackage/com.example.mypackage.MyDreamSettingsActivity" />
+ * android:name="android.service.dream"
+ * android:resource="@xml/my_dream" />
* </service>
* }
* </pre>
@@ -72,6 +72,12 @@ public class Dream extends Service implements Window.Callback {
private final String TAG = Dream.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
/**
+ * The name of the dream manager service.
+ * @hide
+ */
+ public static final String DREAM_SERVICE = "dreams";
+
+ /**
* Used with {@link Intent#ACTION_MAIN} to declare the necessary intent-filter for a dream.
*
* @see Dream
@@ -81,12 +87,12 @@ public class Dream extends Service implements Window.Callback {
"android.intent.category.DREAM";
/**
- * Service meta-data key for declaring an optional configuration activity.
- *
- * @see Dream
- * */
- public static final String METADATA_NAME_CONFIG_ACTIVITY =
- "android.service.dreams.config_activity";
+ * Name under which a Dream publishes information about itself.
+ * This meta-data must reference an XML resource containing
+ * a <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code>
+ * tag.
+ */
+ public static final String DREAM_META_DATA = "android.service.dream";
/**
* Broadcast Action: Sent after the system starts dreaming.
@@ -361,13 +367,6 @@ public class Dream extends Service implements Window.Callback {
return getWindow().findViewById(id);
}
- /** FIXME remove once platform dreams are updated */
- @Deprecated
- protected void lightsOut() {
- setLowProfile(true);
- setFullscreen(true);
- }
-
/**
* Marks this dream as interactive to receive input events.
*
@@ -506,7 +505,7 @@ public class Dream extends Service implements Window.Callback {
// end public api
private void loadSandman() {
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
}
private final void attach(IBinder windowToken) {
@@ -591,7 +590,7 @@ public class Dream extends Service implements Window.Callback {
mFinished = true;
if (mSandman != null) {
- mSandman.awakenSelf(mWindowToken);
+ mSandman.finishSelf(mWindowToken);
} else {
Slog.w(TAG, "No dream manager found");
}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index bd1c5245ab5e..1c1b39094776 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -30,5 +30,5 @@ interface IDreamManager {
ComponentName getDefaultDreamComponent();
void testDream(in ComponentName componentName);
boolean isDreaming();
- void awakenSelf(in IBinder token);
+ void finishSelf(in IBinder token);
} \ No newline at end of file
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index da925c787a2c..28763b3c949d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -21,6 +21,7 @@ import android.content.ComponentCallbacks2;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.opengl.EGL14;
import android.opengl.GLUtils;
import android.opengl.ManagedEGLContext;
import android.os.Handler;
@@ -608,12 +609,6 @@ public abstract class HardwareRenderer {
@SuppressWarnings({"deprecation"})
static abstract class GlRenderer extends HardwareRenderer {
- // These values are not exposed in our EGL APIs
- static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- static final int EGL_OPENGL_ES2_BIT = 4;
- static final int EGL_SURFACE_TYPE = 0x3033;
- static final int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
-
static final int SURFACE_STATE_ERROR = 0;
static final int SURFACE_STATE_SUCCESS = 1;
static final int SURFACE_STATE_UPDATED = 2;
@@ -953,19 +948,8 @@ public abstract class HardwareRenderer {
return null;
}
- /*
- * Before we can issue GL commands, we need to make sure
- * the context is current and bound to a surface.
- */
- if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
- + GLUtils.getEGLErrorString(sEgl.eglGetError()));
- }
-
initCaches();
- enableDirtyRegions();
-
return mEglContext.getGL();
}
@@ -990,7 +974,7 @@ public abstract class HardwareRenderer {
abstract void initCaches();
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
- int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
+ int[] attribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
EGLContext context = egl.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT,
mGlVersion != 0 ? attribs : null);
@@ -1066,6 +1050,14 @@ public abstract class HardwareRenderer {
throw new RuntimeException("createWindowSurface failed "
+ GLUtils.getEGLErrorString(error));
}
+
+ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new IllegalStateException("eglMakeCurrent failed " +
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
+ }
+
+ enableDirtyRegions();
+
return true;
}
@@ -1430,7 +1422,7 @@ public abstract class HardwareRenderer {
@Override
int[] getConfig(boolean dirtyRegions) {
return new int[] {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
@@ -1439,7 +1431,7 @@ public abstract class HardwareRenderer {
// TODO: Find a better way to choose the stencil size
EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
- (dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+ (dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
EGL_NONE
};
}
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 123ce2a92d9b..b0a271198ca2 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -314,7 +314,7 @@ public class ScaleGestureDetector {
}
}
- final boolean configChanged =
+ final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_UP ||
action == MotionEvent.ACTION_POINTER_DOWN;
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
@@ -344,7 +344,7 @@ public class ScaleGestureDetector {
if (skipIndex == i) continue;
// Average touch major and touch minor and convert the resulting diameter into a radius.
- final float touchSize = getAdjustedTouchHistory(event.getPointerId(i));
+ final float touchSize = getAdjustedTouchHistory(event.getPointerId(i)) / 2;
devSumX += Math.abs(event.getX(i) - focusX) + touchSize;
devSumY += Math.abs(event.getY(i) - focusY) + touchSize;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 3be63d5b5704..0d16dd31b0bc 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -46,13 +46,18 @@ import java.util.concurrent.locks.ReentrantLock;
*
* <p>The surface is Z ordered so that it is behind the window holding its
* SurfaceView; the SurfaceView punches a hole in its window to allow its
- * surface to be displayed. The view hierarchy will take care of correctly
+ * surface to be displayed. The view hierarchy will take care of correctly
* compositing with the Surface any siblings of the SurfaceView that would
- * normally appear on top of it. This can be used to place overlays such as
+ * normally appear on top of it. This can be used to place overlays such as
* buttons on top of the Surface, though note however that it can have an
* impact on performance since a full alpha-blended composite will be performed
* each time the Surface changes.
*
+ * <p> The transparent region that makes the surface visible is based on the
+ * layout positions in the view hierarchy. If the post-layout transform
+ * properties are used to draw a sibling view on top of the SurfaceView, the
+ * view may not be properly composited with the surface.
+ *
* <p>Access to the underlying surface is provided via the SurfaceHolder interface,
* which can be retrieved by calling {@link #getHolder}.
*
@@ -62,14 +67,14 @@ import java.util.concurrent.locks.ReentrantLock;
* Surface is created and destroyed as the window is shown and hidden.
*
* <p>One of the purposes of this class is to provide a surface in which a
- * secondary thread can render into the screen. If you are going to use it
+ * secondary thread can render into the screen. If you are going to use it
* this way, you need to be aware of some threading semantics:
*
* <ul>
* <li> All SurfaceView and
* {@link SurfaceHolder.Callback SurfaceHolder.Callback} methods will be called
* from the thread running the SurfaceView's window (typically the main thread
- * of the application). They thus need to correctly synchronize with any
+ * of the application). They thus need to correctly synchronize with any
* state that is also touched by the drawing thread.
* <li> You must ensure that the drawing thread only touches the underlying
* Surface while it is valid -- between
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ecacaca62f2d..12eb800fc3a3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2141,6 +2141,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG2_PADDING_RESOLVED = 0x20000000;
+ /**
+ * Flag indicating that the start/end drawables has been resolved into left/right ones.
+ */
+ static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000;
+
+ /**
+ * Group of bits indicating that RTL properties resolution is done.
+ */
+ static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED |
+ PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED;
+
// There are a couple of flags left in mPrivateFlags2
/* End of masks for mPrivateFlags2 */
@@ -3199,9 +3210,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mResources = context != null ? context.getResources() : null;
mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
// Set layout and text direction defaults
- mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
+ mPrivateFlags2 =
+ (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
(TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) |
+ (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) |
(TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) |
+ (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) |
(IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
@@ -3419,7 +3433,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
break;
case com.android.internal.R.styleable.View_layoutDirection:
// Clear any layout direction flags (included resolved bits) already set
- mPrivateFlags2 &= ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
+ mPrivateFlags2 &=
+ ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
// Set the layout direction flags depending on the value of the attribute
final int layoutDirection = a.getInt(attr, -1);
final int value = (layoutDirection != -1) ?
@@ -5772,6 +5787,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #LAYOUT_DIRECTION_INHERIT} or
* {@link #LAYOUT_DIRECTION_LOCALE}.
* @attr ref android.R.styleable#View_layoutDirection
+ *
+ * @hide
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"),
@@ -5779,7 +5796,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"),
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE")
})
- private int getRawLayoutDirection() {
+ public int getRawLayoutDirection() {
return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
}
@@ -5787,10 +5804,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* Set the layout direction for this view. This will propagate a reset of layout direction
* resolution to the view's children and resolve layout direction for this view.
*
- * @param layoutDirection One of {@link #LAYOUT_DIRECTION_LTR},
- * {@link #LAYOUT_DIRECTION_RTL},
- * {@link #LAYOUT_DIRECTION_INHERIT} or
- * {@link #LAYOUT_DIRECTION_LOCALE}.
+ * @param layoutDirection the layout direction to set. Should be one of:
+ *
+ * {@link #LAYOUT_DIRECTION_LTR},
+ * {@link #LAYOUT_DIRECTION_RTL},
+ * {@link #LAYOUT_DIRECTION_INHERIT},
+ * {@link #LAYOUT_DIRECTION_LOCALE}.
+ *
+ * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution
+ * proceeds up the parent chain of the view to get the value. If there is no parent, then it
+ * will return the default {@link #LAYOUT_DIRECTION_LTR}.
*
* @attr ref android.R.styleable#View_layoutDirection
*/
@@ -5803,11 +5826,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Set the new layout direction (filtered)
mPrivateFlags2 |=
((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK);
- resolveRtlProperties();
- // Notify changes
- onRtlPropertiesChanged();
- // ... and ask for a layout pass
- requestLayout();
+ // We need to resolve all RTL properties as they all depend on layout direction
+ resolveRtlPropertiesIfNeeded();
}
}
@@ -5816,6 +5836,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
* {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
+ *
+ * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version
+ * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"),
@@ -5827,12 +5850,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
return LAYOUT_DIRECTION_LTR;
}
- // The layout direction will be resolved only if needed
- if ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) != PFLAG2_LAYOUT_DIRECTION_RESOLVED) {
- resolveLayoutDirection();
- }
- return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ?
- LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
+ return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
+ PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
}
/**
@@ -11474,10 +11493,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
jumpDrawablesToCurrentState();
- resolveRtlProperties();
- // Notify changes
- onRtlPropertiesChanged();
-
clearAccessibilityFocus();
if (isFocused()) {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -11490,25 +11505,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Resolve all RTL related properties
+ * Resolve all RTL related properties.
*/
- void resolveRtlProperties() {
- // Order is important here: LayoutDirection MUST be resolved first...
- resolveLayoutDirection();
+ void resolveRtlPropertiesIfNeeded() {
+ if (!needRtlPropertiesResolution()) return;
+
+ // Order is important here: LayoutDirection MUST be resolved first
+ if (!isLayoutDirectionResolved()) {
+ resolveLayoutDirection();
+ resolveLayoutParams();
+ }
// ... then we can resolve the others properties depending on the resolved LayoutDirection.
- resolveTextDirection();
- resolveTextAlignment();
- resolvePadding();
- resolveLayoutParams();
- resolveDrawables();
+ if (!isTextDirectionResolved()) {
+ resolveTextDirection();
+ }
+ if (!isTextAlignmentResolved()) {
+ resolveTextAlignment();
+ }
+ if (!isPaddingResolved()) {
+ resolvePadding();
+ }
+ if (!isDrawablesResolved()) {
+ resolveDrawables();
+ }
+ requestLayout();
+ invalidate(true);
+ onRtlPropertiesChanged();
}
- // Reset resolution of all RTL related properties
+ // Reset resolution of all RTL related properties.
void resetRtlProperties() {
resetResolvedLayoutDirection();
resetResolvedTextDirection();
resetResolvedTextAlignment();
resetResolvedPadding();
+ resetResolvedDrawables();
}
/**
@@ -11538,6 +11569,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return true if RTL properties need resolution.
+ */
+ private boolean needRtlPropertiesResolution() {
+ return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED;
+ }
+
+ /**
* Called when any RTL property (layout direction or text direction or text alignment) has
* been changed.
*
@@ -11614,7 +11652,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Reset the resolved layout direction.
+ * Reset the resolved layout direction. Layout direction will be resolved during a call to
+ * {@link #onMeasure(int, int)}.
*
* @hide
*/
@@ -11624,6 +11663,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return true if the layout direction is inherited.
+ *
* @hide
*/
public boolean isLayoutDirectionInherited() {
@@ -11631,12 +11672,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return true if layout direction has been resolved.
+ */
+ private boolean isLayoutDirectionResolved() {
+ return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
+ }
+
+ /**
* Return if padding has been resolved
*
* @hide
*/
boolean isPaddingResolved() {
- return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) != 0;
+ return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED;
}
/**
@@ -14116,6 +14164,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mBackground != null) {
mBackground.setLayoutDirection(getLayoutDirection());
}
+ mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
onResolveDrawables(getLayoutDirection());
}
@@ -14134,6 +14183,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public void onResolveDrawables(int layoutDirection) {
}
+ private void resetResolvedDrawables() {
+ mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED;
+ }
+
+ private boolean isDrawablesResolved() {
+ return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED;
+ }
+
/**
* If your view subclass is displaying its own Drawable objects, it should
* override this function and return true for any Drawable it is
@@ -14403,6 +14460,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
padding = new Rect();
sThreadLocal.set(padding);
}
+ resetResolvedDrawables();
background.setLayoutDirection(getLayoutDirection());
if (background.getPadding(padding)) {
resetResolvedPadding();
@@ -15379,9 +15437,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// first clears the measured dimension flag
mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
- if (!isPaddingResolved()) {
- resolvePadding();
- }
+ resolveRtlPropertiesIfNeeded();
// measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -16526,6 +16582,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
* {@link #TEXT_DIRECTION_LOCALE}
+ *
+ * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
+ * proceeds up the parent chain of the view to get the value. If there is no parent, then it will
+ * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
*/
public void setTextDirection(int textDirection) {
if (getRawTextDirection() != textDirection) {
@@ -16534,6 +16594,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
resetResolvedTextDirection();
// Set the new text direction
mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK);
+ // Do resolution
+ resolveTextDirection();
// Notify change
onRtlPropertiesChanged();
// Refresh
@@ -16545,11 +16607,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Return the resolved text direction.
*
- * This needs resolution if the value is TEXT_DIRECTION_INHERIT. The resolution matches what has
- * been set by {@link #setTextDirection(int)} if it is not TEXT_DIRECTION_INHERIT, otherwise the
- * resolution proceeds up the parent chain of the view. If there is no parent, then it will
- * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}.
- *
* @return the resolved text direction. Returns one of:
*
* {@link #TEXT_DIRECTION_FIRST_STRONG}
@@ -16559,10 +16616,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #TEXT_DIRECTION_LOCALE}
*/
public int getTextDirection() {
- // The text direction will be resolved only if needed
- if ((mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) != PFLAG2_TEXT_DIRECTION_RESOLVED) {
- resolveTextDirection();
- }
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
}
@@ -16601,6 +16654,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
} else {
// We cannot do the resolution if there is no parent, so use the default one
mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
+ // Resolution will need to happen again later
+ return;
}
break;
case TEXT_DIRECTION_FIRST_STRONG:
@@ -16639,16 +16694,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Reset resolved text direction. Text direction can be resolved with a call to
- * getTextDirection().
+ * Reset resolved text direction. Text direction will be resolved during a call to
+ * {@link #onMeasure(int, int)}.
*
* @hide
*/
public void resetResolvedTextDirection() {
+ // Reset any previous text direction resolution
mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
+ // Set to default value
+ mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
}
/**
+ * @return true if text direction is inherited.
+ *
* @hide
*/
public boolean isTextDirectionInherited() {
@@ -16656,6 +16716,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return true if text direction is resolved.
+ */
+ private boolean isTextDirectionResolved() {
+ return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
+ }
+
+ /**
* Return the value specifying the text alignment or policy that was set with
* {@link #setTextAlignment(int)}.
*
@@ -16697,6 +16764,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link #TEXT_ALIGNMENT_VIEW_START},
* {@link #TEXT_ALIGNMENT_VIEW_END}
*
+ * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution
+ * proceeds up the parent chain of the view to get the value. If there is no parent, then it
+ * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}.
+ *
* @attr ref android.R.styleable#View_textAlignment
*/
public void setTextAlignment(int textAlignment) {
@@ -16705,7 +16776,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
resetResolvedTextAlignment();
// Set the new text alignment
- mPrivateFlags2 |= ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
+ mPrivateFlags2 |=
+ ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
+ // Do resolution
+ resolveTextAlignment();
// Notify change
onRtlPropertiesChanged();
// Refresh
@@ -16717,10 +16791,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Return the resolved text alignment.
*
- * The resolved text alignment. This needs resolution if the value is
- * TEXT_ALIGNMENT_INHERIT. The resolution matches {@link #setTextAlignment(int)} if it is
- * not TEXT_ALIGNMENT_INHERIT, otherwise resolution proceeds up the parent chain of the view.
- *
* @return the resolved text alignment. Returns one of:
*
* {@link #TEXT_ALIGNMENT_GRAVITY},
@@ -16740,11 +16810,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
})
public int getTextAlignment() {
- // If text alignment is not resolved, then resolve it
- if ((mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) != PFLAG2_TEXT_ALIGNMENT_RESOLVED) {
- resolveTextAlignment();
- }
- return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+ return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >>
+ PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
}
/**
@@ -16786,6 +16853,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
else {
// We cannot do the resolution if there is no parent so use the default
mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ // Resolution will need to happen again later
+ return;
}
break;
case TEXT_ALIGNMENT_GRAVITY:
@@ -16825,16 +16894,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Reset resolved text alignment.
+ * Reset resolved text alignment. Text alignment will be resolved during a call to
+ * {@link #onMeasure(int, int)}.
*
* @hide
*/
public void resetResolvedTextAlignment() {
// Reset any previous text alignment resolution
mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
+ // Set to default
+ mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
}
/**
+ * @return true if text alignment is inherited.
+ *
* @hide
*/
public boolean isTextAlignmentInherited() {
@@ -16842,6 +16916,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @return true if text alignment is resolved.
+ */
+ private boolean isTextAlignmentResolved() {
+ return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
+ }
+
+ /**
* Generate a value suitable for use in {@link #setId(int)}.
* This value will not collide with ID values generated at build time by aapt for R.id.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 34411ea81de0..41890d6ee3d4 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3391,11 +3391,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
-
- if (child.isLayoutDirectionInherited()) {
- child.resetResolvedLayoutDirection();
- child.resolveRtlProperties();
- }
}
private void addInArray(View child, int index) {
@@ -3621,7 +3616,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
childHasTransientStateChanged(view, false);
}
- view.resetResolvedLayoutDirection();
+ view.resetRtlProperties();
onViewRemoved(view);
@@ -5261,19 +5256,92 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @hide
*/
@Override
+ public void resolveLayoutDirection() {
+ super.resolveLayoutDirection();
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.isLayoutDirectionInherited()) {
+ child.resolveLayoutDirection();
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void resolveTextDirection() {
+ super.resolveTextDirection();
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.isTextDirectionInherited()) {
+ child.resolveTextDirection();
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void resolveTextAlignment() {
+ super.resolveTextAlignment();
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.isTextAlignmentInherited()) {
+ child.resolveTextAlignment();
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
public void resetResolvedLayoutDirection() {
super.resetResolvedLayoutDirection();
- // Take care of resetting the children resolution too
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.isLayoutDirectionInherited()) {
child.resetResolvedLayoutDirection();
}
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void resetResolvedTextDirection() {
+ super.resetResolvedTextDirection();
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
if (child.isTextDirectionInherited()) {
child.resetResolvedTextDirection();
}
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void resetResolvedTextAlignment() {
+ super.resetResolvedTextAlignment();
+
+ int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
if (child.isTextAlignmentInherited()) {
child.resetResolvedTextAlignment();
}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 63a0870307f7..c7da818907d4 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -36,6 +36,10 @@ import java.util.TimeZone;
/**
* This widget display an analogic clock with two hands for hours and
* minutes.
+ *
+ * @attr ref android.R.styleable#AnalogClock_dial
+ * @attr ref android.R.styleable#AnalogClock_hand_hour
+ * @attr ref android.R.styleable#AnalogClock_hand_minute
*/
@RemoteView
public class AnalogClock extends View {
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 87396fbc13d0..7ca83223bee3 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -789,6 +789,7 @@ public class ImageView extends View {
if (resizeWidth) {
int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
pleft + pright;
+ widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
if (newWidth <= widthSize) {
widthSize = newWidth;
done = true;
@@ -799,6 +800,7 @@ public class ImageView extends View {
if (!done && resizeHeight) {
int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
ptop + pbottom;
+ heightSize = resolveAdjustedSize(newHeight, mMaxHeight, heightMeasureSpec);
if (newHeight <= heightSize) {
heightSize = newHeight;
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 90f55bf78797..4b5dfb84d742 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2166,6 +2166,8 @@ public class RemoteViews implements Parcelable, Filter {
* @param value The value to pass to the method.
*/
public void setUri(int viewId, String methodName, Uri value) {
+ // Resolve any filesystem path before sending remotely
+ value = value.getCanonicalUri();
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index bffbe119724c..4ad0819467ed 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -436,9 +436,10 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
if (mBaseResolveList != null) {
mCurrentResolveList = mBaseResolveList;
} else {
- mCurrentResolveList = mPm.queryIntentActivities(
+ mCurrentResolveList = mPm.queryIntentActivitiesAsUser(
mIntent, PackageManager.MATCH_DEFAULT_ONLY
- | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
+ | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0),
+ UserHandle.getUserId(mLaunchedFromUid));
// Filter out any activities that the launched uid does not
// have permission for. We don't do this when we have an explicit
// list of resolved activities, because that only happens when
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0755038e8ffc..9759bdcb0f7c 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5305,6 +5305,19 @@
<attr name="description" />
</declare-styleable>
+ <!-- Use <code>dream</code> as the root tag of the XML resource that
+ describes an
+ {@link android.service.dreams.Dream}, which is
+ referenced from its
+ {@link android.service.dreams.Dream#DREAM_META_DATA}
+ meta-data entry. Described here are the attributes that can be
+ included in that tag. -->
+ <declare-styleable name="Dream">
+ <!-- Component name of an activity that allows the user to modify
+ the settings for this dream. -->
+ <attr name="settingsActivity" />
+ </declare-styleable>
+
<!-- =============================== -->
<!-- Accounts package class attributes -->
<!-- =============================== -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 39e2cf218447..79d928c64b1b 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -219,15 +219,16 @@ public class WifiStressTest
// Stress Wifi reconnection to secure net after sleep
@LargeTest
public void testWifiReconnectionAfterSleep() {
- int value = Settings.System.getInt(mRunner.getContext().getContentResolver(),
- Settings.System.WIFI_SLEEP_POLICY, -1);
- if (value < 0) {
- Settings.System.putInt(mRunner.getContext().getContentResolver(),
- Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
+ int value = Settings.Global.getInt(mRunner.getContext().getContentResolver(),
+ Settings.Global.WIFI_SLEEP_POLICY, -1);
+ log("wifi sleep policy is: " + value);
+ if (value != Settings.Global.WIFI_SLEEP_POLICY_DEFAULT) {
+ Settings.Global.putInt(mRunner.getContext().getContentResolver(),
+ Settings.Global.WIFI_SLEEP_POLICY, Settings.Global.WIFI_SLEEP_POLICY_DEFAULT);
log("set wifi sleep policy to default value");
}
- Settings.Secure.putLong(mRunner.getContext().getContentResolver(),
- Settings.Secure.WIFI_IDLE_MS, WIFI_IDLE_MS);
+ Settings.Global.putLong(mRunner.getContext().getContentResolver(),
+ Settings.Global.WIFI_IDLE_MS, WIFI_IDLE_MS);
// Connect to a Wi-Fi network
WifiConfiguration config = new WifiConfiguration();
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index 485a1bbce407..0583e1215643 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -303,12 +303,12 @@ style="font-weight:500;">App Widgets</span> can resize automatically to fit the
<p>Smart app updates is a new feature of Google Play that introduces a better way of delivering <strong>app updates</strong> to devices. When developers publish an update, Google Play now delivers only the <strong>bits that have changed</strong> to devices, rather than the entire APK. This makes the updates much lighter-weight in most cases, so they are faster to download, save the device’s battery, and conserve bandwidth usage on users’ mobile data plan. On average, a smart app update is about <strong>1/3 the size</strong> of a full APK update.</p>
-<h3 id="gps">Google Play services (coming soon)</h3>
+<h3 id="gps">Google Play services</h3>
<p>Google Play services helps developers to <strong>integrate Google services</strong> such as authentication and Google+ into their apps delivered through Google Play.</p>
-<p>Google Play services will be automatically provisioned to end user devices by Google Play, so all you need is a <strong>thin client library</strong> in your apps.</p>
+<p>Google Play services is automatically provisioned to end user devices by Google Play, so all you need is a <strong>thin client library</strong> in your apps.</p>
<p>Because your app only contains the small client library, you can take advantage of these services without a big increase in download size and storage footprint. Also, Google Play will <strong>deliver regular updates</strong> to the services, without developers needing to publish app updates to take advantage of them.</p>
-<p>For more information about the APIs included in Google Play Services, see the <a href="http://developers.google.com/android/google-play-services/index.html">Google Play Services</a> developer page.</p>
+<p>For more information about the APIs included in Google Play Services, see the <a href="http://developers.google.com/android/google-play-services/index.html">Google Play services</a> developer page.</p>
diff --git a/docs/html/guide/google/play/services.jd b/docs/html/guide/google/play/services.jd
index 519d78b28efd..092642c26d71 100644
--- a/docs/html/guide/google/play/services.jd
+++ b/docs/html/guide/google/play/services.jd
@@ -1,24 +1,25 @@
page.title=Google Play Services
-
@jd:body
-
-<p>Google Play services is a platform that is delivered through the Google Play Store that
+<p>
+ Google Play services is a platform that is delivered through the Google Play Store that
offers integration with Google products, such as Google+, into Android apps.
The Google Play services framework consists of a services component
- that runs on the device and a thin client library that you package with your app. </p>
-
-
+ that runs on the device and a thin client library that you package with your app.
+</p>
<div class="distribute-features col-13">
- <ul>
- <li style="border-top: 1px solid #F80;"><h5>Easy Authentication</h5> Your app can leverage the user's
- existing Google account on the device without having to go through
- tedious authentication flows. A few clicks from the user and you're set!
- <br /> <a href="https://developers.google.com/android/google-play-services">Learn more &raquo;</a>
+<ul>
+ <li style="border-top: 1px solid #F80;"><h5>Easy Authentication</h5>
+ Your app can leverage the user's existing Google account on the device without having to go
+ through tedious authentication flows. A few clicks from the user and you're set!
+ <br/>
+ <a href="https://developers.google.com/android/google-play-services">Learn more &raquo;</a>
</li>
- <li style="border-top: 1px solid #F80;"><h5>Google+ Integration</h5> Google Play services makes it
- easy for your app to integrate with Sign in with Google+, +1 button, and Google+ history.
- <br /> <a href="https://developers.google.com/android/google-play-services">Learn more &raquo;</a>
- </li>
- </ul>
-
-</div> \ No newline at end of file
+ <li style="border-top: 1px solid #F80;"><h5>Google+ Integration</h5>
+ Google Play services makes it easy for your app to integrate with Google+ sign-in and the +1
+ button.
+ <br/>
+ <a href="https://developers.google.com/android/google-play-services">Learn more &raquo;</a>
+ </li>
+</ul>
+
+</div>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 5a4e03ac8db3..7e031d9daaac 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -117,7 +117,7 @@ to modify App Widget settings at create-time.</p>
application's
<code>AndroidManifest.xml</code> file. For example:</p>
-<pre>
+<pre style="clear:right">
&lt;receiver android:name="ExampleAppWidgetProvider" >
&lt;intent-filter>
&lt;action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -815,8 +815,7 @@ href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
sample</a>:</p>
<p>
-<img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView
-Widget" />
+<img src="{@docRoot}resources/images/StackWidget.png" alt="" />
</p>
<p>This sample consists of a stack of 10 views, which display the values
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
index 13c03af7dbe6..65c69c01aafb 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicBlend.java
@@ -36,17 +36,18 @@ public class ScriptIntrinsicBlend extends ScriptIntrinsic {
* @return ScriptIntrinsicBlend
*/
public static ScriptIntrinsicBlend create(RenderScript rs, Element e) {
- int id = rs.nScriptIntrinsicCreate(6, e.getID(rs));
+ // 7 comes from RS_SCRIPT_INTRINSIC_ID_BLEND in rsDefines.h
+ int id = rs.nScriptIntrinsicCreate(7, e.getID(rs));
return new ScriptIntrinsicBlend(id, rs);
}
private void blend(int id, Allocation ain, Allocation aout) {
- if (ain.getElement() != Element.U8_4(mRS)) {
- throw new RSIllegalArgumentException("Input not of expected format.");
+ if (!ain.getElement().isCompatible(Element.U8_4(mRS))) {
+ throw new RSIllegalArgumentException("Input is not of expected format.");
}
- if (aout.getElement() != Element.U8_4(mRS)) {
- throw new RSIllegalArgumentException("Output not of expected format.");
+ if (!aout.getElement().isCompatible(Element.U8_4(mRS))) {
+ throw new RSIllegalArgumentException("Output is not of expected format.");
}
forEach(id, ain, aout, null);
}
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index fb525ee428ac..882e4bbc4bb1 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "Layer.h"
+#include "LayerRenderer.h"
#include "OpenGLRenderer.h"
#include "Caches.h"
@@ -46,14 +47,15 @@ Layer::~Layer() {
if (mesh) delete mesh;
if (meshIndices) delete meshIndices;
if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
- if (fbo) Caches::getInstance().fboCache.put(fbo);
+ removeFbo();
deleteTexture();
}
-void Layer::freeResourcesLocked() {
- if (colorFilter) {
- Caches::getInstance().resourceCache.decrementRefcountLocked(colorFilter);
- colorFilter = NULL;
+void Layer::removeFbo() {
+ if (fbo) {
+ LayerRenderer::flushLayer(this);
+ Caches::getInstance().fboCache.put(fbo);
+ fbo = 0;
}
}
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 9b6205d31f28..69be3178ff9d 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -48,7 +48,7 @@ struct Layer {
Layer(const uint32_t layerWidth, const uint32_t layerHeight);
~Layer();
- void freeResourcesLocked();
+ void removeFbo();
/**
* Sets this layer's region to a rectangle. Computes the appropriate
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 799aea3755a5..f2e7f66ac503 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -299,13 +299,6 @@ void LayerRenderer::destroyLayer(Layer* layer) {
LAYER_RENDERER_LOGD("Recycling layer, %dx%d fbo = %d",
layer->getWidth(), layer->getHeight(), layer->getFbo());
- GLuint fbo = layer->getFbo();
- if (fbo) {
- flushLayer(layer);
- Caches::getInstance().fboCache.put(fbo);
- layer->setFbo(0);
- }
-
if (!Caches::getInstance().layerCache.put(layer)) {
LAYER_RENDERER_LOGD(" Destroyed!");
Caches::getInstance().resourceCache.decrementRefcount(layer);
@@ -314,6 +307,7 @@ void LayerRenderer::destroyLayer(Layer* layer) {
#if DEBUG_LAYER_RENDERER
Caches::getInstance().layerCache.dump();
#endif
+ layer->removeFbo();
layer->region.clear();
}
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 392f8634c08c..acedbcc547c8 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -60,6 +60,8 @@ public:
ANDROID_API static void destroyLayerDeferred(Layer* layer);
ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
+ static void flushLayer(Layer* layer);
+
protected:
virtual bool hasLayer();
virtual Region* getRegion();
@@ -69,8 +71,6 @@ protected:
private:
void generateMesh();
- static void flushLayer(Layer* layer);
-
Layer* mLayer;
}; // class LayerRenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d0d1d93489df..87c3a4723b79 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2729,13 +2729,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
mCaches.activeTexture(0);
if (CC_LIKELY(!layer->region.isEmpty())) {
+ SkiaColorFilter* oldFilter = mColorFilter;
+ mColorFilter = layer->getColorFilter();
+
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
} else if (layer->mesh) {
const float a = layer->getAlpha() / 255.0f;
- SkiaColorFilter *oldFilter = mColorFilter;
- mColorFilter = layer->getColorFilter();
-
setupDraw();
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
@@ -2764,13 +2764,13 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pain
finishDrawTexture();
- mColorFilter = oldFilter;
-
#if DEBUG_LAYERS_AS_REGIONS
drawRegionRects(layer->region);
#endif
}
+ mColorFilter = oldFilter;
+
if (debugLayerUpdate) {
drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
0x7f00ff00, SkXfermode::kSrcOver_Mode);
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 5b1b57d3a664..f0b5553a79a7 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -81,6 +81,7 @@ Program::Program(const ProgramDescription& description, const char* vertex, cons
if (mInitialized) {
transform = addUniform("transform");
+ projection = addUniform("projection");
}
}
@@ -152,18 +153,20 @@ GLuint Program::buildShader(const char* source, GLenum type) {
void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
const mat4& transformMatrix, bool offset) {
- mat4 t(projectionMatrix);
+ mat4 p(projectionMatrix);
if (offset) {
// offset screenspace xy by an amount that compensates for typical precision
// issues in GPU hardware that tends to paint hor/vert lines in pixels shifted
// up and to the left.
// This offset value is based on an assumption that some hardware may use as
// little as 12.4 precision, so we offset by slightly more than 1/16.
- t.translate(.375, .375, 0);
+ p.translate(.375, .375, 0);
}
- t.multiply(transformMatrix);
+
+ mat4 t(transformMatrix);
t.multiply(modelViewMatrix);
+ glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]);
glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
}
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index b1cb44690265..7e3aacf90260 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -374,6 +374,11 @@ public:
*/
int transform;
+ /**
+ * Name of the projection uniform.
+ */
+ int projection;
+
protected:
/**
* Adds an attribute with the specified name.
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 7bc2b376b43b..f536adeff374 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -48,6 +48,7 @@ const char* gVS_Header_Attributes_AAVertexShapeParameters =
const char* gVS_Header_Uniforms_TextureTransform =
"uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
+ "uniform mat4 projection;\n" \
"uniform mat4 transform;\n";
const char* gVS_Header_Uniforms_IsPoint =
"uniform mediump float pointSize;\n";
@@ -104,28 +105,28 @@ const char* gVS_Main_OutTransformedTexCoords =
const char* gVS_Main_OutGradient[6] = {
// Linear
" linear = vec2((screenSpace * position).x, 0.5);\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
" linear = (screenSpace * position).x;\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
// Circular
" circular = (screenSpace * position).xy;\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
" circular = (screenSpace * position).xy;\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
// Sweep
" sweep = (screenSpace * position).xy;\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
" sweep = (screenSpace * position).xy;\n"
- " ditherTexCoords = (gl_Position * ditherSize).xy;\n",
+ " ditherTexCoords = (transform * position).xy * ditherSize;\n",
};
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_OutPointBitmapTexCoords =
" outPointBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_Position =
- " gl_Position = transform * position;\n";
+ " gl_Position = projection * transform * position;\n";
const char* gVS_Main_PointSize =
" gl_PointSize = pointSize;\n";
const char* gVS_Main_AALine =
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 1adf2c77e7c3..03e2172a7aaf 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -38,6 +38,8 @@ struct Texture {
firstFilter = true;
firstWrap = true;
+
+ id = 0;
}
void setWrap(GLenum wrap, bool bindTexture = false, bool force = false,
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 44a0333ed76d..0872f1dcc86c 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -17,6 +17,7 @@
package android.media;
import android.net.Uri;
+import android.os.UserHandle;
/**
* @hide
@@ -28,6 +29,6 @@ interface IRingtonePlayer {
boolean isPlaying(IBinder token);
/** Used for Notification sound playback. */
- void playAsync(in Uri uri, boolean looping, int streamType);
+ void playAsync(in Uri uri, in UserHandle user, boolean looping, int streamType);
void stopAsync();
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 23f7b5566a75..f190eb978423 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -225,8 +225,9 @@ public class Ringtone {
mLocalPlayer.start();
}
} else if (mAllowRemote) {
+ final Uri canonicalUri = mUri.getCanonicalUri();
try {
- mRemotePlayer.play(mRemoteToken, mUri, mStreamType);
+ mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
} catch (RemoteException e) {
Log.w(TAG, "Problem playing ringtone: " + e);
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4d241ed92c9a..a7294ec86589 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
index 89d4ef7444e3..bd872381442c 100644
--- a/packages/SystemUI/src/com/android/systemui/Somnambulator.java
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Intent;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.service.dreams.Dream;
import android.service.dreams.IDreamManager;
import android.util.Slog;
@@ -45,7 +46,7 @@ public class Somnambulator extends Activity {
setResult(RESULT_OK, resultIntent);
} else {
IDreamManager somnambulist = IDreamManager.Stub.asInterface(
- ServiceManager.checkService("dreams"));
+ ServiceManager.checkService(Dream.DREAM_SERVICE));
if (somnambulist != null) {
try {
Slog.v("Somnambulator", "Dreaming by user request.");
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 3502b62b9df8..0c6e59c7c4e9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,6 +17,7 @@
package com.android.systemui.media;
import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.media.Ringtone;
@@ -26,6 +27,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.systemui.SystemUI;
@@ -70,9 +72,10 @@ public class RingtonePlayer extends SystemUI {
private final IBinder mToken;
private final Ringtone mRingtone;
- public Client(IBinder token, Uri uri, int streamType) {
+ public Client(IBinder token, Uri uri, UserHandle user, int streamType) {
mToken = token;
- mRingtone = new Ringtone(mContext, false);
+
+ mRingtone = new Ringtone(getContextForUser(user), false);
mRingtone.setStreamType(streamType);
mRingtone.setUri(uri);
}
@@ -90,12 +93,16 @@ public class RingtonePlayer extends SystemUI {
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
@Override
public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
- if (LOGD) Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ")");
+ if (LOGD) {
+ Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ + Binder.getCallingUid() + ")");
+ }
Client client;
synchronized (mClients) {
client = mClients.get(token);
if (client == null) {
- client = new Client(token, uri, streamType);
+ final UserHandle user = Binder.getCallingUserHandle();
+ client = new Client(token, uri, user, streamType);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
@@ -131,12 +138,13 @@ public class RingtonePlayer extends SystemUI {
}
@Override
- public void playAsync(Uri uri, boolean looping, int streamType) {
- if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ")");
+ public void playAsync(Uri uri, UserHandle user, boolean looping, int streamType) {
+ if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
- mAsyncPlayer.play(mContext, uri, looping, streamType);
+
+ mAsyncPlayer.play(getContextForUser(user), uri, looping, streamType);
}
@Override
@@ -149,6 +157,14 @@ public class RingtonePlayer extends SystemUI {
}
};
+ private Context getContextForUser(UserHandle user) {
+ try {
+ return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Clients:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e6aa632eeb1a..d72632faa874 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -45,6 +45,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.Dream;
import android.service.dreams.IDreamManager;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -262,7 +263,7 @@ public class PhoneStatusBar extends BaseStatusBar {
.getDefaultDisplay();
mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService("dreams"));
+ ServiceManager.checkService(Dream.DREAM_SERVICE));
super.start(); // calls createAndAddWindows()
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 8ad5a919cdd9..4a8bf720aae1 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,9 +16,6 @@
package com.android.server;
-import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
-import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
-
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -27,16 +24,12 @@ import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.dreams.IDreamManager;
import android.util.Log;
import android.util.Slog;
@@ -48,14 +41,10 @@ import java.io.FileReader;
*/
final class DockObserver extends UEventObserver {
private static final String TAG = DockObserver.class.getSimpleName();
- private static final boolean LOG = false;
private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock";
private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state";
- private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
- private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
private static final int MSG_DOCK_STATE_CHANGED = 0;
private final Object mLock = new Object();
@@ -66,11 +55,16 @@ final class DockObserver extends UEventObserver {
private boolean mSystemReady;
private final Context mContext;
+ private final PowerManager mPowerManager;
+ private final PowerManager.WakeLock mWakeLock;
public DockObserver(Context context) {
mContext = context;
- init(); // set initial status
+ mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ init(); // set initial status
startObserving(DOCK_UEVENT_MATCH);
}
@@ -87,17 +81,9 @@ final class DockObserver extends UEventObserver {
mPreviousDockState = mDockState;
mDockState = newState;
if (mSystemReady) {
- // Don't force screen on when undocking from the desk dock.
- // The change in power state will do this anyway.
- // FIXME - we should be configurable.
- if ((mPreviousDockState != Intent.EXTRA_DOCK_STATE_DESK
- && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
- && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
- mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
- PowerManager pm =
- (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- pm.wakeUp(SystemClock.uptimeMillis());
- }
+ // Wake up immediately when docked or undocked.
+ mPowerManager.wakeUp(SystemClock.uptimeMillis());
+
updateLocked();
}
}
@@ -138,6 +124,7 @@ final class DockObserver extends UEventObserver {
}
private void updateLocked() {
+ mWakeLock.acquire();
mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
}
@@ -145,8 +132,8 @@ final class DockObserver extends UEventObserver {
synchronized (mLock) {
Slog.i(TAG, "Dock state changed: " + mDockState);
+ // Skip the dock intent if not yet provisioned.
final ContentResolver cr = mContext.getContentResolver();
-
if (Settings.Global.getInt(cr,
Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
@@ -158,16 +145,8 @@ final class DockObserver extends UEventObserver {
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
- // Check if this is Bluetooth Dock
- // TODO(BT): Get Dock address.
- // String address = null;
- // if (address != null) {
- // intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
- // BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
- // }
-
- // User feedback to confirm dock connection. Particularly
- // useful for flaky contact pins...
+ // Play a sound to provide feedback to confirm dock connection.
+ // Particularly useful for flaky contact pins...
if (Settings.Global.getInt(cr,
Settings.Global.DOCK_SOUNDS_ENABLED, 1) == 1) {
String whichSound = null;
@@ -204,42 +183,14 @@ final class DockObserver extends UEventObserver {
}
}
- IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
- if (mgr != null) {
- // dreams feature enabled
- boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
- if (undocked) {
- try {
- if (mgr.isDreaming()) {
- mgr.awaken();
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to awaken!", e);
- }
- } else {
- if (isScreenSaverEnabled(mContext) && isScreenSaverActivatedOnDock(mContext)) {
- try {
- mgr.dream();
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to dream!", e);
- }
- }
- }
- } else {
- // dreams feature not enabled, send legacy intent
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
- }
- }
+ // Send the dock event intent.
+ // There are many components in the system watching for this so as to
+ // adjust audio routing, screen orientation, etc.
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- private static boolean isScreenSaverEnabled(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED) != 0;
- }
-
- private static boolean isScreenSaverActivatedOnDock(Context context) {
- return Settings.Secure.getInt(context.getContentResolver(),
- SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK) != 0;
+ // Release the wake lock that was acquired when the message was posted.
+ mWakeLock.release();
+ }
}
private final Handler mHandler = new Handler(true /*async*/) {
diff --git a/services/java/com/android/server/DreamController.java b/services/java/com/android/server/DreamController.java
deleted file mode 100644
index 498e581b1854..000000000000
--- a/services/java/com/android/server/DreamController.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.IBinder.DeathRecipient;
-import android.service.dreams.IDreamService;
-import android.util.Slog;
-import android.view.IWindowManager;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-import com.android.internal.util.DumpUtils;
-
-import java.io.PrintWriter;
-import java.util.NoSuchElementException;
-
-/**
- * Internal controller for starting and stopping the current dream and managing related state.
- *
- * Assumes all operations (except {@link #dump}) are called from a single thread.
- */
-final class DreamController {
- private static final boolean DEBUG = true;
- private static final String TAG = DreamController.class.getSimpleName();
-
- public interface Listener {
- void onDreamStopped(boolean wasTest);
- }
-
- private final Context mContext;
- private final IWindowManager mIWindowManager;
- private final DeathRecipient mDeathRecipient;
- private final ServiceConnection mServiceConnection;
- private final Listener mListener;
-
- private Handler mHandler;
-
- private ComponentName mCurrentDreamComponent;
- private IDreamService mCurrentDream;
- private Binder mCurrentDreamToken;
- private boolean mCurrentDreamIsTest;
-
- public DreamController(Context context, DeathRecipient deathRecipient,
- ServiceConnection serviceConnection, Listener listener) {
- mContext = context;
- mDeathRecipient = deathRecipient;
- mServiceConnection = serviceConnection;
- mListener = listener;
- mIWindowManager = WindowManagerGlobal.getWindowManagerService();
- }
-
- public void setHandler(Handler handler) {
- mHandler = handler;
- }
-
- public void dump(PrintWriter pw) {
- if (mHandler== null || pw == null) {
- return;
- }
- DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
- @Override
- public void dump(PrintWriter pw) {
- pw.print(" component="); pw.println(mCurrentDreamComponent);
- pw.print(" token="); pw.println(mCurrentDreamToken);
- pw.print(" dream="); pw.println(mCurrentDream);
- }
- }, pw, 200);
- }
-
- public void start(ComponentName dream, boolean isTest) {
- if (DEBUG) Slog.v(TAG, String.format("start(%s,%s)", dream, isTest));
-
- if (mCurrentDreamComponent != null ) {
- if (dream.equals(mCurrentDreamComponent) && isTest == mCurrentDreamIsTest) {
- if (DEBUG) Slog.v(TAG, "Dream is already started: " + dream);
- return;
- }
- // stop the current dream before starting a new one
- stop();
- }
-
- mCurrentDreamComponent = dream;
- mCurrentDreamIsTest = isTest;
- mCurrentDreamToken = new Binder();
-
- try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurrentDreamToken
- + " for window type: " + WindowManager.LayoutParams.TYPE_DREAM);
- mIWindowManager.addWindowToken(mCurrentDreamToken,
- WindowManager.LayoutParams.TYPE_DREAM);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to add window token.");
- stop();
- return;
- }
-
- Intent intent = new Intent(Intent.ACTION_MAIN)
- .setComponent(mCurrentDreamComponent)
- .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
- .putExtra("android.dreams.TEST", mCurrentDreamIsTest);
-
- if (!mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)) {
- Slog.w(TAG, "Unable to bind service");
- stop();
- return;
- }
- if (DEBUG) Slog.v(TAG, "Bound service");
- }
-
- public void attach(ComponentName name, IBinder dream) {
- if (DEBUG) Slog.v(TAG, String.format("attach(%s,%s)", name, dream));
- mCurrentDream = IDreamService.Stub.asInterface(dream);
-
- boolean linked = linkDeathRecipient(dream);
- if (!linked) {
- stop();
- return;
- }
-
- try {
- if (DEBUG) Slog.v(TAG, "Attaching with token:" + mCurrentDreamToken);
- mCurrentDream.attach(mCurrentDreamToken);
- } catch (Throwable ex) {
- Slog.w(TAG, "Unable to send window token to dream:" + ex);
- stop();
- }
- }
-
- public void stop() {
- if (DEBUG) Slog.v(TAG, "stop()");
-
- if (mCurrentDream != null) {
- unlinkDeathRecipient(mCurrentDream.asBinder());
-
- if (DEBUG) Slog.v(TAG, "Unbinding: " + mCurrentDreamComponent + " service: " + mCurrentDream);
- mContext.unbindService(mServiceConnection);
- }
- if (mCurrentDreamToken != null) {
- removeWindowToken(mCurrentDreamToken);
- }
-
- final boolean wasTest = mCurrentDreamIsTest;
- mCurrentDream = null;
- mCurrentDreamToken = null;
- mCurrentDreamComponent = null;
- mCurrentDreamIsTest = false;
-
- if (mListener != null && mHandler != null) {
- mHandler.post(new Runnable(){
- @Override
- public void run() {
- mListener.onDreamStopped(wasTest);
- }});
- }
- }
-
- public void stopSelf(IBinder token) {
- if (DEBUG) Slog.v(TAG, String.format("stopSelf(%s)", token));
- if (token == null || token != mCurrentDreamToken) {
- Slog.w(TAG, "Stop requested for non-current dream token: " + token);
- } else {
- stop();
- }
- }
-
- private void removeWindowToken(IBinder token) {
- if (DEBUG) Slog.v(TAG, "Removing window token: " + token);
- try {
- mIWindowManager.removeWindowToken(token);
- } catch (Throwable e) {
- Slog.w(TAG, "Error removing window token", e);
- }
- }
-
- private boolean linkDeathRecipient(IBinder dream) {
- if (DEBUG) Slog.v(TAG, "Linking death recipient");
- try {
- dream.linkToDeath(mDeathRecipient, 0);
- return true;
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to link death recipient", e);
- return false;
- }
- }
-
- private void unlinkDeathRecipient(IBinder dream) {
- if (DEBUG) Slog.v(TAG, "Unlinking death recipient");
- try {
- dream.unlinkToDeath(mDeathRecipient, 0);
- } catch (NoSuchElementException e) {
- // we tried
- }
- }
-
-} \ No newline at end of file
diff --git a/services/java/com/android/server/DreamManagerService.java b/services/java/com/android/server/DreamManagerService.java
deleted file mode 100644
index b02ea7f768fd..000000000000
--- a/services/java/com/android/server/DreamManagerService.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.provider.Settings.Secure.SCREENSAVER_COMPONENTS;
-import static android.provider.Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT;
-
-import android.app.ActivityManagerNative;
-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.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.Dream;
-import android.service.dreams.IDreamManager;
-import android.util.Slog;
-import android.util.SparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Service api for managing dreams.
- *
- * @hide
- */
-public final class DreamManagerService
- extends IDreamManager.Stub
- implements ServiceConnection {
- private static final boolean DEBUG = true;
- private static final String TAG = DreamManagerService.class.getSimpleName();
-
- private static final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- private static final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-
- private final Object mLock = new Object();
- private final DreamController mController;
- private final DreamControllerHandler mHandler;
- private final Context mContext;
-
- private final CurrentUserManager mCurrentUserManager = new CurrentUserManager();
-
- private final DeathRecipient mAwakenOnBinderDeath = new DeathRecipient() {
- @Override
- public void binderDied() {
- if (DEBUG) Slog.v(TAG, "binderDied()");
- awaken();
- }
- };
-
- private final DreamController.Listener mControllerListener = new DreamController.Listener() {
- @Override
- public void onDreamStopped(boolean wasTest) {
- synchronized(mLock) {
- setDreamingLocked(false, wasTest);
- }
- }};
-
- private boolean mIsDreaming;
-
- public DreamManagerService(Context context) {
- if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
- mContext = context;
- mController = new DreamController(context, mAwakenOnBinderDeath, this, mControllerListener);
- mHandler = new DreamControllerHandler(mController);
- mController.setHandler(mHandler);
- }
-
- public void systemReady() {
- mCurrentUserManager.init(mContext);
-
- if (DEBUG) Slog.v(TAG, "Ready to dream!");
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- pw.println("Dreamland:");
- mController.dump(pw);
- mCurrentUserManager.dump(pw);
- }
-
- // begin IDreamManager api
- @Override
- public ComponentName[] getDreamComponents() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
- int userId = UserHandle.getCallingUserId();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- return getDreamComponentsForUser(userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void setDreamComponents(ComponentName[] componentNames) {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
- int userId = UserHandle.getCallingUserId();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- componentsToString(componentNames),
- userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public ComponentName getDefaultDreamComponent() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
- int userId = UserHandle.getCallingUserId();
-
- final long ident = Binder.clearCallingIdentity();
- try {
- String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_DEFAULT_COMPONENT,
- userId);
- return name == null ? null : ComponentName.unflattenFromString(name);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- }
-
- @Override
- public boolean isDreaming() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
- return mIsDreaming;
- }
-
- @Override
- public void dream() {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG) Slog.v(TAG, "Dream now");
- ComponentName[] dreams = getDreamComponentsForUser(mCurrentUserManager.getCurrentUserId());
- ComponentName firstDream = dreams != null && dreams.length > 0 ? dreams[0] : null;
- if (firstDream != null) {
- mHandler.requestStart(firstDream, false /*isTest*/);
- synchronized (mLock) {
- setDreamingLocked(true, false /*isTest*/);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void testDream(ComponentName dream) {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG) Slog.v(TAG, "Test dream name=" + dream);
- if (dream != null) {
- mHandler.requestStart(dream, true /*isTest*/);
- synchronized (mLock) {
- setDreamingLocked(true, true /*isTest*/);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- }
-
- @Override
- public void awaken() {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG) Slog.v(TAG, "Wake up");
- mHandler.requestStop();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void awakenSelf(IBinder token) {
- // requires no permission, called by Dream from an arbitrary process
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG) Slog.v(TAG, "Wake up from dream: " + token);
- if (token != null) {
- mHandler.requestStopSelf(token);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- // end IDreamManager api
-
- // begin ServiceConnection
- @Override
- public void onServiceConnected(ComponentName name, IBinder dream) {
- if (DEBUG) Slog.v(TAG, "Service connected: " + name + " binder=" +
- dream + " thread=" + Thread.currentThread().getId());
- mHandler.requestAttach(name, dream);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "Service disconnected: " + name);
- // Only happens in exceptional circumstances, awaken just to be safe
- awaken();
- }
- // end ServiceConnection
-
- private void checkPermission(String permission) {
- if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(permission)) {
- throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
- + ", must have permission " + permission);
- }
- }
-
- private void setDreamingLocked(boolean isDreaming, boolean isTest) {
- boolean wasDreaming = mIsDreaming;
- if (!isTest) {
- if (!wasDreaming && isDreaming) {
- if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STARTED");
- mContext.sendBroadcast(mDreamingStartedIntent);
- } else if (wasDreaming && !isDreaming) {
- if (DEBUG) Slog.v(TAG, "Firing ACTION_DREAMING_STOPPED");
- mContext.sendBroadcast(mDreamingStoppedIntent);
- }
- }
- mIsDreaming = isDreaming;
- }
-
- private ComponentName[] getDreamComponentsForUser(int userId) {
- String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- SCREENSAVER_COMPONENTS,
- userId);
- return names == null ? null : componentsFromString(names);
- }
-
- private static String componentsToString(ComponentName[] componentNames) {
- StringBuilder names = new StringBuilder();
- if (componentNames != null) {
- for (ComponentName componentName : componentNames) {
- if (names.length() > 0) {
- names.append(',');
- }
- names.append(componentName.flattenToString());
- }
- }
- return names.toString();
- }
-
- private static ComponentName[] componentsFromString(String names) {
- String[] namesArray = names.split(",");
- ComponentName[] componentNames = new ComponentName[namesArray.length];
- for (int i = 0; i < namesArray.length; i++) {
- componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
- }
- return componentNames;
- }
-
- /**
- * Keeps track of the current user, since dream() uses the current user's configuration.
- */
- private static class CurrentUserManager {
- private final Object mLock = new Object();
- private int mCurrentUserId;
-
- public void init(Context context) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- synchronized(mLock) {
- mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (DEBUG) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
- }
- }
- }}, filter);
- try {
- synchronized (mLock) {
- mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.print(" user="); pw.println(getCurrentUserId());
- }
-
- public int getCurrentUserId() {
- synchronized(mLock) {
- return mCurrentUserId;
- }
- }
- }
-
- /**
- * Handler for asynchronous operations performed by the dream manager.
- *
- * Ensures operations to {@link DreamController} are single-threaded.
- */
- private static final class DreamControllerHandler extends Handler {
- private final DreamController mController;
- private final Runnable mStopRunnable = new Runnable() {
- @Override
- public void run() {
- mController.stop();
- }};
-
- public DreamControllerHandler(DreamController controller) {
- super(true /*async*/);
- mController = controller;
- }
-
- public void requestStart(final ComponentName name, final boolean isTest) {
- post(new Runnable(){
- @Override
- public void run() {
- mController.start(name, isTest);
- }});
- }
-
- public void requestAttach(final ComponentName name, final IBinder dream) {
- post(new Runnable(){
- @Override
- public void run() {
- mController.attach(name, dream);
- }});
- }
-
- public void requestStopSelf(final IBinder token) {
- post(new Runnable(){
- @Override
- public void run() {
- mController.stopSelf(token);
- }});
- }
-
- public void requestStop() {
- post(mStopRunnable);
- }
-
- }
-
-}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 76194ae79be5..5d5f8d37d222 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -890,6 +890,7 @@ public class NotificationManagerService extends INotificationManager.Stub
userId = ActivityManager.handleIncomingUser(callingPid,
callingUid, userId, true, true, "enqueueNotification", pkg);
+ final UserHandle user = new UserHandle(userId);
// Limit the number of notifications that any given package except the android
// package can enqueue. Prevents DOS attacks and deals with leaks.
@@ -991,7 +992,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (notification.icon != 0) {
- final UserHandle user = new UserHandle(userId);
final StatusBarNotification n = new StatusBarNotification(
pkg, id, tag, r.uid, r.initialPid, score, notification, user);
if (old != null && old.statusBarKey != null) {
@@ -1063,7 +1063,7 @@ public class NotificationManagerService extends INotificationManager.Stub
try {
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
if (player != null) {
- player.playAsync(uri, looping, audioStreamType);
+ player.playAsync(uri, user, looping, audioStreamType);
}
} catch (RemoteException e) {
} finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eeab757b5e75..738e19b1f267 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@ import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.server.search.SearchManagerService;
+import android.service.dreams.Dream;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -51,6 +52,7 @@ import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.DisplayManagerService;
+import com.android.server.dreams.DreamManagerService;
import com.android.server.input.InputManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -738,8 +740,8 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "Dreams Service");
// Dreams (interactive idle-time views, a/k/a screen savers)
- dreamy = new DreamManagerService(context);
- ServiceManager.addService("dreams", dreamy);
+ dreamy = new DreamManagerService(context, wmHandler);
+ ServiceManager.addService(Dream.DREAM_SERVICE, dreamy);
} catch (Throwable e) {
reportWtf("starting DreamManagerService", e);
}
@@ -810,7 +812,7 @@ class ServerThread extends Thread {
context.getResources().updateConfiguration(config, metrics);
try {
- power.systemReady(twilight);
+ power.systemReady(twilight, dreamy);
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 85a6e4150f29..07e8f182ed70 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IUiModeManager;
import android.app.Notification;
@@ -39,6 +40,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamManager;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -56,6 +59,9 @@ class UiModeManagerService extends IUiModeManager.Stub {
private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
+ private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
+ private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
+
private final Context mContext;
private final TwilightService mTwilightService;
private final Handler mHandler = new Handler();
@@ -110,72 +116,10 @@ class UiModeManagerService extends IUiModeManager.Stub {
return;
}
- final int enableFlags = intent.getIntExtra("enableFlags", 0);
- final int disableFlags = intent.getIntExtra("disableFlags", 0);
-
+ final int enableFlags = intent.getIntExtra("enableFlags", 0);
+ final int disableFlags = intent.getIntExtra("disableFlags", 0);
synchronized (mLock) {
- // Launch a dock activity
- String category = null;
- if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
- // Only launch car home when car mode is enabled and the caller
- // has asked us to switch to it.
- if (ENABLE_LAUNCH_CAR_DOCK_APP
- && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
- category = Intent.CATEGORY_CAR_DOCK;
- }
- } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
- // Only launch car home when desk mode is enabled and the caller
- // has asked us to switch to it. Currently re-using the car
- // mode flag since we don't have a formal API for "desk mode".
- if (ENABLE_LAUNCH_DESK_DOCK_APP
- && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
- category = Intent.CATEGORY_DESK_DOCK;
- }
- } else {
- // Launch the standard home app if requested.
- if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
- category = Intent.CATEGORY_HOME;
- }
- }
-
- if (LOG) {
- Slog.v(TAG, String.format(
- "Handling broadcast result for action %s: enable=0x%08x disable=0x%08x category=%s",
- intent.getAction(), enableFlags, disableFlags, category));
- }
-
- if (category != null) {
- // This is the new activity that will serve as home while
- // we are in care mode.
- Intent homeIntent = buildHomeIntent(category);
-
- // Now we are going to be careful about switching the
- // configuration and starting the activity -- we need to
- // do this in a specific order under control of the
- // activity manager, to do it cleanly. So compute the
- // new config, but don't set it yet, and let the
- // activity manager take care of both the start and config
- // change.
- Configuration newConfig = null;
- if (mHoldingConfiguration) {
- mHoldingConfiguration = false;
- updateConfigurationLocked(false);
- newConfig = mConfiguration;
- }
- try {
- ActivityManagerNative.getDefault().startActivityWithConfig(
- null, homeIntent, null, null, null, 0, 0,
- newConfig, null, UserHandle.USER_CURRENT);
- mHoldingConfiguration = false;
- } catch (RemoteException e) {
- Slog.w(TAG, e.getCause());
- }
- }
-
- if (mHoldingConfiguration) {
- mHoldingConfiguration = false;
- updateConfigurationLocked(true);
- }
+ updateAfterBroadcastLocked(intent.getAction(), enableFlags, disableFlags);
}
}
};
@@ -335,9 +279,8 @@ class UiModeManagerService extends IUiModeManager.Stub {
}
}
- final void updateConfigurationLocked(boolean sendIt) {
- int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION
- : mDefaultUiModeType;
+ final void updateConfigurationLocked() {
+ int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType;
if (mCarModeEnabled) {
uiMode = Configuration.UI_MODE_TYPE_CAR;
} else if (isDeskDockState(mDockState)) {
@@ -365,17 +308,19 @@ class UiModeManagerService extends IUiModeManager.Stub {
}
mCurUiMode = uiMode;
-
- if (!mHoldingConfiguration && uiMode != mSetUiMode) {
- mSetUiMode = uiMode;
+ if (!mHoldingConfiguration) {
mConfiguration.uiMode = uiMode;
+ }
+ }
- if (sendIt) {
- try {
- ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure communicating with activity manager", e);
- }
+ final void sendConfigurationLocked() {
+ if (mSetUiMode != mConfiguration.uiMode) {
+ mSetUiMode = mConfiguration.uiMode;
+
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(mConfiguration);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure communicating with activity manager", e);
}
}
}
@@ -434,43 +379,38 @@ class UiModeManagerService extends IUiModeManager.Stub {
intent.putExtra("disableFlags", disableFlags);
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
mResultReceiver, null, Activity.RESULT_OK, null, null);
+
// Attempting to make this transition a little more clean, we are going
// to hold off on doing a configuration change until we have finished
// the broadcast and started the home activity.
mHoldingConfiguration = true;
+ updateConfigurationLocked();
} else {
- Intent homeIntent = null;
+ String category = null;
if (mCarModeEnabled) {
if (ENABLE_LAUNCH_CAR_DOCK_APP
- && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
- homeIntent = buildHomeIntent(Intent.CATEGORY_CAR_DOCK);
+ && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_CAR_DOCK;
}
} else if (isDeskDockState(mDockState)) {
if (ENABLE_LAUNCH_DESK_DOCK_APP
- && (enableFlags&UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
- homeIntent = buildHomeIntent(Intent.CATEGORY_DESK_DOCK);
+ && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_DESK_DOCK;
}
} else {
- if ((disableFlags&UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
- homeIntent = buildHomeIntent(Intent.CATEGORY_HOME);
+ if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ category = Intent.CATEGORY_HOME;
}
}
if (LOG) {
Slog.v(TAG, "updateLocked: null action, mDockState="
- + mDockState +", firing homeIntent: " + homeIntent);
+ + mDockState +", category=" + category);
}
- if (homeIntent != null) {
- try {
- mContext.startActivityAsUser(homeIntent, UserHandle.CURRENT);
- } catch (ActivityNotFoundException e) {
- }
- }
+ sendConfigurationAndStartDreamOrDockAppLocked(category);
}
- updateConfigurationLocked(true);
-
// keep screen on when charging and in car mode
boolean keepScreenOn = mCharging &&
((mCarModeEnabled && mCarModeKeepsScreenOn) ||
@@ -487,6 +427,100 @@ class UiModeManagerService extends IUiModeManager.Stub {
}
}
+ private void updateAfterBroadcastLocked(String action, int enableFlags, int disableFlags) {
+ // Launch a dock activity
+ String category = null;
+ if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(action)) {
+ // Only launch car home when car mode is enabled and the caller
+ // has asked us to switch to it.
+ if (ENABLE_LAUNCH_CAR_DOCK_APP
+ && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_CAR_DOCK;
+ }
+ } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(action)) {
+ // Only launch car home when desk mode is enabled and the caller
+ // has asked us to switch to it. Currently re-using the car
+ // mode flag since we don't have a formal API for "desk mode".
+ if (ENABLE_LAUNCH_DESK_DOCK_APP
+ && (enableFlags & UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME) != 0) {
+ category = Intent.CATEGORY_DESK_DOCK;
+ }
+ } else {
+ // Launch the standard home app if requested.
+ if ((disableFlags & UiModeManager.DISABLE_CAR_MODE_GO_HOME) != 0) {
+ category = Intent.CATEGORY_HOME;
+ }
+ }
+
+ if (LOG) {
+ Slog.v(TAG, String.format(
+ "Handling broadcast result for action %s: enable=0x%08x, disable=0x%08x, "
+ + "category=%s",
+ action, enableFlags, disableFlags, category));
+ }
+
+ sendConfigurationAndStartDreamOrDockAppLocked(category);
+ }
+
+ private void sendConfigurationAndStartDreamOrDockAppLocked(String category) {
+ // Update the configuration but don't send it yet.
+ mHoldingConfiguration = false;
+ updateConfigurationLocked();
+
+ // Start the dock app, if there is one.
+ boolean dockAppStarted = false;
+ if (category != null) {
+ // Now we are going to be careful about switching the
+ // configuration and starting the activity -- we need to
+ // do this in a specific order under control of the
+ // activity manager, to do it cleanly. So compute the
+ // new config, but don't set it yet, and let the
+ // activity manager take care of both the start and config
+ // change.
+ Intent homeIntent = buildHomeIntent(category);
+ try {
+ int result = ActivityManagerNative.getDefault().startActivityWithConfig(
+ null, homeIntent, null, null, null, 0, 0,
+ mConfiguration, null, UserHandle.USER_CURRENT);
+ if (result >= ActivityManager.START_SUCCESS) {
+ dockAppStarted = true;
+ } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
+ Slog.e(TAG, "Could not start dock app: " + homeIntent
+ + ", startActivityWithConfig result " + result);
+ }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Could not start dock app: " + homeIntent, ex);
+ }
+ }
+
+ // Send the new configuration.
+ sendConfigurationLocked();
+
+ // If we did not start a dock app, then start dreaming if supported.
+ if (!dockAppStarted && isScreenSaverEnabled() && isScreenSaverActivatedOnDock()) {
+ Slog.i(TAG, "Activating dream while docked.");
+ try {
+ IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
+ ServiceManager.getService(Dream.DREAM_SERVICE));
+ dreamManagerService.dream();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Could not start dream when docked.", ex);
+ }
+ }
+ }
+
+ private boolean isScreenSaverEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+ UserHandle.USER_CURRENT) != 0;
+ }
+
+ private boolean isScreenSaverActivatedOnDock() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+ DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+ }
+
private void adjustStatusBarCarModeLocked() {
if (mStatusBarManager == null) {
mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 0c0f00c44126..1269433d0a6f 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -44,7 +44,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.Message;
@@ -391,7 +390,7 @@ public class ActiveServices {
if (r.isForeground) {
r.isForeground = false;
if (r.app != null) {
- mAm.updateLruProcessLocked(r.app, false, true);
+ mAm.updateLruProcessLocked(r.app, false);
updateServiceForegroundLocked(r.app, true);
}
}
@@ -760,7 +759,8 @@ public class ActiveServices {
int N = mPendingServices.size();
for (int i=0; i<N; i++) {
ServiceRecord pr = mPendingServices.get(i);
- if (pr.name.equals(name)) {
+ if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
+ && pr.name.equals(name)) {
mPendingServices.remove(i);
i--;
N--;
@@ -942,7 +942,7 @@ public class ActiveServices {
Slog.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
- r.shortName, r.restartDelay);
+ r.userId, r.shortName, r.restartDelay);
return canceled;
}
@@ -1083,14 +1083,14 @@ public class ActiveServices {
app.services.add(r);
bumpServiceExecutingLocked(r, "create");
- mAm.updateLruProcessLocked(app, true, true);
+ mAm.updateLruProcessLocked(app, true);
boolean created = false;
try {
mAm.mStringBuilder.setLength(0);
r.intent.getIntent().toShortString(mAm.mStringBuilder, true, false, true, false);
EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
- System.identityHashCode(r), r.shortName,
+ r.userId, System.identityHashCode(r), r.shortName,
mAm.mStringBuilder.toString(), r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
@@ -1240,7 +1240,7 @@ public class ActiveServices {
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing down " + r + " " + r.intent);
EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
- System.identityHashCode(r), r.shortName,
+ r.userId, System.identityHashCode(r), r.shortName,
(r.app != null) ? r.app.pid : -1);
mServiceMap.removeServiceByName(r.name, r.userId);
@@ -1664,7 +1664,7 @@ public class ActiveServices {
Slog.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
- sr.crashCount, sr.shortName, app.pid);
+ sr.userId, sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr, true);
} else if (!allowRestart) {
bringDownServiceLocked(sr, true);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b266bd4df121..370d4270fb15 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1369,7 +1369,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (mSelf.mPidsSelfLocked) {
mSelf.mPidsSelfLocked.put(app.pid, app);
}
- mSelf.updateLruProcessLocked(app, true, true);
+ mSelf.updateLruProcessLocked(app, true);
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
@@ -1805,8 +1805,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private final void updateLruProcessInternalLocked(ProcessRecord app,
- boolean updateActivityTime, int bestPos) {
+ private final void updateLruProcessInternalLocked(ProcessRecord app, int bestPos) {
// put it on the LRU to keep track of when it should be exited.
int lrui = mLruProcesses.indexOf(app);
if (lrui >= 0) mLruProcesses.remove(lrui);
@@ -1817,9 +1816,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.lruSeq = mLruSeq;
// compute the new weight for this process.
- if (updateActivityTime) {
- app.lastActivityTime = SystemClock.uptimeMillis();
- }
+ app.lastActivityTime = SystemClock.uptimeMillis();
if (app.activities.size() > 0) {
// If this process has activities, we more strongly want to keep
// it around.
@@ -1863,24 +1860,22 @@ public final class ActivityManagerService extends ActivityManagerNative
if (cr.binding != null && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app,
- updateActivityTime, i+1);
+ updateLruProcessInternalLocked(cr.binding.service.app, i+1);
}
}
}
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc,
- updateActivityTime, i+1);
+ updateLruProcessInternalLocked(cpr.proc, i+1);
}
}
}
final void updateLruProcessLocked(ProcessRecord app,
- boolean oomAdj, boolean updateActivityTime) {
+ boolean oomAdj) {
mLruSeq++;
- updateLruProcessInternalLocked(app, updateActivityTime, 0);
+ updateLruProcessInternalLocked(app, 0);
//Slog.i(TAG, "Putting proc to front: " + app.processName);
if (oomAdj) {
@@ -1981,7 +1976,8 @@ public final class ActivityManagerService extends ActivityManagerNative
+ "/" + info.processName);
mProcessCrashTimes.remove(info.processName, info.uid);
if (mBadProcesses.get(info.processName, info.uid) != null) {
- EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
+ UserHandle.getUserId(info.uid), info.uid,
info.processName);
mBadProcesses.remove(info.processName, info.uid);
if (app != null) {
@@ -2129,7 +2125,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- EventLog.writeEvent(EventLogTags.AM_PROC_START, startResult.pid, uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_START,
+ UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
@@ -2946,7 +2943,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!r.finishing) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
- System.identityHashCode(r),
+ r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName,
"proc died without state saved");
}
@@ -3037,7 +3034,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died.");
}
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
if (localLOGV) Slog.v(
TAG, "Dying app: " + app + ", pid: " + pid
+ ", thread: " + thread.asBinder());
@@ -3086,7 +3083,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// A new process has already been started.
Slog.i(TAG, "Process " + app.processName + " (pid " + pid
+ ") has died and restarted (pid " + app.pid + ").");
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
} else if (DEBUG_PROCESSES) {
Slog.d(TAG, "Received spurious death notification for thread "
+ thread.asBinder());
@@ -3321,8 +3318,8 @@ public final class ActivityManagerService extends ActivityManagerNative
app.notResponding = true;
// Log the ANR to the event log.
- EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
- annotation);
+ EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
+ app.processName, app.info.flags, annotation);
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(app.pid);
@@ -3408,7 +3405,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
Slog.w(TAG, "Killing " + app + ": background ANR");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "background ANR");
Process.killProcessQuiet(app.pid);
return;
@@ -4077,8 +4074,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
- EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.uid,
- app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
+ pid, app.uid, app.processName);
mProcessNames.remove(app.processName, app.uid);
mIsolatedProcesses.remove(app.uid);
if (mHeavyWeightProcess == app) {
@@ -4090,7 +4087,7 @@ public final class ActivityManagerService extends ActivityManagerNative
checkAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
- EventLog.writeEvent(EventLogTags.AM_KILL, pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, pid,
app.processName, app.setAdj, "start timeout");
Process.killProcessQuiet(pid);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
@@ -4166,7 +4163,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
+ EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
app.thread = thread;
app.curAdj = app.setAdj = -100;
@@ -4244,7 +4241,7 @@ public final class ActivityManagerService extends ActivityManagerNative
enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
- updateLruProcessLocked(app, false, true);
+ updateLruProcessLocked(app, false);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
// todo: Yikes! What should we do? For now we will try to
@@ -5914,7 +5911,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessRecord pr = procs.get(i);
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
- EventLog.writeEvent(EventLogTags.AM_KILL, pr.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.userId, pr.pid,
pr.processName, pr.setAdj, "remove task");
pr.killedBackground = true;
Process.killProcessQuiet(pr.pid);
@@ -6442,7 +6439,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
- updateLruProcessLocked(cpr.proc, false, true);
+ updateLruProcessLocked(cpr.proc, false);
}
}
@@ -6630,6 +6627,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
+ UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
return null;
@@ -7013,7 +7011,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
- updateLruProcessLocked(app, true, true);
+ updateLruProcessLocked(app, true);
}
// This package really, really can not be stopped.
@@ -7499,7 +7497,7 @@ public final class ActivityManagerService extends ActivityManagerNative
int adj = proc.setAdj;
if (adj >= worstType && !proc.killedBackground) {
Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId, proc.pid,
proc.processName, adj, reason);
killed = true;
proc.killedBackground = true;
@@ -7535,8 +7533,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final int adj = proc.setAdj;
if (adj > belowAdj && !proc.killedBackground) {
Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason);
- EventLog.writeEvent(
- EventLogTags.AM_KILL, proc.pid, proc.processName, adj, reason);
+ EventLog.writeEvent(EventLogTags.AM_KILL, proc.userId,
+ proc.pid, proc.processName, adj, reason);
killed = true;
proc.killedBackground = true;
Process.killProcessQuiet(pid);
@@ -7953,7 +7951,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (app.pid > 0 && app.pid != MY_PID) {
handleAppCrashLocked(app);
Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "user's request after error");
Process.killProcessQuiet(app.pid);
}
@@ -7978,7 +7976,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
- app.info.processName, app.uid);
+ app.userId, app.info.processName, app.uid);
for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.app == app) {
@@ -7993,7 +7991,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// explicitly does so... but for persistent process, we really
// need to keep it running. If a persistent process is actually
// repeatedly crashing, then badness for everyone.
- EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
app.info.processName);
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
@@ -8106,7 +8104,7 @@ public final class ActivityManagerService extends ActivityManagerNative
: (r == null ? "unknown" : r.processName);
EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
- processName,
+ UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
crashInfo.exceptionMessage,
@@ -8304,7 +8302,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
- EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
+ EventLog.writeEvent(EventLogTags.AM_WTF,
+ UserHandle.getUserId(Binder.getCallingUid()), Binder.getCallingPid(),
processName,
r == null ? -1 : r.info.flags,
tag, crashInfo.exceptionMessage);
@@ -10067,6 +10066,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" ");
pw.print("oom: max="); pw.print(r.maxAdj);
pw.print(" hidden="); pw.print(r.hiddenAdj);
+ pw.print(" client="); pw.print(r.clientHiddenAdj);
pw.print(" empty="); pw.print(r.emptyAdj);
pw.print(" curRaw="); pw.print(r.curRawAdj);
pw.print(" setRaw="); pw.print(r.setRawAdj);
@@ -10591,7 +10591,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.i(TAG, "Kill " + capp.processName
+ " (pid " + capp.pid + "): provider " + cpr.info.name
+ " in dying process " + (proc != null ? proc.processName : "??"));
- EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, capp.userId, capp.pid,
capp.processName, capp.setAdj, "dying provider "
+ cpr.name.toShortString());
Process.killProcessQuiet(capp.pid);
@@ -12466,7 +12466,7 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
- private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
+ private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj, int clientHiddenAdj,
int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
if (mAdjSeq == app.adjSeq) {
// This adjustment has already been computed. If we are calling
@@ -12474,8 +12474,13 @@ public final class ActivityManagerService extends ActivityManagerNative
// an earlier hidden adjustment that isn't really for us... if
// so, use the new hidden adjustment.
if (!recursed && app.hidden) {
- app.curAdj = app.curRawAdj = app.nonStoppingAdj =
- app.hasActivities ? hiddenAdj : emptyAdj;
+ if (app.hasActivities) {
+ app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj;
+ } else if (app.hasClientActivities) {
+ app.curAdj = app.curRawAdj = app.nonStoppingAdj = clientHiddenAdj;
+ } else {
+ app.curAdj = app.curRawAdj = app.nonStoppingAdj = emptyAdj;
+ }
}
return app.curRawAdj;
}
@@ -12491,6 +12496,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.adjTarget = null;
app.empty = false;
app.hidden = false;
+ app.hasClientActivities = false;
final int activitiesSize = app.activities.size();
@@ -12572,7 +12578,7 @@ public final class ActivityManagerService extends ActivityManagerNative
adj = hiddenAdj;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.hidden = true;
- app.adjType = "bg-activities";
+ app.adjType = "bg-act";
}
boolean hasStoppingActivities = false;
@@ -12614,11 +12620,16 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (adj == hiddenAdj && !app.hasActivities) {
- // Whoops, this process is completely empty as far as we know
- // at this point.
- adj = emptyAdj;
- app.empty = true;
- app.adjType = "bg-empty";
+ if (app.hasClientActivities) {
+ adj = clientHiddenAdj;
+ app.adjType = "bg-client-act";
+ } else {
+ // Whoops, this process is completely empty as far as we know
+ // at this point.
+ adj = emptyAdj;
+ app.empty = true;
+ app.adjType = "bg-empty";
+ }
}
if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -12626,13 +12637,13 @@ public final class ActivityManagerService extends ActivityManagerNative
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.hidden = false;
- app.adjType = "foreground-service";
+ app.adjType = "fg-service";
schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.hidden = false;
- app.adjType = "force-foreground";
+ app.adjType = "force-fg";
app.adjSource = app.forcingToForeground;
schedGroup = Process.THREAD_GROUP_DEFAULT;
}
@@ -12754,6 +12765,14 @@ public final class ActivityManagerService extends ActivityManagerNative
myHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
}
}
+ int myClientHiddenAdj = clientHiddenAdj;
+ if (myClientHiddenAdj > client.clientHiddenAdj) {
+ if (client.clientHiddenAdj >= ProcessList.VISIBLE_APP_ADJ) {
+ myClientHiddenAdj = client.clientHiddenAdj;
+ } else {
+ myClientHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
+ }
+ }
int myEmptyAdj = emptyAdj;
if (myEmptyAdj > client.emptyAdj) {
if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) {
@@ -12763,7 +12782,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
clientAdj = computeOomAdjLocked(client, myHiddenAdj,
- myEmptyAdj, TOP_APP, true, doingAll);
+ myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll);
String adjType = null;
if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
// Not doing bind OOM management, so treat
@@ -12792,6 +12811,19 @@ public final class ActivityManagerService extends ActivityManagerNative
clientAdj = adj;
}
}
+ } else if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
+ if ((cr.flags&Context.BIND_NOT_VISIBLE) == 0) {
+ // If this connection is keeping the service
+ // created, then we want to try to better follow
+ // its memory management semantics for activities.
+ // That is, if it is sitting in the background
+ // LRU list as a hidden process (with activities),
+ // we don't want the service it is connected to
+ // to go into the empty LRU and quickly get killed,
+ // because I'll we'll do is just end up restarting
+ // the service.
+ app.hasClientActivities |= client.hasActivities;
+ }
}
if (adj > clientAdj) {
// If this process has recently shown UI, and
@@ -12843,8 +12875,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
}
+ final ActivityRecord a = cr.activity;
if ((cr.flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
- ActivityRecord a = cr.activity;
if (a != null && adj > ProcessList.FOREGROUND_APP_ADJ &&
(a.visible || a.state == ActivityState.RESUMED
|| a.state == ActivityState.PAUSING)) {
@@ -12902,6 +12934,14 @@ public final class ActivityManagerService extends ActivityManagerNative
myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
}
}
+ int myClientHiddenAdj = clientHiddenAdj;
+ if (myClientHiddenAdj > client.clientHiddenAdj) {
+ if (client.clientHiddenAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ myClientHiddenAdj = client.clientHiddenAdj;
+ } else {
+ myClientHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
+ }
+ }
int myEmptyAdj = emptyAdj;
if (myEmptyAdj > client.emptyAdj) {
if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) {
@@ -12911,7 +12951,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
int clientAdj = computeOomAdjLocked(client, myHiddenAdj,
- myEmptyAdj, TOP_APP, true, doingAll);
+ myClientHiddenAdj, myEmptyAdj, TOP_APP, true, doingAll);
if (adj > clientAdj) {
if (app.hasShownUi && app != mHomeProcess
&& clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -13301,7 +13341,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "Excessive wake lock in " + app.processName
+ " (pid " + app.pid + "): held " + wtimeUsed
+ " during " + realtimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "excessive wake lock");
Process.killProcessQuiet(app.pid);
} else if (doCpuKills && uptimeSince > 0
@@ -13313,7 +13353,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, "Excessive CPU in " + app.processName
+ " (pid " + app.pid + "): used " + cputimeUsed
+ " during " + uptimeSince);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "excessive cpu");
Process.killProcessQuiet(app.pid);
} else {
@@ -13325,8 +13365,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj,
- int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) {
+ int clientHiddenAdj, int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) {
app.hiddenAdj = hiddenAdj;
+ app.clientHiddenAdj = clientHiddenAdj;
app.emptyAdj = emptyAdj;
if (app.thread == null) {
@@ -13337,7 +13378,7 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean success = true;
- computeOomAdjLocked(app, hiddenAdj, emptyAdj, TOP_APP, false, doingAll);
+ computeOomAdjLocked(app, hiddenAdj, clientHiddenAdj, emptyAdj, TOP_APP, false, doingAll);
if (app.curRawAdj != app.setRawAdj) {
if (wasKeeping && !app.keeping) {
@@ -13374,7 +13415,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (app.waitingToKill != null &&
app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, app.waitingToKill);
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
@@ -13424,8 +13465,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mAdjSeq++;
- boolean success = updateOomAdjLocked(app, app.hiddenAdj, app.emptyAdj,
- TOP_APP, false);
+ boolean success = updateOomAdjLocked(app, app.hiddenAdj, app.clientHiddenAdj,
+ app.emptyAdj, TOP_APP, false);
final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
&& app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
if (nowHidden != wasHidden) {
@@ -13439,6 +13480,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final void updateOomAdjLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+ final long oldTime = SystemClock.uptimeMillis() - ProcessList.MAX_EMPTY_TIME;
if (false) {
RuntimeException e = new RuntimeException();
@@ -13449,20 +13491,40 @@ public final class ActivityManagerService extends ActivityManagerNative
mAdjSeq++;
mNewNumServiceProcs = 0;
+ final int emptyProcessLimit;
+ final int hiddenProcessLimit;
+ if (mProcessLimit <= 0) {
+ emptyProcessLimit = hiddenProcessLimit = 0;
+ } else if (mProcessLimit == 1) {
+ emptyProcessLimit = 1;
+ hiddenProcessLimit = 0;
+ } else {
+ emptyProcessLimit = (mProcessLimit*2)/3;
+ hiddenProcessLimit = mProcessLimit - emptyProcessLimit;
+ }
+
// Let's determine how many processes we have running vs.
// how many slots we have for background processes; we may want
// to put multiple processes in a slot of there are enough of
// them.
int numSlots = (ProcessList.HIDDEN_APP_MAX_ADJ
- ProcessList.HIDDEN_APP_MIN_ADJ + 1) / 2;
- int emptyFactor = (mLruProcesses.size()-mNumNonHiddenProcs-mNumHiddenProcs)/numSlots;
+ int numEmptyProcs = mLruProcesses.size()-mNumNonHiddenProcs-mNumHiddenProcs;
+ if (numEmptyProcs > hiddenProcessLimit) {
+ // If there are more empty processes than our limit on hidden
+ // processes, then use the hidden process limit for the factor.
+ // This ensures that the really old empty processes get pushed
+ // down to the bottom, so if we are running low on memory we will
+ // have a better chance at keeping around more hidden processes
+ // instead of a gazillion empty processes.
+ numEmptyProcs = hiddenProcessLimit;
+ }
+ int emptyFactor = numEmptyProcs/numSlots;
if (emptyFactor < 1) emptyFactor = 1;
int hiddenFactor = (mNumHiddenProcs > 0 ? mNumHiddenProcs : 1)/numSlots;
if (hiddenFactor < 1) hiddenFactor = 1;
int stepHidden = 0;
int stepEmpty = 0;
- final int emptyProcessLimit = mProcessLimit > 1 ? mProcessLimit / 2 : mProcessLimit;
- final int hiddenProcessLimit = mProcessLimit > 1 ? mProcessLimit / 2 : mProcessLimit;
int numHidden = 0;
int numEmpty = 0;
int numTrimming = 0;
@@ -13477,11 +13539,12 @@ public final class ActivityManagerService extends ActivityManagerNative
int nextHiddenAdj = curHiddenAdj+1;
int curEmptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
int nextEmptyAdj = curEmptyAdj+2;
+ int curClientHiddenAdj = curEmptyAdj;
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
//Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
- updateOomAdjLocked(app, curHiddenAdj, curEmptyAdj, TOP_APP, true);
+ updateOomAdjLocked(app, curHiddenAdj, curClientHiddenAdj, curEmptyAdj, TOP_APP, true);
if (!app.killedBackground) {
if (app.curRawAdj == curHiddenAdj && app.hasActivities) {
// This process was assigned as a hidden process... step the
@@ -13496,17 +13559,31 @@ public final class ActivityManagerService extends ActivityManagerNative
if (nextHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
nextHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
}
+ if (curClientHiddenAdj <= curHiddenAdj) {
+ curClientHiddenAdj = curHiddenAdj + 1;
+ if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
+ curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+ }
+ }
}
}
numHidden++;
if (numHidden > hiddenProcessLimit) {
Slog.i(TAG, "No longer want " + app.processName
+ " (pid " + app.pid + "): hidden #" + numHidden);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "too many background");
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
}
+ } else if (app.curRawAdj == curHiddenAdj && app.hasClientActivities) {
+ // This process has a client that has activities. We will have
+ // given it the current hidden adj; here we will just leave it
+ // without stepping the hidden adj.
+ curClientHiddenAdj++;
+ if (curClientHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
+ curClientHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+ }
} else {
if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curHiddenAdj) {
// This process was assigned as an empty process... step the
@@ -13525,15 +13602,28 @@ public final class ActivityManagerService extends ActivityManagerNative
} else if (app.curRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
mNumNonHiddenProcs++;
}
- if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
- numEmpty++;
- if (numEmpty > emptyProcessLimit) {
+ if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
+ && !app.hasClientActivities) {
+ if (numEmpty > ProcessList.TRIM_EMPTY_APPS
+ && app.lastActivityTime < oldTime) {
Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): empty #" + numEmpty);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "too many background");
+ + " (pid " + app.pid + "): empty for "
+ + ((oldTime+ProcessList.MAX_EMPTY_TIME-app.lastActivityTime)
+ / 1000) + "s");
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
+ app.processName, app.setAdj, "old background process");
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
+ } else {
+ numEmpty++;
+ if (numEmpty > emptyProcessLimit) {
+ Slog.i(TAG, "No longer want " + app.processName
+ + " (pid " + app.pid + "): empty #" + numEmpty);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ }
}
}
}
@@ -13546,7 +13636,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// left sitting around after no longer needed.
Slog.i(TAG, "Isolated process " + app.processName
+ " (pid " + app.pid + ") no longer needed");
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "isolated not needed");
app.killedBackground = true;
Process.killProcessQuiet(app.pid);
@@ -13567,8 +13657,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// are managing to keep around is less than half the maximum we desire;
// if we are keeping a good number around, we'll let them use whatever
// memory they want.
- if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/4)
- && numEmpty <= (ProcessList.MAX_HIDDEN_APPS/4)) {
+ if (numHidden <= ProcessList.TRIM_HIDDEN_APPS
+ && numEmpty <= ProcessList.TRIM_EMPTY_APPS) {
final int numHiddenAndEmpty = numHidden + numEmpty;
final int N = mLruProcesses.size();
int factor = numTrimming/3;
@@ -13578,9 +13668,9 @@ public final class ActivityManagerService extends ActivityManagerNative
if (factor < minFactor) factor = minFactor;
int step = 0;
int fgTrimLevel;
- if (numHiddenAndEmpty <= (ProcessList.MAX_HIDDEN_APPS/5)) {
+ if (numHiddenAndEmpty <= ProcessList.TRIM_CRITICAL_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
- } else if (numHiddenAndEmpty <= (ProcessList.MAX_HIDDEN_APPS/3)) {
+ } else if (numHiddenAndEmpty <= ProcessList.TRIM_LOW_THRESHOLD) {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
} else {
fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
@@ -13700,7 +13790,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ (app.thread != null ? app.thread.asBinder() : null)
+ ")\n");
if (app.pid > 0 && app.pid != MY_PID) {
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.userId, app.pid,
app.processName, app.setAdj, "empty");
Process.killProcessQuiet(app.pid);
} else {
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 7ff574838df0..6cd86fd05d44 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -746,8 +746,8 @@ final class ActivityRecord {
final long totalTime = stack.mInitialStartTime != 0
? (curTime - stack.mInitialStartTime) : thisTime;
if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
- EventLog.writeEvent(EventLogTags.ACTIVITY_LAUNCH_TIME,
- System.identityHashCode(this), shortComponentName,
+ EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
+ userId, System.identityHashCode(this), shortComponentName,
thisTime, totalTime);
StringBuilder sb = service.mStringBuilder;
sb.setLength(0);
@@ -923,6 +923,8 @@ final class ActivityRecord {
StringBuilder sb = new StringBuilder(128);
sb.append("ActivityRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" u");
+ sb.append(userId);
sb.append(' ');
sb.append(intent.getComponent().flattenToShortString());
sb.append('}');
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 1707ff0fa63b..2d44527421ff 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -638,7 +638,7 @@ final class ActivityStack {
if (idx < 0) {
app.activities.add(r);
}
- mService.updateLruProcessLocked(app, true, true);
+ mService.updateLruProcessLocked(app, true);
try {
if (app.thread == null) {
@@ -656,7 +656,7 @@ final class ActivityStack {
+ " andResume=" + andResume);
if (andResume) {
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
- System.identityHashCode(r),
+ r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
}
if (r.isHomeActivity) {
@@ -951,7 +951,7 @@ final class ActivityStack {
if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
- System.identityHashCode(prev),
+ prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags);
@@ -1040,7 +1040,7 @@ final class ActivityStack {
completePauseLocked();
} else {
EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
- System.identityHashCode(r), r.shortComponentName,
+ r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
}
@@ -1505,7 +1505,7 @@ final class ActivityStack {
if (next.app != null && next.app.thread != null) {
// No reason to do full oom adj update here; we'll let that
// happen whenever it needs to later.
- mService.updateLruProcessLocked(next.app, false, true);
+ mService.updateLruProcessLocked(next.app, false);
}
startPausingLocked(userLeaving, false);
return true;
@@ -1641,7 +1641,7 @@ final class ActivityStack {
if (mMainStack) {
mService.addRecentTaskLocked(next.task);
}
- mService.updateLruProcessLocked(next.app, true, true);
+ mService.updateLruProcessLocked(next.app, true);
updateLRUListLocked(next);
// Have the window manager re-evaluate the orientation of
@@ -1699,7 +1699,7 @@ final class ActivityStack {
}
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
- System.identityHashCode(next),
+ next.userId, System.identityHashCode(next),
next.task.taskId, next.shortComponentName);
next.sleeping = false;
@@ -2967,7 +2967,7 @@ final class ActivityStack {
intent, r.getUriPermissionsLocked());
if (newTask) {
- EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
+ EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
}
logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
startActivityLocked(r, newTask, doResume, keepCurTransition, options);
@@ -3700,7 +3700,7 @@ final class ActivityStack {
r.makeFinishing();
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
- System.identityHashCode(r),
+ r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
if (index < (mHistory.size()-1)) {
ActivityRecord next = mHistory.get(index+1);
@@ -3996,7 +3996,7 @@ final class ActivityStack {
TAG, "Removing activity from " + reason + ": token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
- System.identityHashCode(r),
+ r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
boolean removedFromHistory = false;
@@ -4228,7 +4228,7 @@ final class ActivityStack {
}
finishTaskMoveLocked(task);
- EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
+ EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, task);
}
private final void finishTaskMoveLocked(int task) {
@@ -4448,7 +4448,7 @@ final class ActivityStack {
private final void logStartActivity(int tag, ActivityRecord r,
TaskRecord task) {
EventLog.writeEvent(tag,
- System.identityHashCode(r), task.taskId,
+ r.userId, System.identityHashCode(r), task.taskId,
r.shortComponentName, r.intent.getAction(),
r.intent.getType(), r.intent.getDataString(),
r.intent.getFlags());
@@ -4590,7 +4590,7 @@ final class ActivityStack {
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
- : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
+ : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
r.task.taskId, r.shortComponentName);
r.startFreezingScreenLocked(r.app, 0);
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index 07440b544a1e..c631b6e0f9d9 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -64,6 +64,8 @@ class BroadcastFilter extends IntentFilter {
StringBuilder sb = new StringBuilder();
sb.append("BroadcastFilter{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" u");
+ sb.append(owningUserId);
sb.append(' ');
sb.append(receiverList);
sb.append('}');
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index b0af081fb0ce..9f27994a77d9 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -209,7 +209,7 @@ public class BroadcastQueue {
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceiver = r;
- mService.updateLruProcessLocked(app, true, true);
+ mService.updateLruProcessLocked(app, true);
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
@@ -930,22 +930,22 @@ public class BroadcastQueue {
if (curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter) curReceiver;
EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
- System.identityHashCode(r),
+ bf.owningUserId, System.identityHashCode(r),
r.intent.getAction(),
r.nextReceiver - 1,
System.identityHashCode(bf));
} else {
+ ResolveInfo ri = (ResolveInfo)curReceiver;
EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- ((ResolveInfo)curReceiver).toString());
+ UserHandle.getUserId(ri.activityInfo.applicationInfo.uid),
+ System.identityHashCode(r), r.intent.getAction(),
+ r.nextReceiver - 1, ri.toString());
}
} else {
Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+ r);
EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
+ -1, System.identityHashCode(r),
r.intent.getAction(),
r.nextReceiver,
"NONE");
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index ca6d5f70192b..85ec328d134c 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -194,6 +194,6 @@ class BroadcastRecord extends Binder {
public String toString() {
return "BroadcastRecord{"
+ Integer.toHexString(System.identityHashCode(this))
- + " " + intent.getAction() + "}";
+ + " u" + userId + " " + intent.getAction() + "}";
}
}
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 5b3ff8d3986d..4ed3c3150b5a 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -62,6 +62,8 @@ class ConnectionRecord {
StringBuilder sb = new StringBuilder(128);
sb.append("ConnectionRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" u");
+ sb.append(binding.client.userId);
sb.append(' ');
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
sb.append("CR ");
@@ -70,7 +72,7 @@ class ConnectionRecord {
sb.append("DBG ");
}
if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
- sb.append("NOTFG ");
+ sb.append("!FG ");
}
if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
sb.append("ABCLT ");
@@ -88,7 +90,10 @@ class ConnectionRecord {
sb.append("ACT ");
}
if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
- sb.append("NOTVIS ");
+ sb.append("!VIS ");
+ }
+ if ((flags&Context.BIND_VISIBLE) != 0) {
+ sb.append("VIS ");
}
if (serviceDead) {
sb.append("DEAD ");
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index de306b507ac3..8fb6a93c5ed9 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -25,6 +25,7 @@ import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Slog;
import java.io.PrintWriter;
@@ -199,6 +200,8 @@ class ContentProviderRecord {
StringBuilder sb = new StringBuilder(128);
sb.append("ContentProviderRecord{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(" u");
+ sb.append(UserHandle.getUserId(uid));
sb.append(' ');
sb.append(name.flattenToShortString());
sb.append('}');
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/java/com/android/server/am/EventLogTags.logtags
index a579f440c4b1..6ee750710d6c 100644
--- a/services/java/com/android/server/am/EventLogTags.logtags
+++ b/services/java/com/android/server/am/EventLogTags.logtags
@@ -14,72 +14,72 @@ option java_package com.android.server.am
# google3/googledata/wireless/android/provisioning/gservices.config !!
#
# An activity is being finished:
-30001 am_finish_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+30001 am_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
# A task is being brought to the front of the screen:
-30002 am_task_to_front (Task|1|5)
+30002 am_task_to_front (User|1|5),(Task|1|5)
# An existing activity is being given a new intent:
-30003 am_new_intent (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+30003 am_new_intent (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
# A new task is being created:
-30004 am_create_task (Task ID|1|5)
+30004 am_create_task (User|1|5),(Task ID|1|5)
# A new activity is being created in an existing task:
-30005 am_create_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+30005 am_create_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
# An activity has been resumed into the foreground but was not already running:
-30006 am_restart_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+30006 am_restart_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
# An activity has been resumed and is now in the foreground:
-30007 am_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+30007 am_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
# Application Not Responding
-30008 am_anr (pid|1|5),(Package Name|3),(Flags|1|5),(reason|3)
+30008 am_anr (User|1|5),(pid|1|5),(Package Name|3),(Flags|1|5),(reason|3)
# Activity launch time
-30009 activity_launch_time (Token|1|5),(Component Name|3),(time|2|3)
+30009 am_activity_launch_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
# Application process bound to work
-30010 am_proc_bound (PID|1|5),(Process Name|3)
+30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
# Application process died
-30011 am_proc_died (PID|1|5),(Process Name|3)
+30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3)
# The Activity Manager failed to pause the given activity.
-30012 am_failed_to_pause (Token|1|5),(Wanting to pause|3),(Currently pausing|3)
+30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
# Attempting to pause the current activity
-30013 am_pause_activity (Token|1|5),(Component Name|3)
+30013 am_pause_activity (User|1|5),(Token|1|5),(Component Name|3)
# Application process has been started
-30014 am_proc_start (PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
+30014 am_proc_start (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
# An application process has been marked as bad
-30015 am_proc_bad (UID|1|5),(Process Name|3)
+30015 am_proc_bad (User|1|5),(UID|1|5),(Process Name|3)
# An application process that was bad is now marked as good
-30016 am_proc_good (UID|1|5),(Process Name|3)
+30016 am_proc_good (User|1|5),(UID|1|5),(Process Name|3)
# Reporting to applications that memory is low
30017 am_low_memory (Num Processes|1|1)
# An activity is being destroyed:
-30018 am_destroy_activity (Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+30018 am_destroy_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
# An activity has been relaunched, resumed, and is now in the foreground:
-30019 am_relaunch_resume_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+30019 am_relaunch_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
# An activity has been relaunched:
-30020 am_relaunch_activity (Token|1|5),(Task ID|1|5),(Component Name|3)
+30020 am_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
# The activity's onPause has been called.
-30021 am_on_paused_called (Component Name|3)
+30021 am_on_paused_called (User|1|5),(Component Name|3)
# The activity's onResume has been called.
-30022 am_on_resume_called (Component Name|3)
+30022 am_on_resume_called (User|1|5),(Component Name|3)
# Kill a process to reclaim memory.
-30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
+30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
# Discard an undelivered serialized broadcast (timeout/ANR/crash)
-30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
-30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
+30024 am_broadcast_discard_filter (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
+30025 am_broadcast_discard_app (User|1|5),(Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
# A service is being created
-30030 am_create_service (Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
+30030 am_create_service (User|1|5),(Service Record|1|5),(Name|3),(Intent|3),(PID|1|5)
# A service is being destroyed
-30031 am_destroy_service (Service Record|1|5),(Name|3),(PID|1|5)
+30031 am_destroy_service (User|1|5),(Service Record|1|5),(Name|3),(PID|1|5)
# A process has crashed too many times, it is being cleared
-30032 am_process_crashed_too_much (Name|3),(PID|1|5)
+30032 am_process_crashed_too_much (User|1|5),(Name|3),(PID|1|5)
# An unknown process is trying to attach to the activity manager
30033 am_drop_process (PID|1|5)
# A service has crashed too many times, it is being stopped
-30034 am_service_crashed_too_much (Crash Count|1|1),(Component Name|3),(PID|1|5)
+30034 am_service_crashed_too_much (User|1|5),(Crash Count|1|1),(Component Name|3),(PID|1|5)
# A service is going to be restarted after its process went away
-30035 am_schedule_service_restart (Component Name|3),(Time|2|3)
+30035 am_schedule_service_restart (User|1|5),(Component Name|3),(Time|2|3)
# A client was waiting for a content provider, but its process was lost
-30036 am_provider_lost_process (Package Name|3),(UID|1|5),(Name|3)
+30036 am_provider_lost_process (User|1|5),(Package Name|3),(UID|1|5),(Name|3)
# The activity manager gave up on a new process taking too long to start
-30037 am_process_start_timeout (PID|1|5),(UID|1|5),(Process Name|3)
+30037 am_process_start_timeout (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3)
# Unhandled exception
-30039 am_crash (PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
+30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
# Log.wtf() called
-30040 am_wtf (PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
+30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/java/com/android/server/am/ProcessList.java
index afc060ecc6b7..9e25e3024513 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/java/com/android/server/am/ProcessList.java
@@ -101,7 +101,24 @@ class ProcessList {
// The maximum number of hidden processes we will keep around before
// killing them; this is just a control to not let us go too crazy with
// keeping around processes on devices with large amounts of RAM.
- static final int MAX_HIDDEN_APPS = 15;
+ static final int MAX_HIDDEN_APPS = 24;
+
+ // We allow empty processes to stick around for at most 30 minutes.
+ static final long MAX_EMPTY_TIME = 30*60*1000;
+
+ // The number of hidden at which we don't consider it necessary to do
+ // memory trimming.
+ static final int TRIM_HIDDEN_APPS = 3;
+
+ // The number of empty apps at which we don't consider it necessary to do
+ // memory trimming.
+ static final int TRIM_EMPTY_APPS = 3;
+
+ // Threshold of number of hidden+empty where we consider memory critical.
+ static final int TRIM_CRITICAL_THRESHOLD = 3;
+
+ // Threshold of number of hidden+empty where we consider memory critical.
+ static final int TRIM_LOW_THRESHOLD = 5;
// We put empty content processes after any hidden processes that have
// been idle for less than 15 seconds.
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index d37242259e08..652fdb58b45d 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -61,6 +61,7 @@ class ProcessRecord {
long lruWeight; // Weight for ordering in LRU list
int maxAdj; // Maximum OOM adjustment for this process
int hiddenAdj; // If hidden, this is the adjustment to use
+ int clientHiddenAdj; // If empty but hidden client, this is the adjustment to use
int emptyAdj; // If empty, this is the adjustment to use
int curRawAdj; // Current OOM unlimited adjustment for this process
int setRawAdj; // Last set OOM unlimited adjustment for this process
@@ -75,6 +76,7 @@ class ProcessRecord {
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean hasActivities; // Are there any activities running in this process?
+ boolean hasClientActivities; // Are there any client services with activities?
boolean foregroundServices; // Running any services that are foreground?
boolean foregroundActivities; // Running any activities that are foreground?
boolean systemNoUi; // This is a system process, but not currently showing UI.
@@ -188,8 +190,7 @@ class ProcessRecord {
instrumentationInfo.dump(new PrintWriterPrinter(pw), prefix + " ");
}
}
- pw.print(prefix); pw.print("thread="); pw.print(thread);
- pw.print(" curReceiver="); pw.println(curReceiver);
+ pw.print(prefix); pw.print("thread="); pw.println(thread);
pw.print(prefix); pw.print("pid="); pw.print(pid); pw.print(" starting=");
pw.print(starting); pw.print(" lastPss="); pw.println(lastPss);
pw.print(prefix); pw.print("lastActivityTime=");
@@ -201,6 +202,7 @@ class ProcessRecord {
pw.print(" empty="); pw.println(empty);
pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
pw.print(" hidden="); pw.print(hiddenAdj);
+ pw.print(" client="); pw.print(clientHiddenAdj);
pw.print(" empty="); pw.print(emptyAdj);
pw.print(" curRaw="); pw.print(curRawAdj);
pw.print(" setRaw="); pw.print(setRawAdj);
@@ -211,18 +213,27 @@ class ProcessRecord {
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
- pw.print(" pendingUiClean="); pw.print(pendingUiClean);
- pw.print(" hasAboveClient="); pw.println(hasAboveClient);
- pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
- pw.print(" foregroundServices="); pw.print(foregroundServices);
- pw.print(" forcingToForeground="); pw.println(forcingToForeground);
- pw.print(prefix); pw.print("persistent="); pw.print(persistent);
- pw.print(" removed="); pw.print(removed);
- pw.print(" hasActivities="); pw.print(hasActivities);
- pw.print(" foregroundActivities="); pw.println(foregroundActivities);
pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
pw.print(" lruSeq="); pw.println(lruSeq);
+ if (hasShownUi || pendingUiClean || hasAboveClient) {
+ pw.print(prefix); pw.print("hasShownUi="); pw.print(hasShownUi);
+ pw.print(" pendingUiClean="); pw.print(pendingUiClean);
+ pw.print(" hasAboveClient="); pw.println(hasAboveClient);
+ }
+ if (setIsForeground || foregroundServices || forcingToForeground != null) {
+ pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
+ pw.print(" foregroundServices="); pw.print(foregroundServices);
+ pw.print(" forcingToForeground="); pw.println(forcingToForeground);
+ }
+ if (persistent || removed) {
+ pw.print(prefix); pw.print("persistent="); pw.print(persistent);
+ pw.print(" removed="); pw.println(removed);
+ }
+ if (hasActivities || hasClientActivities || foregroundActivities) {
+ pw.print(prefix); pw.print("hasActivities="); pw.print(hasActivities);
+ pw.print(" hasClientActivities="); pw.print(hasClientActivities);
+ pw.print(" foregroundActivities="); pw.println(foregroundActivities);
+ }
if (!keeping) {
long wtime;
synchronized (batteryStats.getBatteryStats()) {
@@ -231,10 +242,10 @@ class ProcessRecord {
}
long timeUsed = wtime - lastWakeTime;
pw.print(prefix); pw.print("lastWakeTime="); pw.print(lastWakeTime);
- pw.print(" time used=");
+ pw.print(" timeUsed=");
TimeUtils.formatDuration(timeUsed, pw); pw.println("");
pw.print(prefix); pw.print("lastCpuTime="); pw.print(lastCpuTime);
- pw.print(" time used=");
+ pw.print(" timeUsed=");
TimeUtils.formatDuration(curCpuTime-lastCpuTime, pw); pw.println("");
}
pw.print(prefix); pw.print("lastRequestedGc=");
@@ -299,6 +310,9 @@ class ProcessRecord {
pw.print(prefix); pw.print(" - "); pw.println(conProviders.get(i).toShortString());
}
}
+ if (curReceiver != null) {
+ pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
+ }
if (receivers.size() > 0) {
pw.print(prefix); pw.println("Receivers:");
for (ReceiverList rl : receivers) {
@@ -318,7 +332,7 @@ class ProcessRecord {
pkgList.add(_info.packageName);
thread = _thread;
maxAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
- hiddenAdj = emptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+ hiddenAdj = clientHiddenAdj = emptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
curRawAdj = setRawAdj = -100;
curAdj = setAdj = -100;
persistent = false;
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 7055fdc66386..84e824af9dea 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -425,6 +425,7 @@ class ServiceRecord extends Binder {
StringBuilder sb = new StringBuilder(128);
sb.append("ServiceRecord{")
.append(Integer.toHexString(System.identityHashCode(this)))
+ .append(" u").append(userId)
.append(' ').append(shortName).append('}');
return stringName = sb.toString();
}
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/java/com/android/server/dreams/DreamController.java
new file mode 100644
index 000000000000..81c801871374
--- /dev/null
+++ b/services/java/com/android/server/dreams/DreamController.java
@@ -0,0 +1,243 @@
+/*
+ * 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.dreams;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.service.dreams.Dream;
+import android.service.dreams.IDreamService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.io.PrintWriter;
+import java.util.NoSuchElementException;
+
+/**
+ * Internal controller for starting and stopping the current dream and managing related state.
+ *
+ * Assumes all operations are called from the dream handler thread.
+ */
+final class DreamController {
+ private static final String TAG = "DreamController";
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Listener mListener;
+ private final IWindowManager mIWindowManager;
+
+ private final Intent mDreamingStartedIntent = new Intent(Dream.ACTION_DREAMING_STARTED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ private final Intent mDreamingStoppedIntent = new Intent(Dream.ACTION_DREAMING_STOPPED)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+ private DreamRecord mCurrentDream;
+
+ public DreamController(Context context, Handler handler, Listener listener) {
+ mContext = context;
+ mHandler = handler;
+ mListener = listener;
+ mIWindowManager = WindowManagerGlobal.getWindowManagerService();
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println("Dreamland:");
+ if (mCurrentDream != null) {
+ pw.println(" mCurrentDream:");
+ pw.println(" mToken=" + mCurrentDream.mToken);
+ pw.println(" mName=" + mCurrentDream.mName);
+ pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mUserId=" + mCurrentDream.mUserId);
+ pw.println(" mBound=" + mCurrentDream.mBound);
+ pw.println(" mService=" + mCurrentDream.mService);
+ pw.println(" mSentStartBroadcast=" + mCurrentDream.mSentStartBroadcast);
+ } else {
+ pw.println(" mCurrentDream: null");
+ }
+ }
+
+ public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+ stopDream();
+
+ Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+
+ mCurrentDream = new DreamRecord(token, name, isTest, userId);
+
+ try {
+ mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to add window token for dream.", ex);
+ stopDream();
+ return;
+ }
+
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Dream.CATEGORY_DREAM);
+ intent.setComponent(name);
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ try {
+ if (!mContext.bindService(intent, mCurrentDream,
+ Context.BIND_AUTO_CREATE, userId)) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent);
+ stopDream();
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
+ stopDream();
+ return;
+ }
+
+ mCurrentDream.mBound = true;
+ }
+
+ public void stopDream() {
+ if (mCurrentDream == null) {
+ return;
+ }
+
+ final DreamRecord oldDream = mCurrentDream;
+ mCurrentDream = null;
+ Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+ + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+
+ if (oldDream.mSentStartBroadcast) {
+ mContext.sendBroadcast(mDreamingStoppedIntent);
+ }
+
+ 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.
+ try {
+ oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
+ } catch (NoSuchElementException ex) {
+ // don't care
+ }
+ oldDream.mService = null;
+ }
+
+ if (oldDream.mBound) {
+ mContext.unbindService(oldDream);
+ }
+
+ try {
+ mIWindowManager.removeWindowToken(oldDream.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Error removing window token for dream.", ex);
+ }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDreamStopped(oldDream.mToken);
+ }
+ });
+ }
+
+ private void attach(IDreamService service) {
+ try {
+ service.asBinder().linkToDeath(mCurrentDream, 0);
+ service.attach(mCurrentDream.mToken);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "The dream service died unexpectedly.", ex);
+ stopDream();
+ return;
+ }
+
+ mCurrentDream.mService = service;
+
+ if (!mCurrentDream.mIsTest) {
+ mContext.sendBroadcast(mDreamingStartedIntent);
+ mCurrentDream.mSentStartBroadcast = true;
+ }
+ }
+
+ /**
+ * Callback interface to be implemented by the {@link DreamManagerService}.
+ */
+ public interface Listener {
+ void onDreamStopped(Binder token);
+ }
+
+ private final class DreamRecord implements DeathRecipient, ServiceConnection {
+ public final Binder mToken;
+ public final ComponentName mName;
+ public final boolean mIsTest;
+ public final int mUserId;
+
+ public boolean mBound;
+ public IDreamService mService;
+ public boolean mSentStartBroadcast;
+
+ public DreamRecord(Binder token, ComponentName name,
+ boolean isTest, int userId) {
+ mToken = token;
+ mName = name;
+ mIsTest = isTest;
+ mUserId = userId;
+ }
+
+ // May be called on any thread.
+ @Override
+ public void binderDied() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mService = null;
+ if (mCurrentDream == DreamRecord.this) {
+ stopDream();
+ }
+ }
+ });
+ }
+
+ // May be called on any thread.
+ @Override
+ public void onServiceConnected(ComponentName name, final IBinder service) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCurrentDream == DreamRecord.this && mService == null) {
+ attach(IDreamService.Stub.asInterface(service));
+ }
+ }
+ });
+ }
+
+ // May be called on any thread.
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mService = null;
+ if (mCurrentDream == DreamRecord.this) {
+ stopDream();
+ }
+ }
+ });
+ }
+ }
+} \ No newline at end of file
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
new file mode 100644
index 000000000000..1f4017614617
--- /dev/null
+++ b/services/java/com/android/server/dreams/DreamManagerService.java
@@ -0,0 +1,383 @@
+/*
+ * 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.dreams;
+
+import com.android.internal.util.DumpUtils;
+
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.IDreamManager;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import libcore.util.Objects;
+
+/**
+ * Service api for managing dreams.
+ *
+ * @hide
+ */
+public final class DreamManagerService extends IDreamManager.Stub {
+ private static final boolean DEBUG = true;
+ private static final String TAG = "DreamManagerService";
+
+ private final Object mLock = new Object();
+
+ private final Context mContext;
+ private final DreamHandler mHandler;
+ private final DreamController mController;
+ private final PowerManager mPowerManager;
+
+ private Binder mCurrentDreamToken;
+ private ComponentName mCurrentDreamName;
+ private int mCurrentDreamUserId;
+ private boolean mCurrentDreamIsTest;
+
+ public DreamManagerService(Context context, Handler mainHandler) {
+ mContext = context;
+ mHandler = new DreamHandler(mainHandler.getLooper());
+ mController = new DreamController(context, mHandler, mControllerListener);
+
+ mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ }
+
+ public void systemReady() {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ stopDreamLocked();
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+ pw.println("DREAM MANAGER (dumpsys dreams)");
+ pw.println();
+
+ pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
+ pw.println("mCurrentDreamName=" + mCurrentDreamName);
+ pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
+ pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println();
+
+ DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ mController.dump(pw);
+ }
+ }, pw, 200);
+ }
+
+ @Override // Binder call
+ public ComponentName[] getDreamComponents() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDreamComponentsForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void setDreamComponents(ComponentName[] componentNames) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames),
+ userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public ComponentName getDefaultDreamComponent() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+ userId);
+ return name == null ? null : ComponentName.unflattenFromString(name);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public boolean isDreaming() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ synchronized (mLock) {
+ return mCurrentDreamToken != null && !mCurrentDreamIsTest;
+ }
+ }
+
+ @Override // Binder call
+ public void dream() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Ask the power manager to nap. It will eventually call back into
+ // startDream() if/when it is appropriate to start dreaming.
+ // Because napping could cause the screen to turn off immediately if the dream
+ // cannot be started, we keep one eye open and gently poke user activity.
+ long time = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(time, true /*noChangeLights*/);
+ mPowerManager.nap(time);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void testDream(ComponentName dream) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ if (dream == null) {
+ throw new IllegalArgumentException("dream must not be null");
+ }
+
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int currentUserId = ActivityManager.getCurrentUser();
+ if (callingUserId != currentUserId) {
+ // This check is inherently prone to races but at least it's something.
+ Slog.w(TAG, "Aborted attempt to start a test dream while a different "
+ + " user is active: callingUserId=" + callingUserId
+ + ", currentUserId=" + currentUserId);
+ return;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ startDreamLocked(dream, true /*isTest*/, callingUserId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void awaken() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Treat an explicit request to awaken as user activity so that the
+ // device doesn't immediately go to sleep if the timeout expired,
+ // for example when being undocked.
+ long time = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(time, false /*noChangeLights*/);
+ stopDream();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void finishSelf(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream finished: " + token);
+ }
+
+ // Note that a dream finishing and self-terminating is not
+ // itself considered user activity. If the dream is ending because
+ // the user interacted with the device then user activity will already
+ // have been poked so the device will stay awake a bit longer.
+ // If the dream is ending on its own for other reasons and no wake
+ // locks are held and the user activity timeout has expired then the
+ // device may simply go to sleep.
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token) {
+ stopDreamLocked();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Called by the power manager to start a dream.
+ */
+ public void startDream() {
+ int userId = ActivityManager.getCurrentUser();
+ ComponentName dream = chooseDreamForUser(userId);
+ if (dream != null) {
+ synchronized (mLock) {
+ startDreamLocked(dream, false /*isTest*/, userId);
+ }
+ }
+ }
+
+ /**
+ * Called by the power manager to stop a dream.
+ */
+ public void stopDream() {
+ synchronized (mLock) {
+ stopDreamLocked();
+ }
+ }
+
+ private ComponentName chooseDreamForUser(int userId) {
+ ComponentName[] dreams = getDreamComponentsForUser(userId);
+ return dreams != null && dreams.length != 0 ? dreams[0] : null;
+ }
+
+ private ComponentName[] getDreamComponentsForUser(int userId) {
+ String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_COMPONENTS,
+ userId);
+ return names == null ? null : componentsFromString(names);
+ }
+
+ private void startDreamLocked(final ComponentName name,
+ final boolean isTest, final int userId) {
+ if (Objects.equal(mCurrentDreamName, name)
+ && mCurrentDreamIsTest == isTest
+ && mCurrentDreamUserId == userId) {
+ return;
+ }
+
+ stopDreamLocked();
+
+ Slog.i(TAG, "Entering dreamland.");
+
+ final Binder newToken = new Binder();
+ mCurrentDreamToken = newToken;
+ mCurrentDreamName = name;
+ mCurrentDreamIsTest = isTest;
+ mCurrentDreamUserId = userId;
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mController.startDream(newToken, name, isTest, userId);
+ }
+ });
+ }
+
+ private void stopDreamLocked() {
+ if (mCurrentDreamToken != null) {
+ Slog.i(TAG, "Leaving dreamland.");
+
+ cleanupDreamLocked();
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mController.stopDream();
+ }
+ });
+ }
+ }
+
+ private void cleanupDreamLocked() {
+ mCurrentDreamToken = null;
+ mCurrentDreamName = null;
+ mCurrentDreamIsTest = false;
+ mCurrentDreamUserId = 0;
+ }
+
+ private void checkPermission(String permission) {
+ if (mContext.checkCallingOrSelfPermission(permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+ + ", must have permission " + permission);
+ }
+ }
+
+ private static String componentsToString(ComponentName[] componentNames) {
+ StringBuilder names = new StringBuilder();
+ if (componentNames != null) {
+ for (ComponentName componentName : componentNames) {
+ if (names.length() > 0) {
+ names.append(',');
+ }
+ names.append(componentName.flattenToString());
+ }
+ }
+ return names.toString();
+ }
+
+ private static ComponentName[] componentsFromString(String names) {
+ String[] namesArray = names.split(",");
+ ComponentName[] componentNames = new ComponentName[namesArray.length];
+ for (int i = 0; i < namesArray.length; i++) {
+ componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+ }
+ return componentNames;
+ }
+
+ private final DreamController.Listener mControllerListener = new DreamController.Listener() {
+ @Override
+ public void onDreamStopped(Binder token) {
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token) {
+ cleanupDreamLocked();
+ }
+ }
+ }
+ };
+
+ /**
+ * Handler for asynchronous operations performed by the dream manager.
+ * Ensures operations to {@link DreamController} are single-threaded.
+ */
+ private final class DreamHandler extends Handler {
+ public DreamHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+ }
+}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 030eb5eae65d..ad138e80140b 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -24,6 +24,7 @@ import com.android.server.TwilightService;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.display.DisplayManagerService;
+import com.android.server.dreams.DreamManagerService;
import android.Manifest;
import android.content.BroadcastReceiver;
@@ -46,13 +47,11 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.service.dreams.Dream;
-import android.service.dreams.IDreamManager;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -100,14 +99,12 @@ 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: dream ended
- private static final int DIRTY_DREAM_ENDED = 1 << 9;
// 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.
private static final int WAKEFULNESS_ASLEEP = 0;
// Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep().
- // When the user activity timeout expires, the device may start napping.
+ // When the user activity timeout expires, the device may start napping or go to sleep.
private static final int WAKEFULNESS_AWAKE = 1;
// Wakefulness: The device is napping. It is deciding whether to dream or go to sleep
// but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which
@@ -149,7 +146,7 @@ public final class PowerManagerService extends IPowerManager.Stub
private Notifier mNotifier;
private DisplayPowerController mDisplayPowerController;
private SettingsObserver mSettingsObserver;
- private IDreamManager mDreamManager;
+ private DreamManagerService mDreamManager;
private LightsService.Light mAttentionLight;
private final Object mLock = new Object();
@@ -335,9 +332,10 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
- public void systemReady(TwilightService twilight) {
+ public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
synchronized (mLock) {
mSystemReady = true;
+ mDreamManager = dreamManager;
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
@@ -365,10 +363,7 @@ public final class PowerManagerService extends IPowerManager.Stub
mContext.registerReceiver(new BootCompletedReceiver(), filter, null, mHandler);
filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DOCK_EVENT);
- mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
-
- filter = new IntentFilter();
+ filter.addAction(Dream.ACTION_DREAMING_STARTED);
filter.addAction(Dream.ACTION_DREAMING_STOPPED);
mContext.registerReceiver(new DreamReceiver(), filter, null, mHandler);
@@ -887,6 +882,47 @@ public final class PowerManagerService extends IPowerManager.Stub
return true;
}
+ @Override // Binder call
+ public void nap(long eventTime) {
+ if (eventTime > SystemClock.uptimeMillis()) {
+ throw new IllegalArgumentException("event time must not be in the future");
+ }
+
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ napInternal(eventTime);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void napInternal(long eventTime) {
+ synchronized (mLock) {
+ if (napNoUpdateLocked(eventTime)) {
+ updatePowerStateLocked();
+ }
+ }
+ }
+
+ private boolean napNoUpdateLocked(long eventTime) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime);
+ }
+
+ if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
+ || !mBootCompleted || !mSystemReady) {
+ return false;
+ }
+
+ Slog.i(TAG, "Nap time...");
+
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_NAPPING;
+ return true;
+ }
+
/**
* Updates the global power state based on dirty bits recorded in mDirty.
*
@@ -1143,11 +1179,15 @@ public final class PowerManagerService extends IPowerManager.Stub
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
- Slog.d(TAG, "updateWakefulnessLocked: Nap time...");
+ Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
+ }
+ final long time = SystemClock.uptimeMillis();
+ if (mDreamsActivateOnSleepSetting) {
+ changed = napNoUpdateLocked(time);
+ } else {
+ changed = goToSleepNoUpdateLocked(time,
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
}
- mWakefulness = WAKEFULNESS_NAPPING;
- mDirty |= DIRTY_WAKEFULNESS;
- changed = true;
}
}
return changed;
@@ -1172,8 +1212,7 @@ public final class PowerManagerService extends IPowerManager.Stub
| DIRTY_SETTINGS
| DIRTY_IS_POWERED
| DIRTY_STAY_ON
- | DIRTY_BATTERY_STATE
- | DIRTY_DREAM_ENDED)) != 0) {
+ | DIRTY_BATTERY_STATE)) != 0) {
scheduleSandmanLocked();
}
}
@@ -1210,32 +1249,15 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
- // Get the dream manager, if needed.
- if (startDreaming && mDreamManager == null) {
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService("dreams"));
- if (mDreamManager == null) {
- Slog.w(TAG, "Unable to find IDreamManager.");
- }
- }
-
// Start dreaming if needed.
// We only control the dream on the handler thread, so we don't need to worry about
// concurrent attempts to start or stop the dream.
boolean isDreaming = false;
if (mDreamManager != null) {
- try {
- isDreaming = mDreamManager.isDreaming();
- if (startDreaming && !isDreaming) {
- Slog.i(TAG, "Entering dreamland.");
- mDreamManager.dream();
- isDreaming = mDreamManager.isDreaming();
- if (!isDreaming) {
- Slog.i(TAG, "Could not enter dreamland. Sleep will be dreamless.");
- }
- }
- } catch (RemoteException ex) {
+ if (startDreaming) {
+ mDreamManager.startDream();
}
+ isDreaming = mDreamManager.isDreaming();
}
// Update dream state.
@@ -1255,18 +1277,6 @@ public final class PowerManagerService extends IPowerManager.Stub
if (!continueDreaming) {
handleDreamFinishedLocked();
}
-
- // In addition to listening for the intent, poll the sandman periodically to detect
- // when the dream has ended (as a watchdog only, ensuring our state is always correct).
- if (mWakefulness == WAKEFULNESS_DREAMING
- || mWakefulness == WAKEFULNESS_NAPPING) {
- if (!mSandmanScheduled) {
- mSandmanScheduled = true;
- Message msg = mHandler.obtainMessage(MSG_SANDMAN);
- msg.setAsynchronous(true);
- mHandler.sendMessageDelayed(msg, 5000);
- }
- }
}
// Stop dreaming if needed.
@@ -1274,26 +1284,22 @@ public final class PowerManagerService extends IPowerManager.Stub
// If so, then the power manager will have posted another message to the handler
// to take care of it later.
if (mDreamManager != null) {
- try {
- if (!continueDreaming && isDreaming) {
- Slog.i(TAG, "Leaving dreamland.");
- mDreamManager.awaken();
- }
- } catch (RemoteException ex) {
+ if (!continueDreaming) {
+ mDreamManager.stopDream();
}
}
}
/**
* Returns true if the device is allowed to dream in its current state,
- * assuming there has been no recent user activity and no wake locks are held.
+ * assuming that there was either an explicit request to nap or the user activity
+ * timeout expired and no wake locks are held.
*/
private boolean canDreamLocked() {
return mIsPowered
&& mDreamsSupportedConfig
&& mDreamsEnabledSetting
- && mDreamsActivateOnSleepSetting
- && !mBatteryService.isBatteryLow();
+ && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
}
/**
@@ -1313,7 +1319,6 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
-
/**
* Updates the display power state asynchronously.
* When the update is finished, mDisplayReady will be set to true. The display
@@ -1494,15 +1499,6 @@ public final class PowerManagerService extends IPowerManager.Stub
updatePowerStateLocked();
}
- private void handleDockStateChangedLocked(int dockState) {
- // TODO
- }
-
- private void handleDreamEndedLocked() {
- mDirty |= DIRTY_DREAM_ENDED;
- updatePowerStateLocked();
- }
-
/**
* Reboot the device immediately, passing 'reason' (may be null)
* to the underlying __reboot system call. Should not return.
@@ -1957,22 +1953,11 @@ public final class PowerManagerService extends IPowerManager.Stub
}
}
- private final class DockReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
- Intent.EXTRA_DOCK_STATE_UNDOCKED);
- handleDockStateChangedLocked(dockState);
- }
- }
- }
-
private final class DreamReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
- handleDreamEndedLocked();
+ scheduleSandmanLocked();
}
}
}
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 9dfe4a1f99c7..15d075cf5502 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -21,6 +21,8 @@
<uses-permission android:name="android.permission.REMOVE_TASKS" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
<application android:label="ActivityTest">
<activity android:name="ActivityTestMain">
<intent-filter>
@@ -31,6 +33,8 @@
<service android:name="SingleUserService"
android:singleUser="true" android:exported="true">
</service>
+ <service android:name="ServiceUserTarget">
+ </service>
<receiver android:name="UserTarget">
</receiver>
<receiver android:name="SingleUserReceiver"
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 2348e99e46eb..f0c3b2246ffb 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -16,6 +16,7 @@
package com.google.android.test.activity;
+import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
@@ -31,6 +32,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.graphics.Bitmap;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -41,6 +43,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.util.Log;
@@ -51,6 +54,9 @@ public class ActivityTestMain extends Activity {
ActivityManager mAm;
Configuration mOverrideConfig;
+ int mSecondUser;
+
+ ArrayList<ServiceConnection> mConnections = new ArrayList<ServiceConnection>();
class BroadcastResultReceiver extends BroadcastReceiver {
@Override
@@ -122,6 +128,15 @@ public class ActivityTestMain extends Activity {
applyOverrideConfiguration(mOverrideConfig);
}
}
+
+ UserManager um = (UserManager)getSystemService(Context.USER_SERVICE);
+ List<UserInfo> users = um.getUsers();
+ mSecondUser = Integer.MAX_VALUE;
+ for (UserInfo ui : users) {
+ if (ui.id != 0 && mSecondUser > ui.id) {
+ mSecondUser = ui.id;
+ }
+ }
}
@Override
@@ -148,7 +163,12 @@ public class ActivityTestMain extends Activity {
Log.i(TAG, "Service disconnected " + name);
}
};
- bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ if (bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
+ mConnections.add(conn);
+ } else {
+ Toast.makeText(ActivityTestMain.this, "Failed to bind",
+ Toast.LENGTH_LONG).show();
+ }
return true;
}
});
@@ -185,15 +205,70 @@ public class ActivityTestMain extends Activity {
return true;
}
});
- menu.add("Send to user 1!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ menu.add("Send to user 0!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent(ActivityTestMain.this, UserTarget.class);
+ sendOrderedBroadcastAsUser(intent, new UserHandle(0), null,
+ new BroadcastResultReceiver(),
+ null, Activity.RESULT_OK, null, null);
+ return true;
+ }
+ });
+ menu.add("Send to user " + mSecondUser + "!").setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
@Override public boolean onMenuItemClick(MenuItem item) {
Intent intent = new Intent(ActivityTestMain.this, UserTarget.class);
- sendOrderedBroadcastAsUser(intent, new UserHandle(1), null,
+ sendOrderedBroadcastAsUser(intent, new UserHandle(mSecondUser), null,
new BroadcastResultReceiver(),
null, Activity.RESULT_OK, null, null);
return true;
}
});
+ menu.add("Bind to user 0!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent(ActivityTestMain.this, ServiceUserTarget.class);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Service connected " + name + " " + service);
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Service disconnected " + name);
+ }
+ };
+ if (bindService(intent, conn, Context.BIND_AUTO_CREATE, 0)) {
+ mConnections.add(conn);
+ } else {
+ Toast.makeText(ActivityTestMain.this, "Failed to bind",
+ Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ });
+ menu.add("Bind to user " + mSecondUser + "!").setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ Intent intent = new Intent(ActivityTestMain.this, ServiceUserTarget.class);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Service connected " + name + " " + service);
+ }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Service disconnected " + name);
+ }
+ };
+ if (bindService(intent, conn, Context.BIND_AUTO_CREATE, mSecondUser)) {
+ mConnections.add(conn);
+ } else {
+ Toast.makeText(ActivityTestMain.this, "Failed to bind",
+ Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+ });
menu.add("Density!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override public boolean onMenuItemClick(MenuItem item) {
if (mOverrideConfig == null) {
@@ -226,6 +301,15 @@ public class ActivityTestMain extends Activity {
}
}
+ @Override
+ protected void onStop() {
+ super.onStop();
+ for (ServiceConnection conn : mConnections) {
+ unbindService(conn);
+ }
+ mConnections.clear();
+ }
+
private View scrollWrap(View view) {
ScrollView scroller = new ScrollView(this);
scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ServiceUserTarget.java b/tests/ActivityTests/src/com/google/android/test/activity/ServiceUserTarget.java
new file mode 100644
index 000000000000..a7474ec9b541
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ServiceUserTarget.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.google.android.test.activity;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.widget.Toast;
+
+public class ServiceUserTarget extends Service {
+ Binder mBinder = new Binder();
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Toast.makeText(this,
+ "Service created as user " + UserHandle.myUserId(),
+ Toast.LENGTH_LONG).show();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserService.java b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserService.java
index c40582a9c8ce..e9c340fbccd0 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserService.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserService.java
@@ -20,11 +20,21 @@ import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserHandle;
+import android.widget.Toast;
public class SingleUserService extends Service {
Binder mBinder = new Binder();
@Override
+ public void onCreate() {
+ super.onCreate();
+ Toast.makeText(this,
+ "Service created as user " + UserHandle.myUserId(),
+ Toast.LENGTH_LONG).show();
+ }
+
+ @Override
public IBinder onBind(Intent intent) {
return mBinder;
}
diff --git a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
index 4715d6ef04b5..f0a2b9244a65 100644
--- a/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
+++ b/tests/RenderScriptTests/ImageProcessing/res/layout/main.xml
@@ -54,6 +54,10 @@
android:id="@+id/filterselection"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
+ <Spinner
+ android:id="@+id/spinner1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
<TextView
android:id="@+id/slider1Text"
android:layout_width="match_parent"
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
new file mode 100644
index 000000000000..292082424543
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Blend.java
@@ -0,0 +1,176 @@
+/*
+ * 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.rs.image;
+
+import java.lang.Math;
+import java.lang.Short;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptC;
+import android.renderscript.ScriptGroup;
+import android.renderscript.ScriptIntrinsicBlend;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.Spinner;
+
+public class Blend extends TestBase {
+ private ScriptIntrinsicBlend mBlend;
+ private ScriptC_blend mBlendHelper;
+ private short image1Alpha = 128;
+ private short image2Alpha = 128;
+
+ String mIntrinsicNames[];
+
+ private Allocation image1;
+ private Allocation image2;
+ private int currentIntrinsic = 0;
+
+ private AdapterView.OnItemSelectedListener mIntrinsicSpinnerListener =
+ new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ currentIntrinsic = pos;
+ runTest();
+ act.updateDisplay();
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+
+ }
+ };
+
+ public void createTest(android.content.res.Resources res) {
+ mBlend = ScriptIntrinsicBlend.create(mRS, Element.U8_4(mRS));
+ mBlendHelper = new ScriptC_blend(mRS);
+ mBlendHelper.set_alpha((short)128);
+
+ image1 = Allocation.createTyped(mRS, mInPixelsAllocation.getType());
+ image2 = Allocation.createTyped(mRS, mInPixelsAllocation2.getType());
+
+ mIntrinsicNames = new String[14];
+ mIntrinsicNames[0] = "Source";
+ mIntrinsicNames[1] = "Destination";
+ mIntrinsicNames[2] = "Source Over";
+ mIntrinsicNames[3] = "Destination Over";
+ mIntrinsicNames[4] = "Source In";
+ mIntrinsicNames[5] = "Destination In";
+ mIntrinsicNames[6] = "Source Out";
+ mIntrinsicNames[7] = "Destination Out";
+ mIntrinsicNames[8] = "Source Atop";
+ mIntrinsicNames[9] = "Destination Atop";
+ mIntrinsicNames[10] = "XOR";
+ mIntrinsicNames[11] = "Add";
+ mIntrinsicNames[12] = "Subtract";
+ mIntrinsicNames[13] = "Multiply";
+ }
+
+ public boolean onSpinner1Setup(Spinner s) {
+ s.setAdapter(new ArrayAdapter<String>(
+ act, R.layout.spinner_layout, mIntrinsicNames));
+ s.setOnItemSelectedListener(mIntrinsicSpinnerListener);
+ return true;
+ }
+
+ public boolean onBar1Setup(SeekBar b, TextView t) {
+ t.setText("Image 1 Alpha");
+ b.setMax(255);
+ b.setProgress(image1Alpha);
+ return true;
+ }
+
+ public void onBar1Changed(int progress) {
+ image1Alpha = (short)progress;
+ }
+
+ public boolean onBar2Setup(SeekBar b, TextView t) {
+ t.setText("Image 2 Alpha");
+ b.setMax(255);
+ b.setProgress(image2Alpha);
+ return true;
+ }
+
+ public void onBar2Changed(int progress) {
+ image2Alpha = (short)progress;
+ }
+
+ public void runTest() {
+ image1.copy2DRangeFrom(0, 0, mInPixelsAllocation.getType().getX(), mInPixelsAllocation.getType().getY(), mInPixelsAllocation, 0, 0);
+ image2.copy2DRangeFrom(0, 0, mInPixelsAllocation2.getType().getX(), mInPixelsAllocation2.getType().getY(), mInPixelsAllocation2, 0, 0);
+
+ mBlendHelper.set_alpha(image1Alpha);
+ mBlendHelper.forEach_setImageAlpha(image1);
+
+ mBlendHelper.set_alpha(image2Alpha);
+ mBlendHelper.forEach_setImageAlpha(image2);
+
+ switch (currentIntrinsic) {
+ case 0:
+ mBlend.forEachSrc(image1, image2);
+ break;
+ case 1:
+ mBlend.forEachDst(image1, image2);
+ break;
+ case 2:
+ mBlend.forEachSrcOver(image1, image2);
+ break;
+ case 3:
+ mBlend.forEachDstOver(image1, image2);
+ break;
+ case 4:
+ mBlend.forEachSrcIn(image1, image2);
+ break;
+ case 5:
+ mBlend.forEachDstIn(image1, image2);
+ break;
+ case 6:
+ mBlend.forEachSrcOut(image1, image2);
+ break;
+ case 7:
+ mBlend.forEachDstOut(image1, image2);
+ break;
+ case 8:
+ mBlend.forEachSrcAtop(image1, image2);
+ break;
+ case 9:
+ mBlend.forEachDstAtop(image1, image2);
+ break;
+ case 10:
+ mBlend.forEachXor(image1, image2);
+ break;
+ case 11:
+ mBlend.forEachAdd(image1, image2);
+ break;
+ case 12:
+ mBlend.forEachSubtract(image1, image2);
+ break;
+ case 13:
+ mBlend.forEachMultiply(image1, image2);
+ break;
+ }
+
+ mOutPixelsAllocation.copy2DRangeFrom(0, 0, image2.getType().getX(), image2.getType().getY(), image2, 0, 0);
+ }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index a8462e6e6449..db0ef787a96e 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -55,9 +55,11 @@ public class ImageProcessingActivity extends Activity
private final String RESULT_FILE = "image_processing_result.csv";
Bitmap mBitmapIn;
+ Bitmap mBitmapIn2;
Bitmap mBitmapOut;
String mTestNames[];
+ private Spinner mSpinner;
private SeekBar mBar1;
private SeekBar mBar2;
private SeekBar mBar3;
@@ -81,6 +83,10 @@ public class ImageProcessingActivity extends Activity
private TestBase mTest;
+ public void updateDisplay() {
+ mTest.updateBitmap(mBitmapOut);
+ mDisplayView.invalidate();
+ }
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
@@ -98,8 +104,7 @@ public class ImageProcessingActivity extends Activity
}
mTest.runTest();
- mTest.updateBitmap(mBitmapOut);
- mDisplayView.invalidate();
+ updateDisplay();
}
}
@@ -110,6 +115,9 @@ public class ImageProcessingActivity extends Activity
}
void setupBars() {
+ mSpinner.setVisibility(View.VISIBLE);
+ mTest.onSpinner1Setup(mSpinner);
+
mBar1.setVisibility(View.VISIBLE);
mText1.setVisibility(View.VISIBLE);
mTest.onBar1Setup(mBar1, mText1);
@@ -221,19 +229,21 @@ public class ImageProcessingActivity extends Activity
case 27:
mTest = new Mandelbrot();
break;
+ case 28:
+ mTest = new Blend();
+ break;
}
- mTest.createBaseTest(this, mBitmapIn);
+ mTest.createBaseTest(this, mBitmapIn, mBitmapIn2);
setupBars();
mTest.runTest();
- mTest.updateBitmap(mBitmapOut);
- mDisplayView.invalidate();
+ updateDisplay();
mBenchmarkResult.setText("Result: not run");
}
void setupTests() {
- mTestNames = new String[28];
+ mTestNames = new String[29];
mTestNames[0] = "Levels Vec3 Relaxed";
mTestNames[1] = "Levels Vec4 Relaxed";
mTestNames[2] = "Levels Vec3 Full";
@@ -262,6 +272,7 @@ public class ImageProcessingActivity extends Activity
mTestNames[25] = "Convolve 5x5";
mTestNames[26] = "Intrinsics Convolve 5x5";
mTestNames[27] = "Mandelbrot";
+ mTestNames[28] = "Intrinsics Blend";
mTestSpinner.setAdapter(new ArrayAdapter<String>(
this, R.layout.spinner_layout, mTestNames));
@@ -284,6 +295,7 @@ public class ImageProcessingActivity extends Activity
setContentView(R.layout.main);
mBitmapIn = loadBitmap(R.drawable.img1600x1067);
+ mBitmapIn2 = loadBitmap(R.drawable.img1600x1067b);
mBitmapOut = loadBitmap(R.drawable.img1600x1067);
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
@@ -291,6 +303,8 @@ public class ImageProcessingActivity extends Activity
mDisplayView = (ImageView) findViewById(R.id.display);
mDisplayView.setImageBitmap(mBitmapOut);
+ mSpinner = (Spinner) findViewById(R.id.spinner1);
+
mBar1 = (SeekBar) findViewById(R.id.slider1);
mBar2 = (SeekBar) findViewById(R.id.slider2);
mBar3 = (SeekBar) findViewById(R.id.slider3);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
index 6885181535ea..8009daae900d 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/TestBase.java
@@ -36,14 +36,18 @@ import android.widget.TextView;
import android.view.View;
import android.util.Log;
import java.lang.Math;
+import android.widget.Spinner;
public class TestBase {
protected final String TAG = "Img";
protected RenderScript mRS;
protected Allocation mInPixelsAllocation;
+ protected Allocation mInPixelsAllocation2;
protected Allocation mOutPixelsAllocation;
+ protected ImageProcessingActivity act;
+
// Override to use UI elements
public void onBar1Changed(int progress) {
}
@@ -84,11 +88,20 @@ public class TestBase {
return false;
}
- public final void createBaseTest(ImageProcessingActivity act, Bitmap b) {
+ public boolean onSpinner1Setup(Spinner s) {
+ s.setVisibility(View.INVISIBLE);
+ return false;
+ }
+
+ public final void createBaseTest(ImageProcessingActivity ipact, Bitmap b, Bitmap b2) {
+ act = ipact;
mRS = RenderScript.create(act);
mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
+ mInPixelsAllocation2 = Allocation.createFromBitmap(mRS, b2,
+ Allocation.MipmapControl.MIPMAP_NONE,
+ Allocation.USAGE_SCRIPT);
mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
new file mode 100644
index 000000000000..87b56f771b22
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/blend.rs
@@ -0,0 +1,24 @@
+// Copyright (C) 2011 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.
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+
+uchar alpha = 0x0;
+
+void setImageAlpha(uchar4 *v_out, uint32_t x, uint32_t y) {
+ v_out->rgba = convert_uchar4((convert_uint4(v_out->rgba) * alpha) >> (uint4)8);
+ v_out->a = alpha;
+}
+
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 9c2e1b9127f1..77168f948640 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1946,7 +1946,7 @@ static status_t writeTextLayoutClasses(
const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
fprintf(fp,
- "int styleable.%s_%s %d\n",
+ "int styleable %s_%s %d\n",
nclassName.string(),
String8(name).string(), (int)pos);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 0c85204b581c..0cf0f21ae0a8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -60,6 +60,11 @@ public class BridgePowerManager implements IPowerManager {
}
@Override
+ public void nap(long arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ @Override
public void preventScreenOn(boolean arg0) throws RemoteException {
// pass for now.
}