Merge "Print spooler UI polish and bug fixes." into lmp-dev
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 9dc9766..47f72a8 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -367,6 +367,10 @@
throw new IllegalArgumentException("Unrecognized outline?");
}
+ public boolean hasShadow() {
+ return nHasShadow(mNativeRenderNode);
+ }
+
/**
* Enables or disables clipping to the outline.
*
@@ -861,6 +865,7 @@
float alpha);
private static native boolean nSetOutlineEmpty(long renderNode);
private static native boolean nSetOutlineNone(long renderNode);
+ private static native boolean nHasShadow(long renderNode);
private static native boolean nSetClipToOutline(long renderNode, boolean clipToOutline);
private static native boolean nSetRevealClip(long renderNode,
boolean shouldClip, float x, float y, float radius);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 92ad4e8..770e78c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10224,6 +10224,7 @@
*
* @return true if the content in this view might overlap, false otherwise.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public boolean hasOverlappingRendering() {
return true;
}
@@ -10926,6 +10927,17 @@
invalidateViewProperty(false, false);
}
+ /**
+ * HierarchyViewer only
+ *
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "drawing")
+ public boolean hasShadow() {
+ return mRenderNode.hasShadow();
+ }
+
+
/** @hide */
public void setRevealClip(boolean shouldClip, float x, float y, float radius) {
mRenderNode.setRevealClip(shouldClip, x, y, radius);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 974fe4e..ac1b6a9 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3301,6 +3301,7 @@
* @return True if the group's children will be clipped to their bounds,
* false otherwise.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public boolean getClipChildren() {
return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
}
@@ -3349,6 +3350,7 @@
*
* @attr ref android.R.styleable#ViewGroup_clipToPadding
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public boolean getClipToPadding() {
return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 949f4ff..050037e 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -173,6 +173,12 @@
return true;
}
+static jboolean android_view_RenderNode_hasShadow(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr) {
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ return renderNode->stagingProperties().hasShadow();
+}
+
static jboolean android_view_RenderNode_setClipToOutline(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -491,6 +497,7 @@
{ "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
{ "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty },
{ "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone },
+ { "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow },
{ "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline },
{ "nSetRevealClip", "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip },
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 0c8d07f..46eeb6a 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -569,6 +569,10 @@
return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
}
+ bool hasShadow() const {
+ return getZ() >= 0.0f && getOutline().getPath() != NULL;
+ }
+
private:
// Rendering properties
struct PrimitiveFields {
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
index a7c5e85..ec8307f 100644
--- a/libs/hwui/RenderState.cpp
+++ b/libs/hwui/RenderState.cpp
@@ -38,6 +38,7 @@
}
void RenderState::onGLContextDestroyed() {
+ AutoMutex _lock(mLayerLock);
if (CC_UNLIKELY(!mActiveLayers.empty())) {
mCaches->dumpMemoryUsage();
for (std::set<renderthread::CanvasContext*>::iterator cit = mRegisteredContexts.begin();
@@ -51,6 +52,13 @@
}
context->mRootRenderNode->debugDumpLayers(" ");
}
+
+ for (std::set<const Layer*>::iterator lit = mActiveLayers.begin();
+ lit != mActiveLayers.end(); lit++) {
+ const Layer* layer = *(lit);
+ ALOGD("Layer %p, fbo %d, buildlayered %d",
+ layer, layer->getFbo(), layer->wasBuildLayered);
+ }
LOG_ALWAYS_FATAL("layers have survived gl context destruction");
}
}
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
index c7ab197..74bafca 100644
--- a/libs/hwui/RenderState.h
+++ b/libs/hwui/RenderState.h
@@ -19,6 +19,7 @@
#include <set>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <utils/Mutex.h>
#include <private/hwui/DrawGlInfo.h>
@@ -52,9 +53,11 @@
void debugOverdraw(bool enable, bool clear);
void registerLayer(const Layer* layer) {
+ AutoMutex _lock(mLayerLock);
mActiveLayers.insert(layer);
}
void unregisterLayer(const Layer* layer) {
+ AutoMutex _lock(mLayerLock);
mActiveLayers.erase(layer);
}
@@ -83,6 +86,7 @@
GLsizei mViewportWidth;
GLsizei mViewportHeight;
GLuint mFramebuffer;
+ Mutex mLayerLock;
};
} /* namespace uirenderer */
diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java
index 2095152..59d50bd 100644
--- a/services/core/java/com/android/server/NativeDaemonEvent.java
+++ b/services/core/java/com/android/server/NativeDaemonEvent.java
@@ -201,20 +201,16 @@
}
while (current < length) {
// find the end of the word
- if (quoted) {
- wordEnd = current;
- while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) {
- if (rawEvent.charAt(wordEnd - 1) != '\\') {
- break;
- } else {
- wordEnd++; // skip this escaped quote and keep looking
- }
+ char terminator = quoted ? '\"' : ' ';
+ wordEnd = current;
+ while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) {
+ if (rawEvent.charAt(wordEnd) == '\\') {
+ // skip the escaped char
+ ++wordEnd;
}
- } else {
- wordEnd = rawEvent.indexOf(' ', current);
+ ++wordEnd;
}
- // if we didn't find the end-o-word token, take the rest of the string
- if (wordEnd == -1) wordEnd = length;
+ if (wordEnd > length) wordEnd = length;
String word = rawEvent.substring(current, wordEnd);
current += word.length();
if (!quoted) {
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index cf7e65c..cb1748d 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -397,8 +397,7 @@
break;
case NsdManager.NATIVE_DAEMON_EVENT:
NativeEvent event = (NativeEvent) msg.obj;
- if (!handleNativeEvent(event.code, event.raw,
- NativeDaemonEvent.unescapeArgs(event.raw))) {
+ if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
result = NOT_HANDLED;
}
break;
@@ -474,8 +473,14 @@
case NativeResponseCode.SERVICE_RESOLVED:
/* NNN resolveId fullName hostName port txtlen txtdata */
if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
- int index = cooked[2].indexOf(".");
- if (index == -1) {
+ int index = 0;
+ while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
+ if (cooked[2].charAt(index) == '\\') {
+ ++index;
+ }
+ ++index;
+ }
+ if (index >= cooked[2].length()) {
Slog.e(TAG, "Invalid service found " + raw);
break;
}
@@ -483,6 +488,8 @@
String rest = cooked[2].substring(index);
String type = rest.replace(".local.", "");
+ name = unescape(name);
+
clientInfo.mResolvedService.setServiceName(name);
clientInfo.mResolvedService.setServiceType(type);
clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
@@ -541,6 +548,30 @@
}
}
+ private String unescape(String s) {
+ StringBuilder sb = new StringBuilder(s.length());
+ for (int i = 0; i < s.length(); ++i) {
+ char c = s.charAt(i);
+ if (c == '\\') {
+ if (++i >= s.length()) {
+ Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ break;
+ }
+ c = s.charAt(i);
+ if (c != '.' && c != '\\') {
+ if (i + 2 >= s.length()) {
+ Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
+ break;
+ }
+ c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
+ i += 2;
+ }
+ }
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
private NativeDaemonConnector mNativeConnector;
private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
@@ -625,10 +656,12 @@
private class NativeEvent {
final int code;
final String raw;
+ final String[] cooked;
- NativeEvent(int code, String raw) {
+ NativeEvent(int code, String raw, String[] cooked) {
this.code = code;
this.raw = raw;
+ this.cooked = cooked;
}
}
@@ -644,7 +677,7 @@
public boolean onEvent(int code, String raw, String[] cooked) {
// TODO: NDC translates a message to a callback, we could enhance NDC to
// directly interact with a state machine through messages
- NativeEvent event = new NativeEvent(code, raw);
+ NativeEvent event = new NativeEvent(code, raw, cooked);
mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
return true;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index aea00da..7b4270b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3783,21 +3783,25 @@
} else {
pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId);
}
- if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
- if (numMatch == permissions.length) {
- pi.requestedPermissions = permissions;
- } else {
- pi.requestedPermissions = new String[numMatch];
- numMatch = 0;
- for (int i=0; i<permissions.length; i++) {
- if (tmp[i]) {
- pi.requestedPermissions[numMatch] = permissions[i];
- numMatch++;
+ // The above might return null in cases of uninstalled apps or install-state
+ // skew across users/profiles.
+ if (pi != null) {
+ if ((flags&PackageManager.GET_PERMISSIONS) == 0) {
+ if (numMatch == permissions.length) {
+ pi.requestedPermissions = permissions;
+ } else {
+ pi.requestedPermissions = new String[numMatch];
+ numMatch = 0;
+ for (int i=0; i<permissions.length; i++) {
+ if (tmp[i]) {
+ pi.requestedPermissions[numMatch] = permissions[i];
+ numMatch++;
+ }
}
}
}
+ list.add(pi);
}
- list.add(pi);
}
@Override