diff options
21 files changed, 447 insertions, 108 deletions
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index 1f378da4afd3..175b9799c5db 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.SystemApi; +import android.os.Build; import android.os.Bundle; /** @@ -28,15 +29,28 @@ import android.os.Bundle; @SystemApi public class BroadcastOptions { private long mTemporaryAppWhitelistDuration; + private int mMinManifestReceiverApiLevel = 0; + private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; /** * How long to temporarily put an app on the power whitelist when executing this broadcast * to it. - * @hide */ - public static final String KEY_TEMPORARY_APP_WHITELIST_DURATION + static final String KEY_TEMPORARY_APP_WHITELIST_DURATION = "android:broadcast.temporaryAppWhitelistDuration"; + /** + * Corresponds to {@link #setMinManifestReceiverApiLevel}. + */ + static final String KEY_MIN_MANIFEST_RECEIVER_API_LEVEL + = "android:broadcast.minManifestReceiverApiLevel"; + + /** + * Corresponds to {@link #setMaxManifestReceiverApiLevel}. + */ + static final String KEY_MAX_MANIFEST_RECEIVER_API_LEVEL + = "android:broadcast.maxManifestReceiverApiLevel"; + public static BroadcastOptions makeBasic() { BroadcastOptions opts = new BroadcastOptions(); return opts; @@ -48,6 +62,9 @@ public class BroadcastOptions { /** @hide */ public BroadcastOptions(Bundle opts) { mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION); + mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0); + mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, + Build.VERSION_CODES.CUR_DEVELOPMENT); } /** @@ -68,10 +85,46 @@ public class BroadcastOptions { } /** + * Set the minimum target API level of receivers of the broadcast. If an application + * is targeting an API level less than this, the broadcast will not be delivered to + * them. This only applies to receivers declared in the app's AndroidManifest.xml. + * @hide + */ + public void setMinManifestReceiverApiLevel(int apiLevel) { + mMinManifestReceiverApiLevel = apiLevel; + } + + /** + * Return {@link #setMinManifestReceiverApiLevel}. + * @hide + */ + public int getMinManifestReceiverApiLevel() { + return mMinManifestReceiverApiLevel; + } + + /** + * Set the maximum target API level of receivers of the broadcast. If an application + * is targeting an API level greater than this, the broadcast will not be delivered to + * them. This only applies to receivers declared in the app's AndroidManifest.xml. + * @hide + */ + public void setMaxManifestReceiverApiLevel(int apiLevel) { + mMaxManifestReceiverApiLevel = apiLevel; + } + + /** + * Return {@link #setMaxManifestReceiverApiLevel}. + * @hide + */ + public int getMaxManifestReceiverApiLevel() { + return mMaxManifestReceiverApiLevel; + } + + /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) * Context.sendBroadcast(Intent)} and related methods. - * Note that the returned Bundle is still owned by the ActivityOptions + * Note that the returned Bundle is still owned by the BroadcastOptions * object; you must not modify it, but can supply it to the sendBroadcast * methods that take an options Bundle. */ @@ -80,6 +133,12 @@ public class BroadcastOptions { if (mTemporaryAppWhitelistDuration > 0) { b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration); } + if (mMinManifestReceiverApiLevel != 0) { + b.putInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, mMinManifestReceiverApiLevel); + } + if (mMaxManifestReceiverApiLevel != Build.VERSION_CODES.CUR_DEVELOPMENT) { + b.putInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, mMaxManifestReceiverApiLevel); + } return b.isEmpty() ? null : b; } } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d90ed9f6e639..569ab1116b5b 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1093,7 +1093,23 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier()); + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, + user.getIdentifier()); + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); + } + } + + @Override + @Deprecated + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(); + ActivityManagerNative.getDefault().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true, + user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index c61f20444813..38a4475064af 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2116,6 +2116,14 @@ public abstract class Context { UserHandle user); /** + * @hide + * This is just here for sending CONNECTIVITY_ACTION. + */ + @Deprecated + public abstract void sendStickyBroadcastAsUser(@RequiresPermission Intent intent, + UserHandle user, Bundle options); + + /** * <p>Version of * {@link #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)} * that allows you to specify the diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index e49e771d4124..1a3d262f6b56 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -536,6 +536,13 @@ public class ContextWrapper extends Context { mBase.sendStickyBroadcastAsUser(intent, user); } + /** @hide */ + @Override + @Deprecated + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { + mBase.sendStickyBroadcastAsUser(intent, user, options); + } + @Override @Deprecated public void sendStickyOrderedBroadcastAsUser(Intent intent, diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 71f881e6d6e1..2488111247a2 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -595,14 +595,14 @@ enum { MEMINFO_COUNT }; -static long get_zram_mem_used() +static long long get_zram_mem_used() { #define ZRAM_SYSFS "/sys/block/zram0/" FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r"); if (f) { - long mem_used_total = 0; + long long mem_used_total = 0; - int matched = fscanf(f, "%*d %*d %ld %*d %*d %*d %*d", &mem_used_total); + int matched = fscanf(f, "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total); if (matched != 1) ALOGW("failed to parse " ZRAM_SYSFS "mm_stat"); @@ -612,9 +612,9 @@ static long get_zram_mem_used() f = fopen(ZRAM_SYSFS "mem_used_total", "r"); if (f) { - long mem_used_total = 0; + long long mem_used_total = 0; - int matched = fscanf(f, "%ld", &mem_used_total); + int matched = fscanf(f, "%lld", &mem_used_total); if (matched != 1) ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total"); diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index f1c89b895048..d4dbb00aa207 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -309,6 +309,14 @@ void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const LOG_ALWAYS_FATAL("unsupported operation"); } +void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + +void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) { + LOG_ALWAYS_FATAL("unsupported operation"); +} + namespace VertexBufferRenderFlags { enum { Offset = 0x1, diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index b936e6d5b062..ec03e8310a36 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -467,13 +467,13 @@ void OpReorderer::deferNodePropsAndOps(RenderNode& node) { // (temp layers are clipped to viewport, since they don't persist offscreen content) SkPaint saveLayerPaint; saveLayerPaint.setAlpha(properties.getAlpha()); - onBeginLayerOp(*new (mAllocator) BeginLayerOp( + deferBeginLayerOp(*new (mAllocator) BeginLayerOp( saveLayerBounds, Matrix4::identity(), saveLayerBounds, &saveLayerPaint)); deferNodeOps(node); - onEndLayerOp(*new (mAllocator) EndLayerOp()); + deferEndLayerOp(*new (mAllocator) EndLayerOp()); } else { deferNodeOps(node); } @@ -559,7 +559,7 @@ void OpReorderer::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedN } const RenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; - deferRenderNodeOp(*childOp); + deferRenderNodeOpImpl(*childOp); drawIndex++; } } @@ -645,7 +645,7 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { int restoreTo = mCanvasState.save(SkCanvas::kMatrix_SaveFlag); mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor); - deferRenderNodeOp(*childOp); + deferRenderNodeOpImpl(*childOp); mCanvasState.restoreToCount(restoreTo); } @@ -653,13 +653,13 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { } /** - * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods. + * Used to define a list of lambdas referencing private OpReorderer::onXX::defer() methods. * * This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas. * E.g. a BitmapOp op then would be dispatched to OpReorderer::onBitmapOp(const BitmapOp&) */ #define OP_RECEIVER(Type) \ - [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, + [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, void OpReorderer::deferNodeOps(const RenderNode& renderNode) { typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); static OpDispatcher receivers[] = { @@ -687,7 +687,7 @@ void OpReorderer::deferNodeOps(const RenderNode& renderNode) { } } -void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { +void OpReorderer::deferRenderNodeOpImpl(const RenderNodeOp& op) { if (op.renderNode->nothingToDraw()) return; int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); @@ -702,9 +702,9 @@ void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { mCanvasState.restoreToCount(count); } -void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { +void OpReorderer::deferRenderNodeOp(const RenderNodeOp& op) { if (!op.skipInOrderDraw) { - deferRenderNodeOp(op); + deferRenderNodeOpImpl(op); } } @@ -712,7 +712,7 @@ void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) { * Defers an unmergeable, strokeable op, accounting correctly * for paint's style on the bounds being computed. */ -void OpReorderer::onStrokeableOp(const RecordedOp& op, batchid_t batchId, +void OpReorderer::deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior) { // Note: here we account for stroke when baking the op BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct( @@ -734,11 +734,11 @@ static batchid_t tessBatchId(const RecordedOp& op) { : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices); } -void OpReorderer::onArcOp(const ArcOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferArcOp(const ArcOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onBitmapOp(const BitmapOp& op) { +void OpReorderer::deferBitmapOp(const BitmapOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -757,28 +757,43 @@ void OpReorderer::onBitmapOp(const BitmapOp& op) { } } -void OpReorderer::onBitmapMeshOp(const BitmapMeshOp& op) { +void OpReorderer::deferBitmapMeshOp(const BitmapMeshOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::onBitmapRectOp(const BitmapRectOp& op) { +void OpReorderer::deferBitmapRectOp(const BitmapRectOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap); } -void OpReorderer::onLinesOp(const LinesOp& op) { +void OpReorderer::deferCirclePropsOp(const CirclePropsOp& op) { + // allocate a temporary oval op (with mAllocator, so it persists until render), so the + // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. + float x = *(op.x); + float y = *(op.y); + float radius = *(op.radius); + Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius); + const OvalOp* resolvedOp = new (mAllocator) OvalOp( + unmappedBounds, + op.localMatrix, + op.localClipRect, + op.paint); + deferOvalOp(*resolvedOp); +} + +void OpReorderer::deferLinesOp(const LinesOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - onStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); + deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); } -void OpReorderer::onOvalOp(const OvalOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferOvalOp(const OvalOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onPatchOp(const PatchOp& op) { +void OpReorderer::deferPatchOp(const PatchOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -795,30 +810,41 @@ void OpReorderer::onPatchOp(const PatchOp& op) { } } -void OpReorderer::onPathOp(const PathOp& op) { - onStrokeableOp(op, OpBatchType::Bitmap); +void OpReorderer::deferPathOp(const PathOp& op) { + deferStrokeableOp(op, OpBatchType::Bitmap); } -void OpReorderer::onPointsOp(const PointsOp& op) { +void OpReorderer::deferPointsOp(const PointsOp& op) { batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices; - onStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); + deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced); +} + +void OpReorderer::deferRectOp(const RectOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onRectOp(const RectOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferRoundRectOp(const RoundRectOp& op) { + deferStrokeableOp(op, tessBatchId(op)); } -void OpReorderer::onRoundRectOp(const RoundRectOp& op) { - onStrokeableOp(op, tessBatchId(op)); +void OpReorderer::deferRoundRectPropsOp(const RoundRectPropsOp& op) { + // allocate a temporary round rect op (with mAllocator, so it persists until render), so the + // renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple. + const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp( + Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), + op.localMatrix, + op.localClipRect, + op.paint, *op.rx, *op.ry); + deferRoundRectOp(*resolvedOp); } -void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { +void OpReorderer::deferSimpleRectsOp(const SimpleRectsOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices); } -void OpReorderer::onTextOp(const TextOp& op) { +void OpReorderer::deferTextOp(const TextOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -861,7 +887,7 @@ void OpReorderer::restoreForLayer() { } // TODO: test rejection at defer time, where the bounds become empty -void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) { +void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); @@ -906,7 +932,7 @@ void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) { &op, nullptr); } -void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { +void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { const BeginLayerOp& beginLayerOp = *currentLayer().beginLayerOp; int finishedLayerIndex = mLayerStack.back(); @@ -932,11 +958,11 @@ void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { } } -void OpReorderer::onLayerOp(const LayerOp& op) { +void OpReorderer::deferLayerOp(const LayerOp& op) { LOG_ALWAYS_FATAL("unsupported"); } -void OpReorderer::onShadowOp(const ShadowOp& op) { +void OpReorderer::deferShadowOp(const ShadowOp& op) { LOG_ALWAYS_FATAL("unsupported"); } diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 0b88f049b583..35343c8b4358 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -237,7 +237,7 @@ private: void deferNodeOps(const RenderNode& renderNode); - void deferRenderNodeOp(const RenderNodeOp& op); + void deferRenderNodeOpImpl(const RenderNodeOp& op); void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); @@ -246,17 +246,17 @@ private: return mFrameAllocatedPaths.back().get(); } - void onStrokeableOp(const RecordedOp& op, batchid_t batchId, + void deferStrokeableOp(const RecordedOp& op, batchid_t batchId, BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined); /** - * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type. + * Declares all OpReorderer::deferXXXXOp() methods for every RecordedOp type. * * These private methods are called from within deferImpl to defer each individual op * type differently. */ #define INTERNAL_OP_HANDLER(Type) \ - void on##Type(const Type& op); + void defer##Type(const Type& op); MAP_OPS(INTERNAL_OP_HANDLER) std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths; diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 75ecdae3aa6f..d1a486600e4c 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -48,6 +48,7 @@ struct Vertex; M_OP_FN(BitmapOp) \ U_OP_FN(BitmapMeshOp) \ U_OP_FN(BitmapRectOp) \ + U_OP_FN(CirclePropsOp) \ U_OP_FN(LinesOp) \ U_OP_FN(OvalOp) \ M_OP_FN(PatchOp) \ @@ -56,6 +57,7 @@ struct Vertex; U_OP_FN(RectOp) \ U_OP_FN(RenderNodeOp) \ U_OP_FN(RoundRectOp) \ + U_OP_FN(RoundRectPropsOp) \ U_OP_FN(ShadowOp) \ U_OP_FN(SimpleRectsOp) \ M_OP_FN(TextOp) \ @@ -181,6 +183,18 @@ struct BitmapRectOp : RecordedOp { const Rect src; }; +struct CirclePropsOp : RecordedOp { + CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint, + float* x, float* y, float* radius) + : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint) + , x(x) + , y(y) + , radius(radius) {} + const float* x; + const float* y; + const float* radius; +}; + struct LinesOp : RecordedOp { LinesOp(BASE_PARAMS, const float* points, const int floatCount) : SUPER(LinesOp) @@ -195,7 +209,6 @@ struct OvalOp : RecordedOp { : SUPER(OvalOp) {} }; - struct PatchOp : RecordedOp { PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch) : SUPER(PatchOp) @@ -235,6 +248,24 @@ struct RoundRectOp : RecordedOp { const float ry; }; +struct RoundRectPropsOp : RecordedOp { + RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint, + float* left, float* top, float* right, float* bottom, float *rx, float *ry) + : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint) + , left(left) + , top(top) + , right(right) + , bottom(bottom) + , rx(rx) + , ry(ry) {} + const float* left; + const float* top; + const float* right; + const float* bottom; + const float* rx; + const float* ry; +}; + /** * Real-time, dynamic-lit shadow. * diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 57f0d349172c..1bf92be18687 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -343,11 +343,49 @@ void RecordingCanvas::drawRoundRect(float left, float top, float right, float bo refPaint(&paint), rx, ry)); } +void RecordingCanvas::drawRoundRect( + CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint) { + mDisplayList->ref(left); + mDisplayList->ref(top); + mDisplayList->ref(right); + mDisplayList->ref(bottom); + mDisplayList->ref(rx); + mDisplayList->ref(ry); + mDisplayList->ref(paint); + refBitmapsInShader(paint->value.getShader()); + addOp(new (alloc()) RoundRectPropsOp( + *(mState.currentSnapshot()->transform), + mState.getRenderTargetClipBounds(), + &paint->value, + &left->value, &top->value, &right->value, &bottom->value, + &rx->value, &ry->value)); +} + void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) { + // TODO: move to Canvas.h if (radius <= 0) return; drawOval(x - radius, y - radius, x + radius, y + radius, paint); } +void RecordingCanvas::drawCircle( + CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) { + mDisplayList->ref(x); + mDisplayList->ref(y); + mDisplayList->ref(radius); + mDisplayList->ref(paint); + refBitmapsInShader(paint->value.getShader()); + addOp(new (alloc()) CirclePropsOp( + *(mState.currentSnapshot()->transform), + mState.getRenderTargetClipBounds(), + &paint->value, + &x->value, &y->value, &radius->value)); +} + + void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) { addOp(new (alloc()) OvalOp( Rect(left, top, right, bottom), diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 16a277162738..6fbaa8ae75c3 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -69,6 +69,17 @@ public: virtual GLuint getTargetFbo() const override { return -1; } // ---------------------------------------------------------------------------- +// HWUI Canvas draw operations +// ---------------------------------------------------------------------------- + + void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top, + CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom, + CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry, + CanvasPropertyPaint* paint); + void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y, + CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint); + +// ---------------------------------------------------------------------------- // android/graphics/Canvas interface // ---------------------------------------------------------------------------- virtual SkCanvas* asSkCanvas() override; diff --git a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp new file mode 100644 index 000000000000..5dfb2b4a8b33 --- /dev/null +++ b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "TestSceneBase.h" +#include "utils/Color.h" + +class OpPropAnimation; + +static TestScene::Registrar _Shapes(TestScene::Info{ + "opprops", + "A minimal demonstration of CanvasProperty drawing operations.", + TestScene::simpleCreateScene<OpPropAnimation> +}); + +class OpPropAnimation : public TestScene { +public: + sp<CanvasPropertyPaint> mPaint = new CanvasPropertyPaint(SkPaint()); + + sp<CanvasPropertyPrimitive> mRoundRectLeft = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectTop = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRight = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectBottom = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRx = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mRoundRectRy = new CanvasPropertyPrimitive(0); + + sp<CanvasPropertyPrimitive> mCircleX = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mCircleY = new CanvasPropertyPrimitive(0); + sp<CanvasPropertyPrimitive> mCircleRadius = new CanvasPropertyPrimitive(0); + + sp<RenderNode> content; + void createContent(int width, int height, TestCanvas& canvas) override { + content = TestUtils::createNode(0, 0, width, height, + [this, width, height](RenderProperties& props, TestCanvas& canvas) { + mPaint->value.setAntiAlias(true); + mPaint->value.setColor(Color::Blue_500); + + mRoundRectRight->value = width / 2; + mRoundRectBottom->value = height / 2; + + mCircleX->value = width * 0.75; + mCircleY->value = height * 0.75; + + canvas.drawColor(Color::White, SkXfermode::Mode::kSrcOver_Mode); + canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(), + mRoundRectRight.get(), mRoundRectBottom.get(), + mRoundRectRx.get(), mRoundRectRy.get(), mPaint.get()); + canvas.drawCircle(mCircleX.get(), mCircleY.get(), mCircleRadius.get(), mPaint.get()); + }); + canvas.drawRenderNode(content.get()); + } + + void doFrame(int frameNr) override { + float value = (abs((frameNr % 200) - 100)) / 100.0f; + mRoundRectRx->value = dp(10) + value * dp(40); + mRoundRectRy->value = dp(10) + value * dp(80); + mCircleRadius->value = value * dp(200); + content->setPropertyFieldsDirty(RenderNode::GENERIC); + } +}; diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index 44018a024432..e89ab7086933 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -53,6 +53,7 @@ import android.service.notification.StatusBarNotification; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener; @@ -73,6 +74,7 @@ import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMult * <p> * <strong>NOTE</strong>: these tests only work if the device is unlocked. */ +@LargeTest public class BugreportReceiverTest extends InstrumentationTestCase { private static final String TAG = "BugreportReceiverTest"; diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 2e65656546c3..51b84f52498d 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -136,6 +136,9 @@ android:protectionLevel="signature" /> <uses-permission android:name="com.android.systemui.permission.SELF" /> + <!-- Adding Quick Settings tiles --> + <uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" /> + <application android:name=".SystemUIApplication" android:persistent="true" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index b1847e1c1ac6..a78158503a95 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1299,7 +1299,6 @@ public abstract class BaseStatusBar extends SystemUI implements // Since the number of notifications is determined based on the height of the view, we // need to update them. updateRowStates(); - mStackScroller.onHeightChanged(null, false); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c712a568c480..ed64c2b37a4a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -34,6 +34,7 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import android.annotation.Nullable; import android.app.AlarmManager; +import android.app.BroadcastOptions; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -72,6 +73,7 @@ import android.net.RouteInfo; import android.net.UidRange; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; @@ -1529,6 +1531,7 @@ public class ConnectivityService extends IConnectivityManager.Stub log("sendStickyBroadcast: action=" + intent.getAction()); } + Bundle options = null; final long ident = Binder.clearCallingIdentity(); if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) { final NetworkInfo ni = intent.getParcelableExtra( @@ -1536,6 +1539,10 @@ public class ConnectivityService extends IConnectivityManager.Stub if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) { intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } else { + BroadcastOptions opts = BroadcastOptions.makeBasic(); + opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M); + options = opts.toBundle(); } final IBatteryStats bs = BatteryStatsService.getService(); try { @@ -1546,7 +1553,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } try { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 1bab7b99ec62..622aa16cb852 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -468,7 +468,7 @@ public final class BroadcastQueue { } private void deliverToRegisteredReceiverLocked(BroadcastRecord r, - BroadcastFilter filter, boolean ordered) { + BroadcastFilter filter, boolean ordered, int index) { boolean skip = false; if (filter.requiredPermission != null) { int perm = mService.checkComponentPermission(filter.requiredPermission, @@ -576,64 +576,70 @@ public final class BroadcastQueue { if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, filter.receiverList.uid)) { - return; + skip = true; } - if (filter.receiverList.app == null || filter.receiverList.app.crashing) { + if (!skip && (filter.receiverList.app == null || filter.receiverList.app.crashing)) { Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r + " to " + filter.receiverList + ": process crashing"); skip = true; } - if (!skip) { - // If permissions need a review before any of the app components can run, we drop - // the broadcast and if the calling app is in the foreground and the broadcast is - // explicit we launch the review UI passing it a pending intent to send the skipped - // broadcast. - if (Build.PERMISSIONS_REVIEW_REQUIRED) { - if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName, - filter.owningUserId)) { - return; - } + if (skip) { + r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; + return; + } + + // If permissions need a review before any of the app components can run, we drop + // the broadcast and if the calling app is in the foreground and the broadcast is + // explicit we launch the review UI passing it a pending intent to send the skipped + // broadcast. + if (Build.PERMISSIONS_REVIEW_REQUIRED) { + if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName, + filter.owningUserId)) { + r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; + return; } + } - // If this is not being sent as an ordered broadcast, then we - // don't want to touch the fields that keep track of the current - // state of ordered broadcasts. + r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED; + + // If this is not being sent as an ordered broadcast, then we + // don't want to touch the fields that keep track of the current + // state of ordered broadcasts. + if (ordered) { + r.receiver = filter.receiverList.receiver.asBinder(); + r.curFilter = filter; + filter.receiverList.curBroadcast = r; + r.state = BroadcastRecord.CALL_IN_RECEIVE; + if (filter.receiverList.app != null) { + // Bump hosting application to no longer be in background + // scheduling class. Note that we can't do that if there + // isn't an app... but we can only be in that case for + // things that directly call the IActivityManager API, which + // are already core system stuff so don't matter for this. + r.curApp = filter.receiverList.app; + filter.receiverList.app.curReceiver = r; + mService.updateOomAdjLocked(r.curApp); + } + } + try { + if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, + "Delivering to " + filter + " : " + r); + performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, + new Intent(r.intent), r.resultCode, r.resultData, + r.resultExtras, r.ordered, r.initialSticky, r.userId); if (ordered) { - r.receiver = filter.receiverList.receiver.asBinder(); - r.curFilter = filter; - filter.receiverList.curBroadcast = r; - r.state = BroadcastRecord.CALL_IN_RECEIVE; - if (filter.receiverList.app != null) { - // Bump hosting application to no longer be in background - // scheduling class. Note that we can't do that if there - // isn't an app... but we can only be in that case for - // things that directly call the IActivityManager API, which - // are already core system stuff so don't matter for this. - r.curApp = filter.receiverList.app; - filter.receiverList.app.curReceiver = r; - mService.updateOomAdjLocked(r.curApp); - } + r.state = BroadcastRecord.CALL_DONE_RECEIVE; } - try { - if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST, - "Delivering to " + filter + " : " + r); - performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, - new Intent(r.intent), r.resultCode, r.resultData, - r.resultExtras, r.ordered, r.initialSticky, r.userId); - if (ordered) { - r.state = BroadcastRecord.CALL_DONE_RECEIVE; - } - } catch (RemoteException e) { - Slog.w(TAG, "Failure sending broadcast " + r.intent, e); - if (ordered) { - r.receiver = null; - r.curFilter = null; - filter.receiverList.curBroadcast = null; - if (filter.receiverList.app != null) { - filter.receiverList.app.curReceiver = null; - } + } catch (RemoteException e) { + Slog.w(TAG, "Failure sending broadcast " + r.intent, e); + if (ordered) { + r.receiver = null; + r.curFilter = null; + filter.receiverList.curBroadcast = null; + if (filter.receiverList.app != null) { + filter.receiverList.app.curReceiver = null; } } } @@ -740,7 +746,7 @@ public final class BroadcastQueue { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); - deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); + deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); } addBroadcastToHistoryLocked(r); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" @@ -897,7 +903,7 @@ public final class BroadcastQueue { "Delivering ordered [" + mQueueName + "] to registered " + filter + ": " + r); - deliverToRegisteredReceiverLocked(r, filter, r.ordered); + deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. @@ -925,10 +931,17 @@ public final class BroadcastQueue { info.activityInfo.name); boolean skip = false; + if (brOptions != null && + (info.activityInfo.applicationInfo.targetSdkVersion + < brOptions.getMinManifestReceiverApiLevel() || + info.activityInfo.applicationInfo.targetSdkVersion + > brOptions.getMaxManifestReceiverApiLevel())) { + skip = true; + } int perm = mService.checkComponentPermission(info.activityInfo.permission, r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, info.activityInfo.exported); - if (perm != PackageManager.PERMISSION_GRANTED) { + if (!skip && perm != PackageManager.PERMISSION_GRANTED) { if (!info.activityInfo.exported) { Slog.w(TAG, "Permission Denial: broadcasting " + r.intent.toString() @@ -945,7 +958,7 @@ public final class BroadcastQueue { + " due to receiver " + component.flattenToShortString()); } skip = true; - } else if (info.activityInfo.permission != null) { + } else if (!skip && info.activityInfo.permission != null) { final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); if (opCode != AppOpsManager.OP_NONE && mService.mAppOpsService.noteOperation(opCode, r.callingUid, @@ -1118,6 +1131,7 @@ public final class BroadcastQueue { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Skipping delivery of ordered [" + mQueueName + "] " + r + " for whatever reason"); + r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; @@ -1125,6 +1139,7 @@ public final class BroadcastQueue { return; } + r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED; r.state = BroadcastRecord.APP_RECEIVE; r.curComponent = component; r.curReceiver = info.activityInfo; @@ -1294,6 +1309,7 @@ public final class BroadcastQueue { String anrMessage = null; Object curReceiver = r.receivers.get(r.nextReceiver-1); + r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT; Slog.w(TAG, "Receiver during timeout: " + curReceiver); logBroadcastReceiverDiscardLocked(r); if (curReceiver instanceof BroadcastFilter) { diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 1a269cf840f7..e99cbf9e563f 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -57,6 +57,7 @@ final class BroadcastRecord extends Binder { final int appOp; // an app op that is associated with this broadcast final BroadcastOptions options; // BroadcastOptions supplied by caller final List receivers; // contains BroadcastFilter and ResolveInfo + final int[] delivery; // delivery state of each receiver IIntentReceiver resultTo; // who receives final result if non-null long enqueueClockTime; // the clock time the broadcast was enqueued long dispatchTime; // when dispatch started on this set of receivers @@ -79,6 +80,11 @@ final class BroadcastRecord extends Binder { static final int CALL_DONE_RECEIVE = 3; static final int WAITING_SERVICES = 4; + static final int DELIVERY_PENDING = 0; + static final int DELIVERY_DELIVERED = 1; + static final int DELIVERY_SKIPPED = 2; + static final int DELIVERY_TIMEOUT = 3; + // The following are set when we are calling a receiver (one that // was found in our list of registered receivers). BroadcastFilter curFilter; @@ -183,12 +189,24 @@ final class BroadcastRecord extends Binder { PrintWriterPrinter printer = new PrintWriterPrinter(pw); for (int i = 0; i < N; i++) { Object o = receivers.get(i); - pw.print(prefix); pw.print("Receiver #"); pw.print(i); - pw.print(": "); pw.println(o); - if (o instanceof BroadcastFilter) - ((BroadcastFilter)o).dumpBrief(pw, p2); - else if (o instanceof ResolveInfo) - ((ResolveInfo)o).dump(printer, p2, 0); + pw.print(prefix); + switch (delivery[i]) { + case DELIVERY_PENDING: pw.print("Pending"); break; + case DELIVERY_DELIVERED: pw.print("Deliver"); break; + case DELIVERY_SKIPPED: pw.print("Skipped"); break; + case DELIVERY_TIMEOUT: pw.print("Timeout"); break; + default: pw.print("???????"); break; + } + pw.print(" #"); pw.print(i); pw.print(": "); + if (o instanceof BroadcastFilter) { + pw.println(o); + ((BroadcastFilter) o).dumpBrief(pw, p2); + } else if (o instanceof ResolveInfo) { + pw.println("(manifest)"); + ((ResolveInfo) o).dump(printer, p2, 0); + } else { + pw.println(o); + } } } @@ -211,6 +229,7 @@ final class BroadcastRecord extends Binder { appOp = _appOp; options = _options; receivers = _receivers; + delivery = new int[_receivers != null ? _receivers.size() : 0]; resultTo = _resultTo; resultCode = _resultCode; resultData = _resultData; diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java index 757f1c6ea39d..13657ab7f02d 100644 --- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java +++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; +import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; @@ -165,6 +166,11 @@ public class BroadcastInterceptingContext extends ContextWrapper { } @Override + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { + sendBroadcast(intent); + } + + @Override public void removeStickyBroadcast(Intent intent) { // ignored } diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 96c818571df0..64d29787f75f 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -433,6 +433,12 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { + throw new UnsupportedOperationException(); + } + @Override public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, 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 b09a14fd1b39..63411b070d58 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 @@ -1634,6 +1634,11 @@ public final class BridgeContext extends Context { } @Override + public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) { + // pass + } + + @Override public void sendStickyOrderedBroadcastAsUser(Intent intent, UserHandle user, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, |