Merge "Update SearchIndexablesContract"
diff --git a/api/current.txt b/api/current.txt
index 3230bd8..d7664b9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10632,6 +10632,7 @@
method public void setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
method public final void setTileModeY(android.graphics.Shader.TileMode);
method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -10909,6 +10910,7 @@
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public class PaintDrawable extends android.graphics.drawable.ShapeDrawable {
@@ -10999,6 +11001,9 @@
public class TouchFeedbackDrawable extends android.graphics.drawable.LayerDrawable {
method public android.graphics.Rect getDirtyBounds();
+ method public android.content.res.ColorStateList getTint();
+ method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public class TransitionDrawable extends android.graphics.drawable.LayerDrawable implements android.graphics.drawable.Drawable.Callback {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 0d4a4cb..c5e5753 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -461,6 +461,10 @@
return (T) getFaces();
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return (T) getFaceRectangles();
+ } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
+ return (T) getAvailableStreamConfigurations();
+ } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
+ return (T) getAvailableMinFrameDurations();
}
// For other keys, get() falls back to getBase()
@@ -481,6 +485,50 @@
return availableFormats;
}
+ private int[] getAvailableStreamConfigurations() {
+ final int NUM_ELEMENTS_IN_CONFIG = 4;
+ int[] availableConfigs =
+ getBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ if (availableConfigs != null) {
+ if (availableConfigs.length % NUM_ELEMENTS_IN_CONFIG != 0) {
+ Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
+ + " of " + NUM_ELEMENTS_IN_CONFIG);
+ return availableConfigs;
+ }
+
+ for (int i = 0; i < availableConfigs.length; i += NUM_ELEMENTS_IN_CONFIG) {
+ // JPEG has different value between native and managed side, need override.
+ if (availableConfigs[i] == NATIVE_JPEG_FORMAT) {
+ availableConfigs[i] = ImageFormat.JPEG;
+ }
+ }
+ }
+
+ return availableConfigs;
+ }
+
+ private long[] getAvailableMinFrameDurations() {
+ final int NUM_ELEMENTS_IN_DURATION = 4;
+ long[] availableMinDurations =
+ getBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
+ if (availableMinDurations != null) {
+ if (availableMinDurations.length % NUM_ELEMENTS_IN_DURATION != 0) {
+ Log.w(TAG, "availableStreamConfigurations is malformed, length must be multiple"
+ + " of " + NUM_ELEMENTS_IN_DURATION);
+ return availableMinDurations;
+ }
+
+ for (int i = 0; i < availableMinDurations.length; i += NUM_ELEMENTS_IN_DURATION) {
+ // JPEG has different value between native and managed side, need override.
+ if (availableMinDurations[i] == NATIVE_JPEG_FORMAT) {
+ availableMinDurations[i] = ImageFormat.JPEG;
+ }
+ }
+ }
+
+ return availableMinDurations;
+ }
+
private Face[] getFaces() {
final int FACE_LANDMARK_SIZE = 6;
@@ -607,12 +655,56 @@
return setAvailableFormats((int[]) value);
} else if (key.equals(CaptureResult.STATISTICS_FACE_RECTANGLES)) {
return setFaceRectangles((Rect[]) value);
+ } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS)) {
+ return setAvailableStreamConfigurations((int[])value);
+ } else if (key.equals(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS)) {
+ return setAvailableMinFrameDurations((long[])value);
}
// For other keys, set() falls back to setBase().
return false;
}
+ private boolean setAvailableStreamConfigurations(int[] value) {
+ final int NUM_ELEMENTS_IN_CONFIG = 4;
+ int[] availableConfigs = value;
+ if (value == null) {
+ // Let setBase() to handle the null value case.
+ return false;
+ }
+
+ int[] newValues = new int[availableConfigs.length];
+ for (int i = 0; i < availableConfigs.length; i++) {
+ newValues[i] = availableConfigs[i];
+ if (i % NUM_ELEMENTS_IN_CONFIG == 0 && availableConfigs[i] == ImageFormat.JPEG) {
+ newValues[i] = NATIVE_JPEG_FORMAT;
+ }
+ }
+
+ setBase(CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS, newValues);
+ return true;
+ }
+
+ private boolean setAvailableMinFrameDurations(long[] value) {
+ final int NUM_ELEMENTS_IN_DURATION = 4;
+ long[] availableDurations = value;
+ if (value == null) {
+ // Let setBase() to handle the null value case.
+ return false;
+ }
+
+ long[] newValues = new long[availableDurations.length];
+ for (int i = 0; i < availableDurations.length; i++) {
+ newValues[i] = availableDurations[i];
+ if (i % NUM_ELEMENTS_IN_DURATION == 0 && availableDurations[i] == ImageFormat.JPEG) {
+ newValues[i] = NATIVE_JPEG_FORMAT;
+ }
+ }
+
+ setBase(CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS, newValues);
+ return true;
+ }
+
private boolean setAvailableFormats(int[] value) {
int[] availableFormat = value;
if (value == null) {
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index ad33b6f..bcdfda6 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -838,6 +838,11 @@
}
}
+ @Override
+ void pauseSurface(Surface surface) {
+ // No-op
+ }
+
boolean initializeEgl() {
synchronized (sEglLock) {
if (sEgl == null && sEglConfig == null) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 92d85d1..7d46cab 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,6 +234,13 @@
abstract void updateSurface(Surface surface) throws OutOfResourcesException;
/**
+ * Stops any rendering into the surface. Use this if it is unclear whether
+ * or not the surface used by the HardwareRenderer will be changing. It
+ * Suspends any rendering into the surface, but will not do any destruction
+ */
+ abstract void pauseSurface(Surface surface);
+
+ /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index a747ab6..2e0f509 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -54,28 +54,46 @@
private int mWidth, mHeight;
private long mNativeProxy;
+ private boolean mInitialized = false;
ThreadedRenderer(boolean translucent) {
mNativeProxy = nCreateProxy(translucent);
- setEnabled(mNativeProxy != 0);
}
@Override
void destroy(boolean full) {
+ mInitialized = false;
+ updateEnabledState(null);
nDestroyCanvas(mNativeProxy);
}
+ private void updateEnabledState(Surface surface) {
+ if (surface == null || !surface.isValid()) {
+ setEnabled(false);
+ } else {
+ setEnabled(mInitialized);
+ }
+ }
+
@Override
boolean initialize(Surface surface) throws OutOfResourcesException {
+ mInitialized = true;
+ updateEnabledState(surface);
return nInitialize(mNativeProxy, surface);
}
@Override
void updateSurface(Surface surface) throws OutOfResourcesException {
+ updateEnabledState(surface);
nUpdateSurface(mNativeProxy, surface);
}
@Override
+ void pauseSurface(Surface surface) {
+ nPauseSurface(mNativeProxy, surface);
+ }
+
+ @Override
void destroyHardwareResources(View view) {
destroyResources(view);
// TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
@@ -267,6 +285,7 @@
private static native boolean nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
+ private static native void nPauseSurface(long nativeProxy, Surface window);
private static native void nSetup(long nativeProxy, int width, int height);
private static native void nSetDisplayListData(long nativeProxy, long displayList,
long newData);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 94f0683..2d503bf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1421,6 +1421,12 @@
host.getMeasuredHeight() + ", params=" + params);
}
+ if (mAttachInfo.mHardwareRenderer != null) {
+ // relayoutWindow may decide to destroy mSurface. As that decision
+ // happens in WindowManager service, we need to be defensive here
+ // and stop using the surface in case it gets destroyed.
+ mAttachInfo.mHardwareRenderer.pauseSurface(mSurface);
+ }
final int surfaceGenerationId = mSurface.getGenerationId();
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
if (!mDrawDuringWindowsAnimating &&
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 32890cf..20a61bf 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -84,7 +84,7 @@
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
- return proxy->initialize(window.get());
+ return proxy->initialize(window);
}
static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
@@ -94,7 +94,17 @@
if (jsurface) {
window = android_view_Surface_getNativeWindow(env, jsurface);
}
- proxy->updateSurface(window.get());
+ proxy->updateSurface(window);
+}
+
+static void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jobject jsurface) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ sp<ANativeWindow> window;
+ if (jsurface) {
+ window = android_view_Surface_getNativeWindow(env, jsurface);
+ }
+ proxy->pauseSurface(window);
}
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
@@ -203,6 +213,7 @@
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
{ "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
+ { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
{ "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetDisplayListData", "(JJJ)V", (void*) android_view_ThreadedRenderer_setDisplayListData },
{ "nDrawDisplayList", "(JJIIII)V", (void*) android_view_ThreadedRenderer_drawDisplayList },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 46cb9b2..e100a4d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4409,14 +4409,23 @@
<!-- When a tint color is set, specifies its Porter-Duff blending mode. The
default value is src_in, which treats the drawable as an alpha mask. -->
<attr name="tintMode">
- <!-- [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="0" />
- <!-- [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="1" />
- <!-- [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="2" />
+ <!-- The tint is drawn on top of the drawable.
+ [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+ <enum name="src_over" value="3" />
+ <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+ color channels are thrown out. [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="5" />
+ <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+ channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="9" />
+ <!-- Multiplies the color and alpha channels of the drawable with those of
+ the tint. [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="14" />
<!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="3" />
+ <enum name="screen" value="15" />
+ <!-- Combines the tint and drawable color and alpha channels, clamping the
+ result to valid color values. Saturate(S + D) -->
+ <enum name="add" value="16" />
</attr>
</declare-styleable>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 19131f2..66a88a2 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -595,7 +595,6 @@
* Specifies the blending mode used to apply tint.
*
* @param tintMode A Porter-Duff blending mode
- * @hide Pending finalization of supported Modes
*/
public void setTintMode(Mode tintMode) {
if (mBitmapState.mTintMode != tintMode) {
@@ -606,10 +605,7 @@
}
/**
- * Returns the tint mode for this drawable, or {@code null} if none set.
- *
- * @return the tint mode for this drawable, or {@code null} if none set
- * @hide
+ * @hide only needed by a hack within ProgressBar
*/
public Mode getTintMode() {
return mBitmapState.mTintMode;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 077db7a..21cd5db 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1248,16 +1248,14 @@
*/
static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
switch (value) {
- case 0:
- return Mode.SRC_IN;
- case 1:
- return Mode.SRC_ATOP;
- case 2:
- return Mode.MULTIPLY;
- case 3:
- return Mode.SCREEN;
+ case 3: return Mode.SRC_OVER;
+ case 5: return Mode.SRC_IN;
+ case 9: return Mode.SRC_ATOP;
+ case 14: return Mode.MULTIPLY;
+ case 15: return Mode.SCREEN;
+ case 16: return Mode.ADD;
+ default: return defaultMode;
}
- return defaultMode;
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 66193a5..3e9ca0a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -345,7 +345,6 @@
* Specifies the blending mode used to apply tint.
*
* @param tintMode A Porter-Duff blending mode
- * @hide Pending finalization of supported Modes
*/
public void setTintMode(Mode tintMode) {
if (mNinePatchState.mTintMode != tintMode) {
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 3323a25..2810c43 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -124,6 +124,41 @@
return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
}
+ /**
+ * Specifies a tint for drawing touch feedback ripples.
+ *
+ * @param tint Color state list to use for tinting touch feedback ripples,
+ * or null to clear the tint
+ */
+ public void setTint(ColorStateList tint) {
+ if (mState.mTint != tint) {
+ mState.mTint = tint;
+ invalidateSelf();
+ }
+ }
+
+ /**
+ * Returns the tint color for touch feedback ripples.
+ *
+ * @return Color state list to use for tinting touch feedback ripples, or
+ * null if none set
+ */
+ public ColorStateList getTint() {
+ return mState.mTint;
+ }
+
+ /**
+ * Specifies the blending mode used to draw touch feedback ripples.
+ *
+ * @param tintMode A Porter-Duff blending mode
+ */
+ public void setTintMode(Mode tintMode) {
+ if (mState.mTintMode != tintMode) {
+ mState.mTintMode = tintMode;
+ invalidateSelf();
+ }
+ }
+
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a84aa6b..140a07a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -192,7 +192,9 @@
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->addChild(op);
- if (displayList->isProjectionReceiver()) {
+
+ if (displayList->stagingProperties().isProjectionReceiver()) {
+ // use staging property, since recording on UI thread
mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index fd0fabc..fa0fb8a 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -105,6 +105,10 @@
return mDisplayListData && mDisplayListData->hasDrawOps;
}
+ const char* getName() const {
+ return mName.string();
+ }
+
void setName(const char* name) {
if (name) {
char* lastPeriod = strrchr(name, '.');
@@ -129,10 +133,6 @@
return mStagingProperties;
}
- bool isProjectionReceiver() {
- return properties().isProjectionReceiver();
- }
-
int getWidth() {
return properties().getWidth();
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c231f6f..af35344 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -347,6 +347,7 @@
if (mEglSurface != EGL_NO_SURFACE) {
mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
+ mGlobalContext->makeCurrent(mEglSurface);
mHaveNewSurface = true;
}
}
@@ -356,14 +357,15 @@
mHaveNewSurface = false;
}
-void CanvasContext::makeCurrent() {
+void CanvasContext::requireSurface() {
+ LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+ "requireSurface() called but no surface set!");
mGlobalContext->makeCurrent(mEglSurface);
}
bool CanvasContext::initialize(EGLNativeWindowType window) {
if (mCanvas) return false;
setSurface(window);
- makeCurrent();
mCanvas = new OpenGLRenderer();
mCanvas->initProperties();
return true;
@@ -371,7 +373,11 @@
void CanvasContext::updateSurface(EGLNativeWindowType window) {
setSurface(window);
- makeCurrent();
+}
+
+void CanvasContext::pauseSurface(EGLNativeWindowType window) {
+ // TODO: For now we just need a fence, in the future suspend any animations
+ // and such to prevent from trying to render into this surface
}
void CanvasContext::setup(int width, int height) {
@@ -460,7 +466,7 @@
if (!mCanvas) return;
- makeCurrent();
+ requireSurface();
Rect dirty;
mCanvas->invokeFunctors(dirty);
}
@@ -491,12 +497,12 @@
}
Layer* CanvasContext::createRenderLayer(int width, int height) {
- requireGlContext();
+ requireSurface();
return LayerRenderer::createRenderLayer(width, height);
}
Layer* CanvasContext::createTextureLayer() {
- requireGlContext();
+ requireSurface();
return LayerRenderer::createTextureLayer();
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 6f1c37f..9f64944 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -63,6 +63,7 @@
bool initialize(EGLNativeWindowType window);
void updateSurface(EGLNativeWindowType window);
+ void pauseSurface(EGLNativeWindowType window);
void setup(int width, int height);
void setDisplayListData(RenderNode* displayList, DisplayListData* newData);
void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
@@ -83,7 +84,7 @@
private:
void setSurface(EGLNativeWindowType window);
void swapBuffers();
- void makeCurrent();
+ void requireSurface();
friend class InvokeFunctorsTask;
void invokeFunctors();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index e817e61..a7c955e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -92,10 +92,10 @@
return (void*) args->context->initialize(args->window);
}
-bool RenderProxy::initialize(EGLNativeWindowType window) {
+bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
SETUP_TASK(initialize);
args->context = mContext;
- args->window = window;
+ args->window = window.get();
return (bool) postAndWait(task);
}
@@ -104,11 +104,23 @@
return NULL;
}
-void RenderProxy::updateSurface(EGLNativeWindowType window) {
+void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
SETUP_TASK(updateSurface);
args->context = mContext;
- args->window = window;
- post(task);
+ args->window = window.get();
+ postAndWait(task);
+}
+
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, EGLNativeWindowType window) {
+ args->context->pauseSurface(args->window);
+ return NULL;
+}
+
+void RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+ SETUP_TASK(pauseSurface);
+ args->context = mContext;
+ args->window = window.get();
+ postAndWait(task);
}
CREATE_BRIDGE3(setup, CanvasContext* context, int width, int height) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index c50da79..489bf20c1 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -59,8 +59,9 @@
ANDROID_API RenderProxy(bool translucent);
ANDROID_API virtual ~RenderProxy();
- ANDROID_API bool initialize(EGLNativeWindowType window);
- ANDROID_API void updateSurface(EGLNativeWindowType window);
+ ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+ ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
+ ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
ANDROID_API void setup(int width, int height);
ANDROID_API void setDisplayListData(RenderNode* renderNode, DisplayListData* newData);
ANDROID_API void drawDisplayList(RenderNode* displayList,
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index f688d81..664c707 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -471,10 +471,6 @@
final FocusRequester exFocusOwner = mFocusStack.pop();
exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
exFocusOwner.release();
- // clear RCD
- synchronized(mPRStack) {
- clearRemoteControlDisplay_syncAfRcs();
- }
}
}
}
@@ -535,10 +531,6 @@
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
- // there's a new top of the stack, let the remote control know
- synchronized(mPRStack) {
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
}
} else {
// focus is abandoned by a client that's not at the top of the stack,
@@ -582,10 +574,6 @@
// we removed an entry at the top of the stack:
// notify the new top of the stack it gained focus.
notifyTopOfAudioFocusStack();
- // there's a new top of the stack, let the remote control know
- synchronized(mPRStack) {
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
}
}
@@ -694,10 +682,6 @@
mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
clientId, afdh, callingPackageName, Binder.getCallingUid()));
- // there's a new top of the stack, let the remote control know
- synchronized(mPRStack) {
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
}//synchronized(mAudioFocusLock)
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
@@ -1237,11 +1221,11 @@
/**
* Helper function:
* Set the new remote control receiver at the top of the RC focus stack.
- * Called synchronized on mAudioFocusLock, then mPRStack
+ * Called synchronized on mPRStack
* precondition: mediaIntent != null
* @return true if mPRStack was changed, false otherwise
*/
- private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent,
+ private boolean pushMediaButtonReceiver_syncPrs(PendingIntent mediaIntent,
ComponentName target, IBinder token) {
// already at top of stack?
if (!mPRStack.empty() && mPRStack.peek().hasMatchingMediaButtonIntent(mediaIntent)) {
@@ -1285,10 +1269,10 @@
/**
* Helper function:
* Remove the remote control receiver from the RC focus stack.
- * Called synchronized on mAudioFocusLock, then mPRStack
+ * Called synchronized on mPRStack
* precondition: pi != null
*/
- private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
+ private void removeMediaButtonReceiver_syncPrs(PendingIntent pi) {
try {
for (int index = mPRStack.size()-1; index >= 0; index--) {
final PlayerRecord prse = mPRStack.elementAt(index);
@@ -1470,7 +1454,7 @@
* Helper function:
* Called synchronized on mPRStack
*/
- private void clearRemoteControlDisplay_syncAfRcs() {
+ private void clearRemoteControlDisplay_syncPrs() {
synchronized(mCurrentRcLock) {
mCurrentRcClient = null;
}
@@ -1480,20 +1464,20 @@
/**
* Helper function for code readability: only to be called from
- * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
+ * checkUpdateRemoteControlDisplay_syncPrs() which checks the preconditions for
* this method.
* Preconditions:
- * - called synchronized mAudioFocusLock then on mPRStack
+ * - called synchronized on mPRStack
* - mPRStack.isEmpty() is false
*/
- private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+ private void updateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
PlayerRecord prse = mPRStack.peek();
int infoFlagsAboutToBeUsed = infoChangedFlags;
// this is where we enforce opt-in for information display on the remote controls
// with the new AudioManager.registerRemoteControlClient() API
if (prse.getRcc() == null) {
//Log.w(TAG, "Can't update remote control display with null remote control client");
- clearRemoteControlDisplay_syncAfRcs();
+ clearRemoteControlDisplay_syncPrs();
return;
}
synchronized(mCurrentRcLock) {
@@ -1511,62 +1495,25 @@
/**
* Helper function:
- * Called synchronized on mAudioFocusLock, then mPRStack
+ * Called synchronized on mPRStack
* Check whether the remote control display should be updated, triggers the update if required
* @param infoChangedFlags the flags corresponding to the remote control client information
* that has changed, if applicable (checking for the update conditions might trigger a
* clear, rather than an update event).
*/
- private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
+ private void checkUpdateRemoteControlDisplay_syncPrs(int infoChangedFlags) {
// determine whether the remote control display should be refreshed
- // if either stack is empty, there is a mismatch, so clear the RC display
- if (mPRStack.isEmpty() || mFocusStack.isEmpty()) {
- clearRemoteControlDisplay_syncAfRcs();
+ // if the player record stack is empty, there is nothing to display, so clear the RC display
+ if (mPRStack.isEmpty()) {
+ clearRemoteControlDisplay_syncPrs();
return;
}
- // determine which entry in the AudioFocus stack to consider, and compare against the
- // top of the stack for the media button event receivers : simply using the top of the
- // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
- // notifications playing during music playback.
- // Crawl the AudioFocus stack from the top until an entry is found with the following
- // characteristics:
- // - focus gain on STREAM_MUSIC stream
- // - non-transient focus gain on a stream other than music
- FocusRequester af = null;
- try {
- for (int index = mFocusStack.size()-1; index >= 0; index--) {
- FocusRequester fr = mFocusStack.elementAt(index);
- if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
- || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
- af = fr;
- break;
- }
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
- af = null;
- }
- if (af == null) {
- clearRemoteControlDisplay_syncAfRcs();
- return;
- }
-
- // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
- if (!af.hasSamePackage(mPRStack.peek().getCallingPackageName())) {
- clearRemoteControlDisplay_syncAfRcs();
- return;
- }
- // if the audio focus didn't originate from the same Uid as the one in which the remote
- // control information will be retrieved, clear
- if (!af.hasSameUid(mPRStack.peek().getCallingUid())) {
- clearRemoteControlDisplay_syncAfRcs();
- return;
- }
+ // this is where more rules for refresh go
// refresh conditions were verified: update the remote controls
- // ok to call: synchronized mAudioFocusLock then on mPRStack, mPRStack is not empty
- updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
+ // ok to call: synchronized on mPRStack, mPRStack is not empty
+ updateRemoteControlDisplay_syncPrs(infoChangedFlags);
}
/**
@@ -1582,35 +1529,33 @@
private void onPromoteRcc(int rccId) {
if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
- synchronized(mAudioFocusLock) {
- synchronized(mPRStack) {
- // ignore if given RCC ID is already at top of remote control stack
- if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) {
- return;
- }
- int indexToPromote = -1;
- try {
- for (int index = mPRStack.size()-1; index >= 0; index--) {
- final PlayerRecord prse = mPRStack.elementAt(index);
- if (prse.getRccId() == rccId) {
- indexToPromote = index;
- break;
- }
+ synchronized(mPRStack) {
+ // ignore if given RCC ID is already at top of remote control stack
+ if (!mPRStack.isEmpty() && (mPRStack.peek().getRccId() == rccId)) {
+ return;
+ }
+ int indexToPromote = -1;
+ try {
+ for (int index = mPRStack.size()-1; index >= 0; index--) {
+ final PlayerRecord prse = mPRStack.elementAt(index);
+ if (prse.getRccId() == rccId) {
+ indexToPromote = index;
+ break;
}
- if (indexToPromote >= 0) {
- if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote
- + " to " + (mPRStack.size()-1)); }
- final PlayerRecord prse = mPRStack.remove(indexToPromote);
- mPRStack.push(prse);
- // the RC stack changed, reevaluate the display
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
}
- }//synchronized(mPRStack)
- }//synchronized(mAudioFocusLock)
+ if (indexToPromote >= 0) {
+ if (DEBUG_RC) { Log.d(TAG, " moving RCC from index " + indexToPromote
+ + " to " + (mPRStack.size()-1)); }
+ final PlayerRecord prse = mPRStack.remove(indexToPromote);
+ mPRStack.push(prse);
+ // the RC stack changed, reevaluate the display
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // not expected to happen, indicates improper concurrent modification
+ Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+ }
+ }//synchronized(mPRStack)
}
/**
@@ -1621,12 +1566,10 @@
IBinder token) {
Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent);
- synchronized(mAudioFocusLock) {
- synchronized(mPRStack) {
- if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) {
- // new RC client, assume every type of information shall be queried
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
+ synchronized(mPRStack) {
+ if (pushMediaButtonReceiver_syncPrs(mediaIntent, eventReceiver, token)) {
+ // new RC client, assume every type of information shall be queried
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
}
}
}
@@ -1639,14 +1582,12 @@
{
Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent);
- synchronized(mAudioFocusLock) {
- synchronized(mPRStack) {
- boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
- removeMediaButtonReceiver_syncAfRcs(mediaIntent);
- if (topOfStackWillChange) {
- // current RC client will change, assume every type of info needs to be queried
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
+ synchronized(mPRStack) {
+ boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
+ removeMediaButtonReceiver_syncPrs(mediaIntent);
+ if (topOfStackWillChange) {
+ // current RC client will change, assume every type of info needs to be queried
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
}
}
}
@@ -1697,42 +1638,40 @@
IRemoteControlClient rcClient, String callingPackageName) {
if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
- synchronized(mAudioFocusLock) {
- synchronized(mPRStack) {
- // store the new display information
- try {
- for (int index = mPRStack.size()-1; index >= 0; index--) {
- final PlayerRecord prse = mPRStack.elementAt(index);
- if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
- prse.resetControllerInfoForRcc(rcClient, callingPackageName,
- Binder.getCallingUid());
+ synchronized(mPRStack) {
+ // store the new display information
+ try {
+ for (int index = mPRStack.size()-1; index >= 0; index--) {
+ final PlayerRecord prse = mPRStack.elementAt(index);
+ if(prse.hasMatchingMediaButtonIntent(mediaIntent)) {
+ prse.resetControllerInfoForRcc(rcClient, callingPackageName,
+ Binder.getCallingUid());
- if (rcClient == null) {
- break;
- }
-
- rccId = prse.getRccId();
-
- // there is a new (non-null) client:
- // give the new client the displays (if any)
- if (mRcDisplays.size() > 0) {
- plugRemoteControlDisplaysIntoClient_syncRcStack(prse.getRcc());
- }
+ if (rcClient == null) {
break;
}
- }//for
- } catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
- }
- // if the eventReceiver is at the top of the stack
- // then check for potential refresh of the remote controls
- if (isCurrentRcController(mediaIntent)) {
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
- }//synchronized(mPRStack)
- }//synchronized(mAudioFocusLock)
+ rccId = prse.getRccId();
+
+ // there is a new (non-null) client:
+ // give the new client the displays (if any)
+ if (mRcDisplays.size() > 0) {
+ plugRemoteControlDisplaysIntoClient_syncPrs(prse.getRcc());
+ }
+ break;
+ }
+ }//for
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // not expected to happen, indicates improper concurrent modification
+ Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+ }
+
+ // if the eventReceiver is at the top of the stack
+ // then check for potential refresh of the remote controls
+ if (isCurrentRcController(mediaIntent)) {
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
+ }
+ }//synchronized(mPRStack)
return rccId;
}
@@ -1743,29 +1682,27 @@
protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
IRemoteControlClient rcClient) {
if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
- synchronized(mAudioFocusLock) {
- synchronized(mPRStack) {
- boolean topRccChange = false;
- try {
- for (int index = mPRStack.size()-1; index >= 0; index--) {
- final PlayerRecord prse = mPRStack.elementAt(index);
- if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
- && rcClient.equals(prse.getRcc())) {
- // we found the IRemoteControlClient to unregister
- prse.resetControllerInfoForNoRcc();
- topRccChange = (index == mPRStack.size()-1);
- // there can only be one matching RCC in the RC stack, we're done
- break;
- }
+ synchronized(mPRStack) {
+ boolean topRccChange = false;
+ try {
+ for (int index = mPRStack.size()-1; index >= 0; index--) {
+ final PlayerRecord prse = mPRStack.elementAt(index);
+ if ((prse.hasMatchingMediaButtonIntent(mediaIntent))
+ && rcClient.equals(prse.getRcc())) {
+ // we found the IRemoteControlClient to unregister
+ prse.resetControllerInfoForNoRcc();
+ topRccChange = (index == mPRStack.size()-1);
+ // there can only be one matching RCC in the RC stack, we're done
+ break;
}
- } catch (ArrayIndexOutOfBoundsException e) {
- // not expected to happen, indicates improper concurrent modification
- Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
}
- if (topRccChange) {
- // no more RCC for the RCD, check for potential refresh of the remote controls
- checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
- }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // not expected to happen, indicates improper concurrent modification
+ Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
+ }
+ if (topRccChange) {
+ // no more RCC for the RCD, check for potential refresh of the remote controls
+ checkUpdateRemoteControlDisplay_syncPrs(RC_INFO_ALL);
}
}
}
@@ -1843,7 +1780,7 @@
* Plug each registered display into the specified client
* @param rcc, guaranteed non null
*/
- private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
+ private void plugRemoteControlDisplaysIntoClient_syncPrs(IRemoteControlClient rcc) {
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
final DisplayInfoForServer di = displayIterator.next();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 26498ca..edfa36a 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -552,29 +552,72 @@
};
int availableFormatTag = CameraMetadataNative.getTag("android.scaler.availableFormats");
- // Write
- mMetadata.set(CameraCharacteristics.SCALER_AVAILABLE_FORMATS, availableFormats);
+ Key<int[]> formatKey = CameraCharacteristics.SCALER_AVAILABLE_FORMATS;
- byte[] availableFormatValues = mMetadata.readValues(availableFormatTag);
+ validateArrayMetadataReadWriteOverride(formatKey, availableFormats,
+ expectedIntValues, availableFormatTag);
- ByteBuffer bf = ByteBuffer.wrap(availableFormatValues).order(ByteOrder.nativeOrder());
+ //
+ // android.scaler.availableStreamConfigurations (int x n x 4 array)
+ //
+ final int OUTPUT = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT;
+ int[] availableStreamConfigs = new int[] {
+ 0x20, 3280, 2464, OUTPUT, // RAW16
+ 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+ 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+ 0x100, 3264, 2448, OUTPUT, // ImageFormat.JPEG
+ 0x100, 3200, 2400, OUTPUT, // ImageFormat.JPEG
+ 0x100, 2592, 1944, OUTPUT, // ImageFormat.JPEG
+ 0x100, 2048, 1536, OUTPUT, // ImageFormat.JPEG
+ 0x100, 1920, 1080, OUTPUT // ImageFormat.JPEG
+ };
+ int[] expectedAvailableStreamConfigs = new int[] {
+ 0x20, 3280, 2464, OUTPUT, // RAW16
+ 0x23, 3264, 2448, OUTPUT, // YCbCr_420_888
+ 0x23, 3200, 2400, OUTPUT, // YCbCr_420_888
+ 0x21, 3264, 2448, OUTPUT, // BLOB
+ 0x21, 3200, 2400, OUTPUT, // BLOB
+ 0x21, 2592, 1944, OUTPUT, // BLOB
+ 0x21, 2048, 1536, OUTPUT, // BLOB
+ 0x21, 1920, 1080, OUTPUT // BLOB
+ };
+ int availableStreamConfigTag =
+ CameraMetadataNative.getTag("android.scaler.availableStreamConfigurations");
- assertEquals(expectedIntValues.length * 4, availableFormatValues.length);
- for (int i = 0; i < expectedIntValues.length; ++i) {
- assertEquals(expectedIntValues[i], bf.getInt());
- }
- // Read
- byte[] availableFormatsAsByteArray = new byte[expectedIntValues.length * 4];
- ByteBuffer availableFormatsByteBuffer =
- ByteBuffer.wrap(availableFormatsAsByteArray).order(ByteOrder.nativeOrder());
- for (int value : expectedIntValues) {
- availableFormatsByteBuffer.putInt(value);
- }
- mMetadata.writeValues(availableFormatTag, availableFormatsAsByteArray);
+ Key<int[]> configKey = CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+ validateArrayMetadataReadWriteOverride(configKey, availableStreamConfigs,
+ expectedAvailableStreamConfigs, availableStreamConfigTag);
- int[] resultFormats = mMetadata.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS);
- assertNotNull("result available formats shouldn't be null", resultFormats);
- assertArrayEquals(availableFormats, resultFormats);
+ //
+ // android.scaler.availableMinFrameDurations (int x n x 4 array)
+
+ //
+ long[] availableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333336, // RAW16
+ 0x23, 3264, 2448, 33333336, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333336, // YCbCr_420_888
+ 0x100, 3264, 2448, 33333336, // ImageFormat.JPEG
+ 0x100, 3200, 2400, 33333336, // ImageFormat.JPEG
+ 0x100, 2592, 1944, 33333336, // ImageFormat.JPEG
+ 0x100, 2048, 1536, 33333336, // ImageFormat.JPEG
+ 0x100, 1920, 1080, 33333336 // ImageFormat.JPEG
+ };
+ long[] expectedAvailableMinDurations = new long[] {
+ 0x20, 3280, 2464, 33333336, // RAW16
+ 0x23, 3264, 2448, 33333336, // YCbCr_420_888
+ 0x23, 3200, 2400, 33333336, // YCbCr_420_888
+ 0x21, 3264, 2448, 33333336, // BLOB
+ 0x21, 3200, 2400, 33333336, // BLOB
+ 0x21, 2592, 1944, 33333336, // BLOB
+ 0x21, 2048, 1536, 33333336, // BLOB
+ 0x21, 1920, 1080, 33333336 // BLOB
+ };
+ int availableMinDurationsTag =
+ CameraMetadataNative.getTag("android.scaler.availableMinFrameDurations");
+
+ Key<long[]> durationKey = CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ validateArrayMetadataReadWriteOverride(durationKey, availableMinDurations,
+ expectedAvailableMinDurations, availableMinDurationsTag);
//
// android.statistics.faces (Face x n array)
@@ -639,4 +682,59 @@
}
}
+
+ /**
+ * Validate metadata array tag read/write override.
+ *
+ * <p>Only support long and int array for now, can be easily extend to support other
+ * primitive arrays.</p>
+ */
+ private <T> void validateArrayMetadataReadWriteOverride(Key<T> key, T writeValues,
+ T readValues, int tag) {
+ Class<T> type = key.getType();
+ if (!type.isArray()) {
+ throw new IllegalArgumentException("This function expects an key with array type");
+ } else if (type != int[].class && type != long[].class) {
+ throw new IllegalArgumentException("This function expects long or int array values");
+ }
+
+ // Write
+ mMetadata.set(key, writeValues);
+
+ byte[] readOutValues = mMetadata.readValues(tag);
+
+ ByteBuffer bf = ByteBuffer.wrap(readOutValues).order(ByteOrder.nativeOrder());
+
+ int readValuesLength = Array.getLength(readValues);
+ int readValuesNumBytes = readValuesLength * 4;
+ if (type == long[].class) {
+ readValuesNumBytes = readValuesLength * 8;
+ }
+
+ assertEquals(readValuesNumBytes, readOutValues.length);
+ for (int i = 0; i < readValuesLength; ++i) {
+ if (type == int[].class) {
+ assertEquals(Array.getInt(readValues, i), bf.getInt());
+ } else if (type == long[].class) {
+ assertEquals(Array.getLong(readValues, i), bf.getLong());
+ }
+ }
+
+ // Read
+ byte[] readOutValuesAsByteArray = new byte[readValuesNumBytes];
+ ByteBuffer readOutValuesByteBuffer =
+ ByteBuffer.wrap(readOutValuesAsByteArray).order(ByteOrder.nativeOrder());
+ for (int i = 0; i < readValuesLength; ++i) {
+ if (type == int[].class) {
+ readOutValuesByteBuffer.putInt(Array.getInt(readValues, i));
+ } else if (type == long[].class) {
+ readOutValuesByteBuffer.putLong(Array.getLong(readValues, i));
+ }
+ }
+ mMetadata.writeValues(tag, readOutValuesAsByteArray);
+
+ T result = mMetadata.get(key);
+ assertNotNull(key.getName() + " result shouldn't be null", result);
+ assertArrayEquals(writeValues, result);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index dd75921..64c67b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -43,6 +43,7 @@
boolean mVisible;
boolean mTaskLaunched;
+ // Broadcast receiver to handle messages from our RecentsService
BroadcastReceiver mServiceBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -63,6 +64,14 @@
}
};
+ // Broadcast receiver to handle messages from the system
+ BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ finish();
+ }
+ };
+
/** Updates the set of recent tasks */
void updateRecentsTasks() {
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
@@ -111,12 +120,6 @@
RecentsTaskLoader.initialize(this);
RecentsConfiguration.reinitialize(this);
- // Set the background dim
- WindowManager.LayoutParams wlp = getWindow().getAttributes();
- wlp.dimAmount = Constants.Values.Window.BackgroundDim;
- getWindow().setAttributes(wlp);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
-
// Create the view hierarchy
mRecentsView = new RecentsView(this);
mRecentsView.setCallbacks(this);
@@ -170,12 +173,37 @@
Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
Console.AnsiRed);
super.onResume();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ "[RecentsActivity|onAttachedToWindow]", "",
+ Console.AnsiRed);
+ super.onAttachedToWindow();
// Register the broadcast receiver to handle messages from our service
IntentFilter filter = new IntentFilter();
filter.addAction(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY);
filter.addAction(RecentsService.ACTION_FINISH_RECENTS_ACTIVITY);
registerReceiver(mServiceBroadcastReceiver, filter);
+
+ // Register the broadcast receiver to handle messages when the screen is turned off
+ filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ registerReceiver(mScreenOffReceiver, filter);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+ "[RecentsActivity|onDetachedFromWindow]", "",
+ Console.AnsiRed);
+ super.onDetachedFromWindow();
+
+ // Unregister any broadcast receivers we have registered
+ unregisterReceiver(mServiceBroadcastReceiver);
+ unregisterReceiver(mScreenOffReceiver);
}
@Override
@@ -183,9 +211,6 @@
Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
Console.AnsiRed);
super.onPause();
-
- // Unregister any broadcast receivers we have registered
- unregisterReceiver(mServiceBroadcastReceiver);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 4a0de0b..94a655f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.util.DisplayMetrics;
@@ -62,6 +63,12 @@
DisplayMetrics dm = res.getDisplayMetrics();
mDisplayMetrics = dm;
+ boolean isLandscape = res.getConfiguration().orientation ==
+ Configuration.ORIENTATION_LANDSCAPE;
+ Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+ "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
+ Console.AnsiGreen);
+
displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
animationPxMovementPerSecond =
res.getDimensionPixelSize(R.dimen.recents_animation_movement_in_dps_per_second);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index d661f287..754d956 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -22,7 +22,6 @@
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -213,6 +212,7 @@
Console.log(Constants.DebugFlags.App.TaskDataLoader,
" [TaskResourceLoader|loadThumbnail]",
thumbnail);
+ thumbnail.setHasAlpha(false);
loadThumbnail = thumbnail;
mThumbnailCache.put(t.key, thumbnail);
} else {
@@ -331,13 +331,9 @@
// Create the default assets
Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+ icon.eraseColor(0x00000000);
mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas();
- c.setBitmap(icon);
- c.drawColor(0x00000000);
- c.setBitmap(mDefaultThumbnail);
- c.drawColor(0x00000000);
- c.setBitmap(null);
+ mDefaultThumbnail.eraseColor(0x00000000);
mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
Console.log(Constants.DebugFlags.App.TaskDataLoader,
"[RecentsTaskLoader|defaultBitmaps]",
@@ -454,6 +450,7 @@
"[RecentsTaskLoader|loadingTaskThumbnail]");
task.thumbnail = ssp.getTaskThumbnail(task.key.id);
if (task.thumbnail != null) {
+ task.thumbnail.setHasAlpha(false);
mThumbnailCache.put(task.key, task.thumbnail);
} else {
task.thumbnail = mDefaultThumbnail;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index efcd948..505238d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -24,7 +24,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -52,9 +51,7 @@
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
// Create a dummy icon
mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(mDummyIcon);
- c.drawColor(0xFF999999);
- c.setBitmap(null);
+ mDummyIcon.eraseColor(0xFF999999);
}
}
@@ -117,9 +114,7 @@
// If we are mocking, then just return a dummy thumbnail
if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
Bitmap thumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- Canvas c = new Canvas(thumbnail);
- c.drawColor(0xff333333);
- c.setBitmap(null);
+ thumbnail.eraseColor(0xff333333);
return thumbnail;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 1ebe231..141d870 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -108,6 +108,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -118,6 +119,7 @@
// We measure our stack views sans the status bar. It will handle the nav bar itself.
RecentsConfiguration config = RecentsConfiguration.getInstance();
+ int childWidth = width - config.systemInsets.right;
int childHeight = height - config.systemInsets.top;
// Measure each child
@@ -125,7 +127,7 @@
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
- child.measure(widthMeasureSpec,
+ child.measure(MeasureSpec.makeMeasureSpec(childWidth, widthMode),
MeasureSpec.makeMeasureSpec(childHeight, heightMode));
}
}
@@ -255,11 +257,11 @@
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
try {
+ UserHandle taskUser = new UserHandle(task.userId);
if (opts != null) {
- getContext().startActivityAsUser(i, opts.toBundle(),
- new UserHandle(task.userId));
+ getContext().startActivityAsUser(i, opts.toBundle(), taskUser);
} else {
- getContext().startActivityAsUser(i, new UserHandle(task.userId));
+ getContext().startActivityAsUser(i, taskUser);
}
} catch (ActivityNotFoundException anfe) {
Console.logError(getContext(), "Could not start Activity");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index fa06764..c9a491e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -524,8 +524,8 @@
(Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height()));
int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height()));
int centerX = mStackRect.centerX();
- mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top,
- centerX + size / 2, mStackRectSansPeek.top + size);
+ mTaskRect.set(mStackRect.left, mStackRectSansPeek.top,
+ mStackRect.right, mStackRectSansPeek.top + size);
// Update the scroll bounds
updateMinMaxScroll(false);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 972b088..79c4a50 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -151,8 +151,11 @@
private void removeUser(int userId) {
synchronized (mLock) {
+ UserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ return;
+ }
// Release created sessions.
- UserState userState = getUserStateLocked(userId);
for (SessionState state : userState.sessionStateMap.values()) {
if (state.session != null) {
try {