summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/BroadcastOptions.java65
-rw-r--r--core/java/android/app/ContextImpl.java18
-rw-r--r--core/java/android/content/Context.java8
-rw-r--r--core/java/android/content/ContextWrapper.java7
-rw-r--r--core/jni/android_os_Debug.cpp10
-rw-r--r--libs/hwui/BakedOpDispatcher.cpp8
-rw-r--r--libs/hwui/OpReorderer.cpp94
-rw-r--r--libs/hwui/OpReorderer.h8
-rw-r--r--libs/hwui/RecordedOp.h33
-rw-r--r--libs/hwui/RecordingCanvas.cpp38
-rw-r--r--libs/hwui/RecordingCanvas.h11
-rw-r--r--libs/hwui/tests/common/scenes/OpPropAnimation.cpp72
-rw-r--r--packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java2
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java9
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java120
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java31
-rw-r--r--services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java6
-rw-r--r--test-runner/src/android/test/mock/MockContext.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java5
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,