diff options
29 files changed, 727 insertions, 187 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 16d4ad6..42c9d34 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1131,6 +1131,19 @@ public final class Pm { } private void runClear() { + int userId = 0; + String option = nextOption(); + if (option != null && option.equals("--user")) { + String optionData = nextOptionData(); + if (optionData == null || !isNumber(optionData)) { + System.err.println("Error: no USER_ID specified"); + showUsage(); + return; + } else { + userId = Integer.parseInt(optionData); + } + } + String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package specified"); @@ -1140,8 +1153,7 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { - // XXX TO DO: add user arg - if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, 0)) { + if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId)) { System.err.println("Failed"); } @@ -1179,7 +1191,7 @@ public final class Pm { return "unknown"; } - private boolean isNumber(String s) { + private static boolean isNumber(String s) { try { Integer.parseInt(s); } catch (NumberFormatException nfe) { @@ -1452,7 +1464,7 @@ public final class Pm { System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]"); System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); - System.err.println(" pm clear PACKAGE"); + System.err.println(" pm clear [--user USER_ID] PACKAGE"); System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index de4dd88..affeb90 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -283,6 +283,8 @@ public class SearchManagerService extends ISearchManager.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); synchronized (mSearchables) { for (int i = 0; i < mSearchables.size(); i++) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 946965b..158e0c0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -10515,9 +10515,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread.</p> * - * <p>This method can be invoked from outside of the UI thread - * only when this View is attached to a window.</p> - * * @param action The Runnable that will be executed. * * @return Returns true if the Runnable was successfully placed in to the @@ -10542,9 +10539,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * after the specified amount of time elapses. * The runnable will be run on the user interface thread.</p> * - * <p>This method can be invoked from outside of the UI thread - * only when this View is attached to a window.</p> - * * @param action The Runnable that will be executed. * @param delayMillis The delay (in milliseconds) until the Runnable * will be executed. @@ -10573,9 +10567,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * <p>Causes the Runnable to execute on the next animation time step. * The runnable will be run on the user interface thread.</p> * - * <p>This method can be invoked from outside of the UI thread - * only when this View is attached to a window.</p> - * * @param action The Runnable that will be executed. * * @see #postOnAnimationDelayed @@ -10597,9 +10588,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * after the specified amount of time elapses. * The runnable will be run on the user interface thread.</p> * - * <p>This method can be invoked from outside of the UI thread - * only when this View is attached to a window.</p> - * * @param action The Runnable that will be executed. * @param delayMillis The delay (in milliseconds) until the Runnable * will be executed. @@ -10621,9 +10609,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * <p>Removes the specified Runnable from the message queue.</p> * - * <p>This method can be invoked from outside of the UI thread - * only when this View is attached to a window.</p> - * * @param action The Runnable to remove from the message handling queue * * @return true if this view could ask the Handler to remove the Runnable, diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index b3c679c..751ed7c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -367,6 +367,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean mSingleLine; private int mDesiredHeightAtMeasure = -1; private boolean mIncludePad = true; + private int mDeferScroll = -1; // tmp primitives, so we don't alloc them on each draw private Rect mTempRect; @@ -6317,6 +6318,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + if (mDeferScroll >= 0) { + int curs = mDeferScroll; + mDeferScroll = -1; + bringPointIntoView(curs); + } if (changed && mEditor != null) mEditor.invalidateTextDisplayList(); } @@ -6399,6 +6405,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * This has to be called after layout. Returns true if anything changed. */ public boolean bringPointIntoView(int offset) { + if (isLayoutRequested()) { + mDeferScroll = offset; + return false; + } boolean changed = false; Layout layout = isShowingHint() ? mHintLayout: mLayout; @@ -7108,13 +7118,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener registerForPreDraw(); } + checkForResize(); + if (curs >= 0) { mHighlightPathBogus = true; if (mEditor != null) mEditor.makeBlink(); bringPointIntoView(curs); } - - checkForResize(); } /** @@ -7161,6 +7171,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (oldStart >= 0 || newStart >= 0) { invalidateCursor(Selection.getSelectionStart(buf), oldStart, newStart); + checkForResize(); registerForPreDraw(); if (mEditor != null) mEditor.makeBlink(); } diff --git a/core/res/res/layout-land/keyguard_status_area.xml b/core/res/res/layout-land/keyguard_status_area.xml index 78bf931..f562d9f 100644 --- a/core/res/res/layout-land/keyguard_status_area.xml +++ b/core/res/res/layout-land/keyguard_status_area.xml @@ -41,6 +41,8 @@ <TextView android:id="@+id/alarm_status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="28dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -53,6 +55,8 @@ <TextView android:id="@+id/owner_info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -64,6 +68,8 @@ <TextView android:id="@+id/status1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -75,6 +81,8 @@ <TextView android:id="@+id/status_security_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="right" android:layout_marginTop="12dp" diff --git a/core/res/res/layout-port/keyguard_status_area.xml b/core/res/res/layout-port/keyguard_status_area.xml index 00aac7b..e0a49dc 100644 --- a/core/res/res/layout-port/keyguard_status_area.xml +++ b/core/res/res/layout-port/keyguard_status_area.xml @@ -56,6 +56,8 @@ <TextView android:id="@+id/owner_info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -67,6 +69,8 @@ <TextView android:id="@+id/status1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -78,6 +82,8 @@ <TextView android:id="@+id/status_security_message" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" diff --git a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml b/core/res/res/layout-sw600dp-port/keyguard_status_area.xml index 679aebd..f21254a 100644 --- a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml +++ b/core/res/res/layout-sw600dp-port/keyguard_status_area.xml @@ -41,6 +41,8 @@ <TextView android:id="@+id/alarm_status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="28dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -53,6 +55,8 @@ <TextView android:id="@+id/owner_info" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" @@ -64,6 +68,8 @@ <TextView android:id="@+id/status1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_gravity="end" android:layout_marginTop="4dp" android:layout_marginEnd="@dimen/kg_status_line_font_right_margin" diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index cc536f2..2b50091 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2427,17 +2427,39 @@ status_t OpenGLRenderer::drawOval(float left, float top, float right, float bott } status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { - if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone; + float startAngle, float sweepAngle, bool useCenter, SkPaint* p) { + if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) { + return DrawGlInfo::kStatusDone; + } if (fabs(sweepAngle) >= 360.0f) { - return drawOval(left, top, right, bottom, paint); + return drawOval(left, top, right, bottom, p); } - mCaches.activeTexture(0); - const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top, - startAngle, sweepAngle, useCenter, paint); - return drawShape(left, top, texture, paint); + // TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180) + if (p->getStyle() != SkPaint::kStroke_Style || p->getPathEffect() != 0 || p->getStrokeCap() != SkPaint::kButt_Cap) { + mCaches.activeTexture(0); + const PathTexture* texture = mCaches.arcShapeCache.getArc(right - left, bottom - top, + startAngle, sweepAngle, useCenter, p); + return drawShape(left, top, texture, p); + } + + SkRect rect = SkRect::MakeLTRB(left, top, right, bottom); + if (p->getStyle() == SkPaint::kStrokeAndFill_Style) { + rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2); + } + + SkPath path; + if (useCenter) { + path.moveTo(rect.centerX(), rect.centerY()); + } + path.arcTo(rect, startAngle, sweepAngle, !useCenter); + if (useCenter) { + path.close(); + } + drawConvexPath(path, p); + + return DrawGlInfo::kStatusDrew; } // See SkPaintDefaults.h diff --git a/libs/hwui/PathRenderer.cpp b/libs/hwui/PathRenderer.cpp index 58d6cb8..dd13d79 100644 --- a/libs/hwui/PathRenderer.cpp +++ b/libs/hwui/PathRenderer.cpp @@ -80,11 +80,24 @@ inline void copyAlphaVertex(AlphaVertex* destPtr, const AlphaVertex* srcPtr) { * * Note that we can't add and normalize the two vectors, that would result in a rectangle having an * offset of (sqrt(2)/2, sqrt(2)/2) at each corner, instead of (1, 1) + * + * NOTE: assumes angles between normals 90 degrees or less */ inline vec2 totalOffsetFromNormals(const vec2& normalA, const vec2& normalB) { return (normalA + normalB) / (1 + fabs(normalA.dot(normalB))); } +inline void scaleOffsetForStrokeWidth(vec2& offset, float halfStrokeWidth, + float inverseScaleX, float inverseScaleY) { + if (halfStrokeWidth == 0.0f) { + // hairline - compensate for scale + offset.x *= 0.5f * inverseScaleX; + offset.y *= 0.5f * inverseScaleY; + } else { + offset *= halfStrokeWidth; + } +} + void getFillVerticesFromPerimeter(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) { Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size()); @@ -119,13 +132,7 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS nextNormal.normalize(); vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); - if (halfStrokeWidth == 0.0f) { - // hairline - compensate for scale - totalOffset.x *= 0.5f * inverseScaleX; - totalOffset.y *= 0.5f * inverseScaleY; - } else { - totalOffset *= halfStrokeWidth; - } + scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); Vertex::set(&buffer[currentIndex++], current->position[0] + totalOffset.x, @@ -145,6 +152,55 @@ void getStrokeVerticesFromPerimeter(const Vector<Vertex>& perimeter, float halfS copyVertex(&buffer[currentIndex++], &buffer[1]); } +void getStrokeVerticesFromUnclosedVertices(const Vector<Vertex>& vertices, float halfStrokeWidth, + VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { + Vertex* buffer = vertexBuffer.alloc<Vertex>(vertices.size() * 2); + + int currentIndex = 0; + const Vertex* current = &(vertices[0]); + vec2 lastNormal; + for (unsigned int i = 0; i < vertices.size() - 1; i++) { + const Vertex* next = &(vertices[i + 1]); + vec2 nextNormal(next->position[1] - current->position[1], + current->position[0] - next->position[0]); + nextNormal.normalize(); + + vec2 totalOffset; + if (i == 0) { + totalOffset = nextNormal; + } else { + totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); + } + scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); + + Vertex::set(&buffer[currentIndex++], + current->position[0] + totalOffset.x, + current->position[1] + totalOffset.y); + + Vertex::set(&buffer[currentIndex++], + current->position[0] - totalOffset.x, + current->position[1] - totalOffset.y); + + current = next; + lastNormal = nextNormal; + } + + vec2 totalOffset = lastNormal; + scaleOffsetForStrokeWidth(totalOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); + + Vertex::set(&buffer[currentIndex++], + current->position[0] + totalOffset.x, + current->position[1] + totalOffset.y); + Vertex::set(&buffer[currentIndex++], + current->position[0] - totalOffset.x, + current->position[1] - totalOffset.y); +#if VERTEX_DEBUG + for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { + ALOGD("point at %f %f", buffer[i].position[0], buffer[i].position[1]); + } +#endif +} + void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2); @@ -202,11 +258,167 @@ void getFillVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, VertexBuffe #if VERTEX_DEBUG for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { - ALOGD("point at %f %f", buffer[i].position[0], buffer[i].position[1]); + ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); + } +#endif +} + + +void getStrokeVerticesFromUnclosedVerticesAA(const Vector<Vertex>& vertices, float halfStrokeWidth, + VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { + AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * vertices.size() + 2); + + // avoid lines smaller than hairline since they break triangle based sampling. instead reducing + // alpha value (TODO: support different X/Y scale) + float maxAlpha = 1.0f; + if (halfStrokeWidth != 0 && inverseScaleX == inverseScaleY && + halfStrokeWidth * inverseScaleX < 0.5f) { + maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX; + halfStrokeWidth = 0.0f; + } + + // there is no outer/inner here, using them for consistency with below approach + int offset = 2 * (vertices.size() - 2); + int currentAAOuterIndex = 2; + int currentAAInnerIndex = 2 * offset + 5; // reversed + int currentStrokeIndex = currentAAInnerIndex + 7; + + const Vertex* last = &(vertices[0]); + const Vertex* current = &(vertices[1]); + vec2 lastNormal(current->position[1] - last->position[1], + last->position[0] - current->position[0]); + lastNormal.normalize(); + + { + // start cap + vec2 totalOffset = lastNormal; + vec2 AAOffset = totalOffset; + AAOffset.x *= 0.5f * inverseScaleX; + AAOffset.y *= 0.5f * inverseScaleY; + + vec2 innerOffset = totalOffset; + scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); + vec2 outerOffset = innerOffset + AAOffset; + innerOffset -= AAOffset; + + // TODO: support square cap by changing this offset to incorporate halfStrokeWidth + vec2 capAAOffset(AAOffset.y, -AAOffset.x); + AlphaVertex::set(&buffer[0], + last->position[0] + outerOffset.x + capAAOffset.x, + last->position[1] + outerOffset.y + capAAOffset.y, + 0.0f); + AlphaVertex::set(&buffer[1], + last->position[0] + innerOffset.x - capAAOffset.x, + last->position[1] + innerOffset.y - capAAOffset.y, + maxAlpha); + + AlphaVertex::set(&buffer[2 * offset + 6], + last->position[0] - outerOffset.x + capAAOffset.x, + last->position[1] - outerOffset.y + capAAOffset.y, + 0.0f); + AlphaVertex::set(&buffer[2 * offset + 7], + last->position[0] - innerOffset.x - capAAOffset.x, + last->position[1] - innerOffset.y - capAAOffset.y, + maxAlpha); + copyAlphaVertex(&buffer[2 * offset + 8], &buffer[0]); + copyAlphaVertex(&buffer[2 * offset + 9], &buffer[1]); + copyAlphaVertex(&buffer[2 * offset + 10], &buffer[1]); // degenerate tris (the only two!) + copyAlphaVertex(&buffer[2 * offset + 11], &buffer[2 * offset + 7]); + } + + for (unsigned int i = 1; i < vertices.size() - 1; i++) { + const Vertex* next = &(vertices[i + 1]); + vec2 nextNormal(next->position[1] - current->position[1], + current->position[0] - next->position[0]); + nextNormal.normalize(); + + vec2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal); + vec2 AAOffset = totalOffset; + AAOffset.x *= 0.5f * inverseScaleX; + AAOffset.y *= 0.5f * inverseScaleY; + + vec2 innerOffset = totalOffset; + scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); + vec2 outerOffset = innerOffset + AAOffset; + innerOffset -= AAOffset; + + AlphaVertex::set(&buffer[currentAAOuterIndex++], + current->position[0] + outerOffset.x, + current->position[1] + outerOffset.y, + 0.0f); + AlphaVertex::set(&buffer[currentAAOuterIndex++], + current->position[0] + innerOffset.x, + current->position[1] + innerOffset.y, + maxAlpha); + + AlphaVertex::set(&buffer[currentStrokeIndex++], + current->position[0] + innerOffset.x, + current->position[1] + innerOffset.y, + maxAlpha); + AlphaVertex::set(&buffer[currentStrokeIndex++], + current->position[0] - innerOffset.x, + current->position[1] - innerOffset.y, + maxAlpha); + + AlphaVertex::set(&buffer[currentAAInnerIndex--], + current->position[0] - innerOffset.x, + current->position[1] - innerOffset.y, + maxAlpha); + AlphaVertex::set(&buffer[currentAAInnerIndex--], + current->position[0] - outerOffset.x, + current->position[1] - outerOffset.y, + 0.0f); + + last = current; + current = next; + lastNormal = nextNormal; + } + + { + // end cap + vec2 totalOffset = lastNormal; + vec2 AAOffset = totalOffset; + AAOffset.x *= 0.5f * inverseScaleX; + AAOffset.y *= 0.5f * inverseScaleY; + + vec2 innerOffset = totalOffset; + scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); + vec2 outerOffset = innerOffset + AAOffset; + innerOffset -= AAOffset; + + // TODO: support square cap by changing this offset to incorporate halfStrokeWidth + vec2 capAAOffset(-AAOffset.y, AAOffset.x); + + AlphaVertex::set(&buffer[offset + 2], + current->position[0] + outerOffset.x + capAAOffset.x, + current->position[1] + outerOffset.y + capAAOffset.y, + 0.0f); + AlphaVertex::set(&buffer[offset + 3], + current->position[0] + innerOffset.x - capAAOffset.x, + current->position[1] + innerOffset.y - capAAOffset.y, + maxAlpha); + + AlphaVertex::set(&buffer[offset + 4], + current->position[0] - outerOffset.x + capAAOffset.x, + current->position[1] - outerOffset.y + capAAOffset.y, + 0.0f); + AlphaVertex::set(&buffer[offset + 5], + current->position[0] - innerOffset.x - capAAOffset.x, + current->position[1] - innerOffset.y - capAAOffset.y, + maxAlpha); + + copyAlphaVertex(&buffer[vertexBuffer.getSize() - 2], &buffer[offset + 3]); + copyAlphaVertex(&buffer[vertexBuffer.getSize() - 1], &buffer[offset + 5]); + } + +#if VERTEX_DEBUG + for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { + ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); } #endif } + void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float halfStrokeWidth, VertexBuffer& vertexBuffer, float inverseScaleX, float inverseScaleY) { AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8); @@ -242,13 +454,7 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal AAOffset.y *= 0.5f * inverseScaleY; vec2 innerOffset = totalOffset; - if (halfStrokeWidth == 0.0f) { - // hairline! - compensate for scale - innerOffset.x *= 0.5f * inverseScaleX; - innerOffset.y *= 0.5f * inverseScaleY; - } else { - innerOffset *= halfStrokeWidth; - } + scaleOffsetForStrokeWidth(innerOffset, halfStrokeWidth, inverseScaleX, inverseScaleY); vec2 outerOffset = innerOffset + AAOffset; innerOffset -= AAOffset; @@ -296,6 +502,12 @@ void getStrokeVerticesFromPerimeterAA(const Vector<Vertex>& perimeter, float hal copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset]); copyAlphaVertex(&buffer[currentAAInnerIndex++], &buffer[2 * offset + 1]); // don't need to create last degenerate tri + +#if VERTEX_DEBUG + for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { + ALOGD("point at %f %f, alpha %f", buffer[i].position[0], buffer[i].position[1], buffer[i].alpha); + } +#endif } void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, @@ -320,7 +532,10 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, threshInvScaleY *= bounds.height() / (bounds.height() + paint->getStrokeWidth()); } } - convexPathPerimeterVertices(path, threshInvScaleX * threshInvScaleX, + + // force close if we're filling the path, since fill path expects closed perimeter. + bool forceClose = style != SkPaint::kStroke_Style; + bool wasClosed = convexPathPerimeterVertices(path, forceClose, threshInvScaleX * threshInvScaleX, threshInvScaleY * threshInvScaleY, tempVertices); if (!tempVertices.size()) { @@ -337,11 +552,22 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, if (style == SkPaint::kStroke_Style) { float halfStrokeWidth = paint->getStrokeWidth() * 0.5f; if (!isAA) { - getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer, - inverseScaleX, inverseScaleY); + if (wasClosed) { + getStrokeVerticesFromPerimeter(tempVertices, halfStrokeWidth, vertexBuffer, + inverseScaleX, inverseScaleY); + } else { + getStrokeVerticesFromUnclosedVertices(tempVertices, halfStrokeWidth, vertexBuffer, + inverseScaleX, inverseScaleY); + } + } else { - getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer, - inverseScaleX, inverseScaleY); + if (wasClosed) { + getStrokeVerticesFromPerimeterAA(tempVertices, halfStrokeWidth, vertexBuffer, + inverseScaleX, inverseScaleY); + } else { + getStrokeVerticesFromUnclosedVerticesAA(tempVertices, halfStrokeWidth, vertexBuffer, + inverseScaleX, inverseScaleY); + } } } else { // For kStrokeAndFill style, the path should be adjusted externally, as it will be treated as a fill here. @@ -354,19 +580,27 @@ void PathRenderer::convexPathVertices(const SkPath &path, const SkPaint* paint, } -void PathRenderer::convexPathPerimeterVertices(const SkPath& path, +void pushToVector(Vector<Vertex>& vertices, float x, float y) { + // TODO: make this not yuck + vertices.push(); + Vertex* newVertex = &(vertices.editArray()[vertices.size() - 1]); + Vertex::set(newVertex, x, y); +} + +bool PathRenderer::convexPathPerimeterVertices(const SkPath& path, bool forceClose, float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex>& outputVertices) { ATRACE_CALL(); - SkPath::Iter iter(path, true); - SkPoint pos; + // TODO: to support joins other than sharp miter, join vertices should be labelled in the + // perimeter, or resolved into more vertices. Reconsider forceClose-ing in that case. + SkPath::Iter iter(path, forceClose); SkPoint pts[4]; SkPath::Verb v; Vertex* newVertex = 0; while (SkPath::kDone_Verb != (v = iter.next(pts))) { switch (v) { case SkPath::kMove_Verb: - pos = pts[0]; + pushToVector(outputVertices, pts[0].x(), pts[0].y()); ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y()); break; case SkPath::kClose_Verb: @@ -377,10 +611,7 @@ void PathRenderer::convexPathPerimeterVertices(const SkPath& path, pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y()); - // TODO: make this not yuck - outputVertices.push(); - newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]); - Vertex::set(newVertex, pts[1].x(), pts[1].y()); + pushToVector(outputVertices, pts[1].x(), pts[1].y()); break; case SkPath::kQuad_Verb: ALOGV("kQuad_Verb"); @@ -403,6 +634,14 @@ void PathRenderer::convexPathPerimeterVertices(const SkPath& path, break; } } + + int size = outputVertices.size(); + if (size >= 2 && outputVertices[0].position[0] == outputVertices[size - 1].position[0] && + outputVertices[0].position[1] == outputVertices[size - 1].position[1]) { + outputVertices.pop(); + return true; + } + return false; } void PathRenderer::recursiveCubicBezierVertices( @@ -419,10 +658,7 @@ void PathRenderer::recursiveCubicBezierVertices( if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { // below thresh, draw line by adding endpoint - // TODO: make this not yuck - outputVertices.push(); - Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]); - Vertex::set(newVertex, p2x, p2y); + pushToVector(outputVertices, p2x, p2y); } else { float p1c1x = (p1x + c1x) * 0.5f; float p1c1y = (p1y + c1y) * 0.5f; @@ -463,10 +699,7 @@ void PathRenderer::recursiveQuadraticBezierVertices( if (d * d < THRESHOLD * THRESHOLD * (dx * dx * sqrInvScaleY + dy * dy * sqrInvScaleX)) { // below thresh, draw line by adding endpoint - // TODO: make this not yuck - outputVertices.push(); - Vertex* newVertex = &(outputVertices.editArray()[outputVertices.size() - 1]); - Vertex::set(newVertex, bx, by); + pushToVector(outputVertices, bx, by); } else { float acx = (ax + cx) * 0.5f; float bcx = (bx + cx) * 0.5f; diff --git a/libs/hwui/PathRenderer.h b/libs/hwui/PathRenderer.h index 28a5b90..e9f347b 100644 --- a/libs/hwui/PathRenderer.h +++ b/libs/hwui/PathRenderer.h @@ -71,10 +71,8 @@ public: const mat4 *transform, VertexBuffer& vertexBuffer); private: - static void convexPathPerimeterVertices( - const SkPath &path, - float sqrInvScaleX, float sqrInvScaleY, - Vector<Vertex> &outputVertices); + static bool convexPathPerimeterVertices(const SkPath &path, bool forceClose, + float sqrInvScaleX, float sqrInvScaleY, Vector<Vertex> &outputVertices); /* endpoints a & b, diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index f26d322..f77cbfb 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -153,11 +153,10 @@ public class AudioService extends IAudioService.Stub implements OnFinished { private static final int MSG_SET_A2DP_CONNECTION_STATE = 22; // end of messages handled under wakelock private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection - private static final int MSG_SET_FORCE_RSX_USE = 24; // force remote submix audio routing - private static final int MSG_CHECK_MUSIC_ACTIVE = 25; - private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 26; - private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 27; - private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 28; + private static final int MSG_CHECK_MUSIC_ACTIVE = 24; + private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25; + private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26; + private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27; // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be // persisted @@ -2221,13 +2220,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { on ? 1 : 0 /*arg1*/, address /*arg2*/, null/*obj*/, 0/*delay*/); - - // Note that we are currently forcing use of remote submix as soon as corresponding device - // is made available - sendMsg(mAudioHandler, MSG_SET_FORCE_RSX_USE, SENDMSG_REPLACE, - AudioSystem.FOR_MEDIA, - on ? AudioSystem.FORCE_REMOTE_SUBMIX : AudioSystem.FORCE_NONE, - null/*obj*/, 0/*delay*/); } private void onSetRsxConnectionState(int available, int address) { @@ -3320,7 +3312,6 @@ public class AudioService extends IAudioService.Stub implements OnFinished { case MSG_SET_FORCE_USE: case MSG_SET_FORCE_BT_A2DP_USE: - case MSG_SET_FORCE_RSX_USE: setForceUse(msg.arg1, msg.arg2); break; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 260ddc7..dde2979 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -360,9 +360,8 @@ public class AudioSystem public static final int FORCE_ANALOG_DOCK = 8; public static final int FORCE_DIGITAL_DOCK = 9; public static final int FORCE_NO_BT_A2DP = 10; - public static final int FORCE_REMOTE_SUBMIX = 11; - public static final int FORCE_SYSTEM_ENFORCED = 12; - private static final int NUM_FORCE_CONFIG = 13; + public static final int FORCE_SYSTEM_ENFORCED = 11; + private static final int NUM_FORCE_CONFIG = 12; public static final int FORCE_DEFAULT = FORCE_NONE; // usage for setForceUse, must match AudioSystem::force_use diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java index eca8618..ebc54b3 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java @@ -79,7 +79,7 @@ public class KeyguardHostView extends KeyguardViewBase { private boolean mEnableMenuKey; private boolean mIsVerifyUnlockOnly; private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView - private SecurityMode mCurrentSecuritySelection = SecurityMode.None; + private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid; protected Runnable mLaunchRunnable; @@ -433,7 +433,8 @@ public class KeyguardHostView extends KeyguardViewBase { */ private void showBackupSecurityScreen() { if (DEBUG) Log.d(TAG, "showBackupSecurity()"); - showSecurityScreen(mSecurityModel.getBackupSecurityMode()); + SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection); + showSecurityScreen(backup); } public boolean showNextSecurityScreenIfPresent() { @@ -543,6 +544,45 @@ public class KeyguardHostView extends KeyguardViewBase { private KeyguardStatusViewManager mKeyguardStatusViewManager; + // Used to ignore callbacks from methods that are no longer current (e.g. face unlock). + // This avoids unwanted asynchronous events from messing with the state. + private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() { + + @Override + public void userActivity(long timeout) { + } + + @Override + public void showBackupSecurity() { + } + + @Override + public void setOnDismissRunnable(Runnable runnable) { + } + + @Override + public void reportSuccessfulUnlockAttempt() { + } + + @Override + public void reportFailedUnlockAttempt() { + } + + @Override + public boolean isVerifyUnlockOnly() { + return false; + } + + @Override + public int getFailedAttempts() { + return 0; + } + + @Override + public void dismiss(boolean securityVerified) { + } + }; + @Override public void reset() { mIsVerifyUnlockOnly = false; @@ -568,9 +608,10 @@ public class KeyguardHostView extends KeyguardViewBase { } } boolean simPukFullScreen = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen); - if (view == null) { + int layoutId = getLayoutIdFor(securityMode); + if (view == null && layoutId != 0) { final LayoutInflater inflater = LayoutInflater.from(mContext); - View v = inflater.inflate(getLayoutIdFor(securityMode), this, false); + View v = inflater.inflate(layoutId, this, false); mSecurityViewContainer.addView(v); updateSecurityView(v); @@ -617,8 +658,12 @@ public class KeyguardHostView extends KeyguardViewBase { KeyguardSecurityView newView = getSecurityView(securityMode); // Emulate Activity life cycle - oldView.onPause(); + if (oldView != null) { + oldView.onPause(); + oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view + } newView.onResume(); + newView.setKeyguardCallback(mCallback); final boolean needsInput = newView.needsInput(); if (mViewMediatorCallback != null) { @@ -749,7 +794,7 @@ public class KeyguardHostView extends KeyguardViewBase { case SimPin: return R.layout.keyguard_sim_pin_view; case SimPuk: return R.layout.keyguard_sim_puk_view; default: - throw new RuntimeException("No layout for securityMode " + securityMode); + return 0; } } diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java index 3b37d56..1868507 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java @@ -86,6 +86,13 @@ public class KeyguardPasswordView extends LinearLayout mLockPatternUtils = utils; } + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + if (hasWindowFocus) { + reset(); + } + } + public void reset() { // start fresh mPasswordEntry.setText(""); @@ -191,7 +198,9 @@ public class KeyguardPasswordView extends LinearLayout } public void afterTextChanged(Editable s) { - mCallback.userActivity(0); + if (mCallback != null) { + mCallback.userActivity(0); + } } }); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java index 80282c1..59e2ca9 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java @@ -28,6 +28,7 @@ public class KeyguardSecurityModel { * @see com.android.internal.policy.impl.LockPatternKeyguardView#getUnlockMode() */ enum SecurityMode { + Invalid, // NULL state None, // No security enabled Pattern, // Unlock by drawing a pattern. Password, // Unlock by entering a password or PIN @@ -53,7 +54,7 @@ public class KeyguardSecurityModel { * Returns true if biometric unlock is installed and selected. If this returns false there is * no need to even construct the biometric unlock. */ - private boolean isBiometricUnlockEnabled() { + boolean isBiometricUnlockEnabled() { return mLockPatternUtils.usingBiometricWeak() && mLockPatternUtils.isBiometricWeakInstalled(); } @@ -128,15 +129,7 @@ public class KeyguardSecurityModel { * * @return backup method or current security mode */ - SecurityMode getBackupSecurityMode() { - SecurityMode mode = getSecurityMode(); - - // Note that getAlternateFor() cannot be called here because we want to get the backup for - // biometric unlock even if it's suppressed; it just has to be enabled. - if (isBiometricUnlockEnabled() - && (mode == SecurityMode.Password || mode == SecurityMode.Pattern)) { - mode = SecurityMode.Biometric; - } + SecurityMode getBackupSecurityMode(SecurityMode mode) { switch(mode) { case Biometric: return getSecurityMode(); diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java index 9615e71..5b85064 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java @@ -221,6 +221,7 @@ class KeyguardStatusViewManager implements SecurityMessageDisplay { mHandler.removeCallbacks(mClearSecurityMessageRunnable); mHandler.postDelayed(mClearSecurityMessageRunnable, SECURITY_MESSAGE_DURATION); } + mSecurityMessage.announceForAccessibility(mSecurityMessage.getText()); } /** diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index c18fe0e..e7e4f87 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -304,6 +304,8 @@ class AppWidgetService extends IAppWidgetService.Stub @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + // Dump the state of all the app widget providers synchronized (mAppWidgetServices) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index c5016e6..6948927 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -609,10 +609,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } /** - * Throw SecurityException if caller has neither COARSE or FINE. - * Otherwise, return the best permission. + * Returns the best permission available to the caller. */ - private String checkPermission() { + private String getBestCallingPermission() { if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { return ACCESS_FINE_LOCATION; @@ -620,9 +619,20 @@ public class LocationManagerService extends ILocationManager.Stub implements Run PackageManager.PERMISSION_GRANTED) { return ACCESS_COARSE_LOCATION; } + return null; + } - throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + - " ACCESS_FINE_LOCATION permission"); + /** + * Throw SecurityException if caller has neither COARSE or FINE. + * Otherwise, return the best permission. + */ + private String checkPermission() { + String perm = getBestCallingPermission(); + if (perm == null) { + throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + + " ACCESS_FINE_LOCATION permission"); + } + return perm; } /** @@ -635,19 +645,15 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } } - private boolean isAllowedProviderSafe(String provider) { + private String getMinimumPermissionForProvider(String provider) { if (LocationManager.GPS_PROVIDER.equals(provider) || LocationManager.PASSIVE_PROVIDER.equals(provider)) { // gps and passive providers require FINE permission - return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED; + return ACCESS_FINE_LOCATION; } else if (LocationManager.NETWORK_PROVIDER.equals(provider) || LocationManager.FUSED_PROVIDER.equals(provider)) { // network and fused providers are ok with COARSE or FINE - return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED) || - (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) - == PackageManager.PERMISSION_GRANTED); + return ACCESS_COARSE_LOCATION; } else { // mock providers LocationProviderInterface lp = mMockProviders.get(provider); @@ -656,20 +662,43 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (properties != null) { if (properties.mRequiresSatellite) { // provider requiring satellites require FINE permission - return mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED; + return ACCESS_FINE_LOCATION; } else if (properties.mRequiresNetwork || properties.mRequiresCell) { // provider requiring network and or cell require COARSE or FINE - return (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED) || - (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) - == PackageManager.PERMISSION_GRANTED); + return ACCESS_COARSE_LOCATION; } } } } - return false; + return null; + } + + private boolean isPermissionSufficient(String perm, String minPerm) { + if (ACCESS_FINE_LOCATION.equals(minPerm)) { + return ACCESS_FINE_LOCATION.equals(perm); + } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { + return ACCESS_FINE_LOCATION.equals(perm) || + ACCESS_COARSE_LOCATION.equals(perm); + } else { + return false; + } + } + + private void checkPermissionForProvider(String perm, String provider) { + String minPerm = getMinimumPermissionForProvider(provider); + if (!isPermissionSufficient(perm, minPerm)) { + if (ACCESS_FINE_LOCATION.equals(minPerm)) { + throw new SecurityException("Location provider \"" + provider + + "\" requires ACCESS_FINE_LOCATION permission."); + } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { + throw new SecurityException("Location provider \"" + provider + + "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); + } else { + throw new SecurityException("Insufficient permission for location provider \"" + + provider + "\"."); + } + } } /** @@ -703,6 +732,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public List<String> getProviders(Criteria criteria, boolean enabledOnly) { ArrayList<String> out; + String perm = getBestCallingPermission(); int callingUserId = UserHandle.getCallingUserId(); long identity = Binder.clearCallingIdentity(); try { @@ -713,7 +743,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (LocationManager.FUSED_PROVIDER.equals(name)) { continue; } - if (isAllowedProviderSafe(name)) { + if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) { if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) { continue; } @@ -980,26 +1010,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run return receiver; } - private boolean isProviderAllowedByCoarsePermission(String provider) { - if (LocationManager.FUSED_PROVIDER.equals(provider)) { - return true; - } - if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { - return true; - } - if (LocationManager.NETWORK_PROVIDER.equals(provider)) { - return true; - } - return false; - } - private String checkPermissionAndRequest(LocationRequest request) { - String perm = checkPermission(); + String perm = getBestCallingPermission(); + String provider = request.getProvider(); + checkPermissionForProvider(perm, provider); if (ACCESS_COARSE_LOCATION.equals(perm)) { - if (!isProviderAllowedByCoarsePermission(request.getProvider())) { - throw new SecurityException("Requires ACCESS_FINE_LOCATION permission"); - } switch (request.getQuality()) { case LocationRequest.ACCURACY_FINE: request.setQuality(LocationRequest.ACCURACY_BLOCK); @@ -1324,7 +1340,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run */ @Override public ProviderProperties getProviderProperties(String provider) { - checkPermission(); + checkPermissionForProvider(getBestCallingPermission(), provider); LocationProviderInterface p; synchronized (mLock) { @@ -1337,13 +1353,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run @Override public boolean isProviderEnabled(String provider) { - String perms = checkPermission(); + checkPermissionForProvider(getBestCallingPermission(), provider); if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; - if (ACCESS_COARSE_LOCATION.equals(perms) && - !isProviderAllowedByCoarsePermission(provider)) { - throw new SecurityException("The \"" + provider + - "\" provider requires ACCESS_FINE_LOCATION permission"); - } long identity = Binder.clearCallingIdentity(); try { diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java index 3e541dd..c441b02 100644 --- a/services/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/java/com/android/server/display/WifiDisplayAdapter.java @@ -198,6 +198,12 @@ final class WifiDisplayAdapter extends DisplayAdapter { updateRememberedDisplaysLocked(); scheduleStatusChangedBroadcastLocked(); } + + if (mActiveDisplay != null && mActiveDisplay.getDeviceAddress().equals(address) + && mDisplayDevice != null) { + mDisplayDevice.setNameLocked(mActiveDisplay.getFriendlyDisplayName()); + sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_CHANGED); + } } public void requestForgetLocked(String address) { @@ -397,7 +403,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { }; private final class WifiDisplayDevice extends DisplayDevice { - private final String mName; + private String mName; private final int mWidth; private final int mHeight; private final float mRefreshRate; @@ -423,6 +429,11 @@ final class WifiDisplayAdapter extends DisplayAdapter { sendTraversalRequestLocked(); } + public void setNameLocked(String name) { + mName = name; + mInfo = null; + } + @Override public void performTraversalInTransactionLocked() { setSurfaceInTransactionLocked(mSurface); diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java index b76ad45..4e692a2 100644 --- a/services/java/com/android/server/power/PowerManagerService.java +++ b/services/java/com/android/server/power/PowerManagerService.java @@ -162,6 +162,11 @@ public final class PowerManagerService extends IPowerManager.Stub // Poll interval in milliseconds for watching boot animation finished. private static final int BOOT_ANIMATION_POLL_INTERVAL = 200; + // If the battery level drops by this percentage and the user activity timeout + // has expired, then assume the device is receiving insufficient current to charge + // effectively and terminate the dream. + private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5; + private Context mContext; private LightsService mLightsService; private BatteryService mBatteryService; @@ -256,6 +261,14 @@ public final class PowerManagerService extends IPowerManager.Stub // The current plug type, such as BatteryManager.BATTERY_PLUGGED_WIRELESS. private int mPlugType; + // The current battery level percentage. + private int mBatteryLevel; + + // The battery level percentage at the time the dream started. + // This is used to terminate a dream and go to sleep if the battery is + // draining faster than it is charging and the user activity timeout has expired. + private int mBatteryLevelWhenDreamStarted; + // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; @@ -1067,12 +1080,14 @@ public final class PowerManagerService extends IPowerManager.Stub final int oldPlugType = mPlugType; mIsPowered = mBatteryService.isPowered(BatteryManager.BATTERY_PLUGGED_ANY); mPlugType = mBatteryService.getPlugType(); + mBatteryLevel = mBatteryService.getBatteryLevel(); if (DEBUG) { Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered + ", mIsPowered=" + mIsPowered + ", oldPlugType=" + oldPlugType - + ", mPlugType=" + mPlugType); + + ", mPlugType=" + mPlugType + + ", mBatteryLevel=" + mBatteryLevel); } if (wasPowered != mIsPowered || oldPlugType != mPlugType) { @@ -1126,8 +1141,7 @@ public final class PowerManagerService extends IPowerManager.Stub } if (!wasPowered && mIsPowered && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS - && mBatteryService.getBatteryLevel() >= - WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) { + && mBatteryLevel >= WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) { return false; } @@ -1403,7 +1417,7 @@ public final class PowerManagerService extends IPowerManager.Stub mSandmanScheduled = false; boolean canDream = canDreamLocked(); if (DEBUG_SPEW) { - Log.d(TAG, "handleSandman: canDream=" + canDream + Slog.d(TAG, "handleSandman: canDream=" + canDream + ", mWakefulness=" + wakefulnessToString(mWakefulness)); } @@ -1431,10 +1445,24 @@ public final class PowerManagerService extends IPowerManager.Stub if (mWakefulness == WAKEFULNESS_NAPPING) { mWakefulness = WAKEFULNESS_DREAMING; mDirty |= DIRTY_WAKEFULNESS; + mBatteryLevelWhenDreamStarted = mBatteryLevel; updatePowerStateLocked(); continueDreaming = true; } else if (mWakefulness == WAKEFULNESS_DREAMING) { - continueDreaming = true; + if (!isBeingKeptAwakeLocked() + && mBatteryLevel < mBatteryLevelWhenDreamStarted + - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) { + // If the user activity timeout expired and the battery appears + // to be draining faster than it is charging then stop dreaming + // and go to sleep. + Slog.i(TAG, "Stopping dream because the battery appears to " + + "be draining faster than it is charging. " + + "Battery level when dream started: " + + mBatteryLevelWhenDreamStarted + "%. " + + "Battery level now: " + mBatteryLevel + "%."); + } else { + continueDreaming = true; + } } } if (!continueDreaming) { @@ -1704,8 +1732,11 @@ public final class PowerManagerService extends IPowerManager.Stub } /** - * Reboot the device, passing 'reason' (may be null) - * to the underlying __reboot system call. Should not return. + * Reboots the device. + * + * @param confirm If true, shows a reboot confirmation dialog. + * @param reason The reason for the reboot, or null if none. + * @param wait If true, this call waits for the reboot to complete and does not return. */ @Override // Binder call public void reboot(boolean confirm, String reason, boolean wait) { @@ -1713,15 +1744,17 @@ public final class PowerManagerService extends IPowerManager.Stub final long ident = Binder.clearCallingIdentity(); try { - rebootInternal(false, confirm, reason, wait); + shutdownOrRebootInternal(false, confirm, reason, wait); } finally { Binder.restoreCallingIdentity(ident); } } /** - * Shutdown the devic, passing 'reason' (may be null) - * to the underlying __reboot system call. Should not return. + * Shuts down the device. + * + * @param confirm If true, shows a shutdown confirmation dialog. + * @param wait If true, this call waits for the shutdown to complete and does not return. */ @Override // Binder call public void shutdown(boolean confirm, boolean wait) { @@ -1729,19 +1762,20 @@ public final class PowerManagerService extends IPowerManager.Stub final long ident = Binder.clearCallingIdentity(); try { - rebootInternal(true, confirm, null, wait); + shutdownOrRebootInternal(true, confirm, null, wait); } finally { Binder.restoreCallingIdentity(ident); } } - private void rebootInternal(final boolean shutdown, final boolean confirm, + private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm, final String reason, boolean wait) { if (mHandler == null || !mSystemReady) { - throw new IllegalStateException("Too early to call reboot()"); + throw new IllegalStateException("Too early to call shutdown() or reboot()"); } Runnable runnable = new Runnable() { + @Override public void run() { synchronized (this) { if (shutdown) { @@ -1789,6 +1823,7 @@ public final class PowerManagerService extends IPowerManager.Stub private void crashInternal(final String message) { Thread t = new Thread("PowerManagerService.crash()") { + @Override public void run() { throw new RuntimeException(message); } @@ -2087,6 +2122,8 @@ public final class PowerManagerService extends IPowerManager.Stub pw.println(" mWakefulness=" + wakefulnessToString(mWakefulness)); pw.println(" mIsPowered=" + mIsPowered); pw.println(" mPlugType=" + mPlugType); + pw.println(" mBatteryLevel=" + mBatteryLevel); + pw.println(" mBatteryLevelWhenDreamStarted=" + mBatteryLevelWhenDreamStarted); pw.println(" mStayOn=" + mStayOn); pw.println(" mProximityPositive=" + mProximityPositive); pw.println(" mBootCompleted=" + mBootCompleted); diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java index 26cb97b..fd594f7 100644 --- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java +++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java @@ -66,7 +66,7 @@ public class SystemClock_Delegate { * @return elapsed nanoseconds since boot. */ @LayoutlibDelegate - /*package*/ static long elapsedRealtimeNano() { + /*package*/ static long elapsedRealtimeNanos() { return System.nanoTime() - sBootTimeNano; } diff --git a/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java new file mode 100644 index 0000000..f75ee50 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/Choreographer_Delegate.java @@ -0,0 +1,33 @@ +/* + * 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.view; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +/** + * Delegate used to provide new implementation of a select few methods of {@link Choreographer} + * + * Through the layoutlib_create tool, the original methods of Choreographer have been + * replaced by calls to methods of the same name in this delegate class. + * + */ +public class Choreographer_Delegate { + + @LayoutlibDelegate + public static float getRefreshRate() { + return 60.f; + } +} diff --git a/tools/layoutlib/bridge/src/android/view/Display_Delegate.java b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java index 6ccdcb6..53dc821 100644 --- a/tools/layoutlib/bridge/src/android/view/Display_Delegate.java +++ b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java @@ -16,11 +16,8 @@ package android.view; -import com.android.layoutlib.bridge.android.BridgeWindowManager; -import com.android.layoutlib.bridge.impl.RenderAction; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; -import android.os.RemoteException; /** * Delegate used to provide new implementation of a select few methods of {@link Display} @@ -31,4 +28,9 @@ import android.os.RemoteException; */ public class Display_Delegate { + @LayoutlibDelegate + static void updateDisplayInfoLocked(Display theDisplay) { + // do nothing + } + } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 3fcc8ef..da736b7 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.layoutlib.bridge.android; +package android.view; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; @@ -28,7 +28,6 @@ import android.os.IRemoteCallback; import android.os.RemoteException; import android.util.DisplayMetrics; import android.view.Display; -import android.view.Display_Delegate; import android.view.Gravity; import android.view.IApplicationToken; import android.view.IDisplayContentChangeListener; @@ -45,16 +44,21 @@ import java.util.List; * Basic implementation of {@link IWindowManager} so that {@link Display} (and * {@link Display_Delegate}) can return a valid instance. */ -public class BridgeWindowManager implements IWindowManager { +public class IWindowManagerImpl implements IWindowManager { private final Configuration mConfig; private final DisplayMetrics mMetrics; private final int mRotation; + private final boolean mHasSystemNavBar; + private final boolean mHasNavigationBar; - public BridgeWindowManager(Configuration config, DisplayMetrics metrics, int rotation) { + public IWindowManagerImpl(Configuration config, DisplayMetrics metrics, int rotation, + boolean hasSystemNavBar, boolean hasNavigationBar) { mConfig = config; mMetrics = metrics; mRotation = rotation; + mHasSystemNavBar = hasSystemNavBar; + mHasNavigationBar = hasNavigationBar; } // custom API. @@ -70,14 +74,18 @@ public class BridgeWindowManager implements IWindowManager { return mRotation; } - // ---- unused implementation of IWindowManager ---- + @Override + public boolean hasNavigationBar() { + return mHasNavigationBar; + } @Override public boolean hasSystemNavBar() throws RemoteException { - // TODO Auto-generated method stub - return false; + return mHasSystemNavBar; } + // ---- unused implementation of IWindowManager ---- + @Override public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4, boolean arg5) @@ -435,11 +443,6 @@ public class BridgeWindowManager implements IWindowManager { } @Override - public boolean hasNavigationBar() { - return false; // should this return something else? - } - - @Override public void lockNow(Bundle options) { // TODO Auto-generated method stub } diff --git a/tools/layoutlib/bridge/src/android/view/WindowManagerGlobal_Delegate.java b/tools/layoutlib/bridge/src/android/view/WindowManagerGlobal_Delegate.java new file mode 100644 index 0000000..2606e55 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/WindowManagerGlobal_Delegate.java @@ -0,0 +1,43 @@ +/* + * 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.view; + +import com.android.tools.layoutlib.annotations.LayoutlibDelegate; + +/** + * Delegate used to provide new implementation of a select few methods of + * {@link WindowManagerGlobal} + * + * Through the layoutlib_create tool, the original methods of WindowManagerGlobal have been + * replaced by calls to methods of the same name in this delegate class. + * + */ +public class WindowManagerGlobal_Delegate { + + private static IWindowManager sService; + + @LayoutlibDelegate + public static IWindowManager getWindowManagerService() { + return sService; + } + + // ---- internal implementation stuff ---- + + public static void setWindowManagerService(IWindowManager service) { + sService = service; + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 80478ba..e2fced6 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -25,6 +25,7 @@ import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.StyleResourceValue; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.BridgeConstants; +import com.android.layoutlib.bridge.android.view.WindowManagerImpl; import com.android.layoutlib.bridge.impl.ParserFactory; import com.android.layoutlib.bridge.impl.Stack; import com.android.resources.ResourceType; @@ -68,9 +69,9 @@ import android.util.TypedValue; import android.view.BridgeInflater; import android.view.CompatibilityInfoHolder; import android.view.Display; -import android.view.Surface; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.textservice.TextServicesManager; import java.io.File; @@ -98,7 +99,7 @@ public final class BridgeContext extends Context { private final Configuration mConfig; private final ApplicationInfo mApplicationInfo; private final IProjectCallback mProjectCallback; - private final BridgeWindowManager mIWindowManager; + private final WindowManager mWindowManager; private Resources.Theme mTheme; @@ -139,10 +140,10 @@ public final class BridgeContext extends Context { mRenderResources = renderResources; mConfig = config; - mIWindowManager = new BridgeWindowManager(mConfig, metrics, Surface.ROTATION_0); - mApplicationInfo = new ApplicationInfo(); mApplicationInfo.targetSdkVersion = targetSdkVersion; + + mWindowManager = new WindowManagerImpl(mMetrics); } /** @@ -198,14 +199,14 @@ public final class BridgeContext extends Context { return mRenderResources; } - public BridgeWindowManager getIWindowManager() { - return mIWindowManager; - } - public Map<String, String> getDefaultPropMap(Object key) { return mDefaultPropMaps.get(key); } + public Configuration getConfiguration() { + return mConfig; + } + /** * Adds a parser to the stack. * @param parser the parser to add. @@ -431,10 +432,8 @@ public final class BridgeContext extends Context { return TextServicesManager.getInstance(); } - // AutoCompleteTextView and MultiAutoCompleteTextView want a window - // service. We don't have any but it's not worth an exception. if (WINDOW_SERVICE.equals(service)) { - return null; + return mWindowManager; } // needed by SearchView diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java new file mode 100644 index 0000000..9a633bf --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java @@ -0,0 +1,64 @@ +/* + * 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.layoutlib.bridge.android.view; + +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.View; +import android.view.WindowManager; + +public class WindowManagerImpl implements WindowManager { + + private final DisplayMetrics mMetrics; + private final Display mDisplay; + + public WindowManagerImpl(DisplayMetrics metrics) { + mMetrics = metrics; + + DisplayInfo info = new DisplayInfo(); + info.logicalHeight = mMetrics.heightPixels; + info.logicalWidth = mMetrics.widthPixels; + mDisplay = new Display(null, Display.DEFAULT_DISPLAY, info, null); + } + + @Override + public Display getDefaultDisplay() { + return mDisplay; + } + + + @Override + public void addView(View arg0, android.view.ViewGroup.LayoutParams arg1) { + // pass + } + + @Override + public void removeView(View arg0) { + // pass + } + + @Override + public void updateViewLayout(View arg0, android.view.ViewGroup.LayoutParams arg1) { + // pass + } + + + @Override + public void removeViewImmediate(View arg0) { + // pass + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index e93b41d..cc0f077 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -68,11 +68,15 @@ import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.AttachInfo_Accessor; import android.view.BridgeInflater; +import android.view.IWindowManagerImpl; +import android.view.IWindowManager; +import android.view.Surface; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.MarginLayoutParams; +import android.view.WindowManagerGlobal_Delegate; import android.widget.AbsListView; import android.widget.AbsSpinner; import android.widget.AdapterView; @@ -185,6 +189,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { findActionBar(resources, metrics); findSystemBar(resources, metrics); + // FIXME: find those out, and possibly add them to the render params + boolean hasSystemNavBar = true; + boolean hasNavigationBar = true; + IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(), + metrics, Surface.ROTATION_0, + hasSystemNavBar, hasNavigationBar); + WindowManagerGlobal_Delegate.setWindowManagerService(iwm); + // build the inflater and parser. mInflater = new BridgeInflater(context, params.getProjectCallback()); context.setBridgeInflater(mInflater); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 5109810..80a1a60 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -110,11 +110,13 @@ public final class CreateInfo implements ICreateInfo { "android.os.Handler#sendMessageAtTime", "android.os.HandlerThread#run", "android.os.Build#getString", - "android.view.Display#getWindowManager", + "android.view.Choreographer#getRefreshRate", + "android.view.Display#updateDisplayInfoLocked", "android.view.LayoutInflater#rInflate", "android.view.LayoutInflater#parseInclude", "android.view.View#isInEditMode", "android.view.ViewRootImpl#isInTouchMode", + "android.view.WindowManagerGlobal#getWindowManagerService", "android.view.inputmethod.InputMethodManager#getInstance", "com.android.internal.util.XmlUtils#convertValueToInt", "com.android.internal.textservice.ITextServicesManager$Stub#asInterface", |