summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Activity.java7
-rw-r--r--core/java/android/provider/MediaStore.java30
-rw-r--r--core/java/android/view/GLES20Canvas.java23
-rw-r--r--core/java/android/view/HardwareRenderer.java148
-rw-r--r--core/java/android/view/ViewRoot.java34
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp3
-rw-r--r--core/res/res/values/themes.xml1
-rw-r--r--docs/html/resources/samples/images/sample_notepadtest_junit.pngbin0 -> 20515 bytes
-rw-r--r--include/private/surfaceflinger/SharedBufferStack.h18
-rw-r--r--include/surfaceflinger/Surface.h3
-rw-r--r--include/ui/egl/android_natives.h29
-rw-r--r--libs/hwui/Caches.h77
-rw-r--r--libs/hwui/GenerationCache.h10
-rw-r--r--libs/hwui/GradientCache.cpp15
-rw-r--r--libs/hwui/GradientCache.h1
-rw-r--r--libs/hwui/LayerCache.cpp13
-rw-r--r--libs/hwui/LayerCache.h1
-rw-r--r--libs/hwui/OpenGLRenderer.cpp164
-rw-r--r--libs/hwui/OpenGLRenderer.h26
-rw-r--r--libs/hwui/PatchCache.cpp4
-rw-r--r--libs/hwui/PatchCache.h1
-rw-r--r--libs/hwui/PathCache.cpp26
-rw-r--r--libs/hwui/PathCache.h3
-rw-r--r--libs/hwui/ProgramCache.h1
-rw-r--r--libs/hwui/Properties.h12
-rw-r--r--libs/hwui/TextDropShadowCache.cpp14
-rw-r--r--libs/hwui/TextDropShadowCache.h21
-rw-r--r--libs/hwui/TextureCache.cpp27
-rw-r--r--libs/hwui/TextureCache.h3
-rw-r--r--libs/surfaceflinger_client/SharedBufferStack.cpp46
-rw-r--r--libs/surfaceflinger_client/Surface.cpp22
-rw-r--r--media/libstagefright/AwesomePlayer.cpp22
-rw-r--r--media/libstagefright/include/ARTSPController.h2
-rw-r--r--media/libstagefright/include/AwesomePlayer.h1
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp52
-rw-r--r--media/libstagefright/rtsp/APacketSource.h5
-rw-r--r--media/libstagefright/rtsp/ARTSPController.cpp12
-rw-r--r--media/libstagefright/rtsp/MyHandler.h109
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java182
-rw-r--r--services/surfaceflinger/Layer.cpp9
-rw-r--r--services/surfaceflinger/LayerBase.cpp107
-rw-r--r--services/surfaceflinger/LayerBase.h8
-rw-r--r--services/surfaceflinger/LayerBlur.cpp2
-rw-r--r--services/surfaceflinger/LayerBuffer.cpp2
-rw-r--r--services/surfaceflinger/TextureManager.h3
-rw-r--r--tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java12
-rw-r--r--voip/java/android/net/sip/SipProfile.java41
48 files changed, 990 insertions, 365 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bf660ea94df9..425b2849c633 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4281,7 +4281,14 @@ public class Activity extends ContextThemeWrapper
final void performPause() {
mFragments.dispatchPause();
+ mCalled = false;
onPause();
+ if (!mCalled && getApplicationInfo().targetSdkVersion
+ >= android.os.Build.VERSION_CODES.GINGERBREAD) {
+ throw new SuperNotCalledException(
+ "Activity " + mComponent.toShortString() +
+ " did not call through to super.onPause()");
+ }
}
final void performUserLeaving() {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 227d94d85229..60ccdafc0a9b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -322,6 +322,8 @@ public final class MediaStore {
private static final int MICRO_KIND = 3;
private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
static final int DEFAULT_GROUP_ID = 0;
+ private static final Object sThumbBufLock = new Object();
+ private static byte[] sThumbBuf;
private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) {
Bitmap bitmap = null;
@@ -397,11 +399,15 @@ public final class MediaStore {
long magic = thumbFile.getMagic(origId);
if (magic != 0) {
if (kind == MICRO_KIND) {
- byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
- if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
- bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap == null) {
- Log.w(TAG, "couldn't decode byte array.");
+ synchronized (sThumbBufLock) {
+ if (sThumbBuf == null) {
+ sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
+ }
+ if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
+ bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
+ if (bitmap == null) {
+ Log.w(TAG, "couldn't decode byte array.");
+ }
}
}
return bitmap;
@@ -427,11 +433,15 @@ public final class MediaStore {
// Assuming thumbnail has been generated, at least original image exists.
if (kind == MICRO_KIND) {
- byte[] data = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
- if (thumbFile.getMiniThumbFromFile(origId, data) != null) {
- bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bitmap == null) {
- Log.w(TAG, "couldn't decode byte array.");
+ synchronized (sThumbBufLock) {
+ if (sThumbBuf == null) {
+ sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
+ }
+ if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
+ bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
+ if (bitmap == null) {
+ Log.w(TAG, "couldn't decode byte array.");
+ }
}
}
} else if (kind == MINI_KIND) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 4c72e9502cef..b058685009c4 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -44,7 +44,7 @@ class GLES20Canvas extends Canvas {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final GL mGl;
private final boolean mOpaque;
- private final int mRenderer;
+ private int mRenderer;
private int mWidth;
private int mHeight;
@@ -76,16 +76,25 @@ class GLES20Canvas extends Canvas {
mOpaque = !translucent;
mRenderer = nCreateRenderer();
+ if (mRenderer == 0) {
+ throw new IllegalStateException("Could not create GLES20Canvas renderer");
+ }
}
-
+
private native int nCreateRenderer();
- @Override
- protected void finalize() throws Throwable {
- try {
- super.finalize();
- } finally {
+ /**
+ * This method <strong>must</strong> be called before releasing a
+ * reference to a GLES20Canvas. This method is responsible for freeing
+ * native resources associated with the hardware. Not invoking this
+ * method properly can result in memory leaks.
+ *
+ * @hide
+ */
+ public synchronized void destroy() {
+ if (mRenderer != 0) {
nDestroyRenderer(mRenderer);
+ mRenderer = 0;
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ca60a8966fe5..32d8123cd6f8 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -35,9 +35,10 @@ import javax.microedition.khronos.opengles.GL;
* @hide
*/
public abstract class HardwareRenderer {
+ private static final String LOG_TAG = "HardwareRenderer";
+
private boolean mEnabled;
private boolean mRequested = true;
- private static final String LOG_TAG = "HardwareRenderer";
/**
* Indicates whether hardware acceleration is available under any form for
@@ -70,9 +71,8 @@ public abstract class HardwareRenderer {
*
* @param width Width of the drawing surface.
* @param height Height of the drawing surface.
- * @param attachInfo The AttachInfo used to render the ViewRoot.
*/
- abstract void setup(int width, int height, View.AttachInfo attachInfo);
+ abstract void setup(int width, int height);
/**
* Draws the specified view.
@@ -96,12 +96,11 @@ public abstract class HardwareRenderer {
*/
void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
SurfaceHolder holder) {
-
if (isRequested()) {
// We lost the gl context, so recreate it.
if (!isEnabled()) {
if (initialize(holder)) {
- setup(width, height, attachInfo);
+ setup(width, height);
}
}
}
@@ -165,18 +164,23 @@ public abstract class HardwareRenderer {
static abstract class GlRenderer extends HardwareRenderer {
private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- EGL10 mEgl;
- EGLDisplay mEglDisplay;
- EGLContext mEglContext;
- EGLSurface mEglSurface;
- EGLConfig mEglConfig;
+ static EGLContext sEglContext;
+ static EGL10 sEgl;
+ static EGLDisplay sEglDisplay;
+ static EGLConfig sEglConfig;
+ private static Thread sEglThread;
+
+ EGLSurface mEglSurface;
+
GL mGl;
- Canvas mCanvas;
+ GLES20Canvas mCanvas;
final int mGlVersion;
final boolean mTranslucent;
+ private boolean mDestroyed;
+
GlRenderer(int glVersion, boolean translucent) {
mGlVersion = glVersion;
mTranslucent = translucent;
@@ -189,7 +193,7 @@ public abstract class HardwareRenderer {
*/
void checkErrors() {
if (isEnabled()) {
- int error = mEgl.eglGetError();
+ int error = sEgl.eglGetError();
if (error != EGL10.EGL_SUCCESS) {
// something bad has happened revert to
// normal rendering.
@@ -208,13 +212,17 @@ public abstract class HardwareRenderer {
if (isRequested() && !isEnabled()) {
initializeEgl();
mGl = createEglSurface(holder);
+ mDestroyed = false;
if (mGl != null) {
- int err = mEgl.eglGetError();
+ int err = sEgl.eglGetError();
if (err != EGL10.EGL_SUCCESS) {
destroy();
setRequested(false);
} else {
+ if (mCanvas != null) {
+ destroyCanvas();
+ }
mCanvas = createCanvas();
if (mCanvas != null) {
setEnabled(true);
@@ -229,64 +237,75 @@ public abstract class HardwareRenderer {
return false;
}
- abstract Canvas createCanvas();
+ private void destroyCanvas() {
+ mCanvas.destroy();
+ mCanvas = null;
+ }
+
+ abstract GLES20Canvas createCanvas();
void initializeEgl() {
- mEgl = (EGL10) EGLContext.getEGL();
+ if (sEglContext != null) return;
+
+ sEglThread = Thread.currentThread();
+ sEgl = (EGL10) EGLContext.getEGL();
// Get to the default display.
- mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+ sEglDisplay = sEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
- if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+ if (sEglDisplay == EGL10.EGL_NO_DISPLAY) {
throw new RuntimeException("eglGetDisplay failed");
}
// We can now initialize EGL for that display
int[] version = new int[2];
- if (!mEgl.eglInitialize(mEglDisplay, version)) {
+ if (!sEgl.eglInitialize(sEglDisplay, version)) {
throw new RuntimeException("eglInitialize failed");
}
- mEglConfig = getConfigChooser(mGlVersion).chooseConfig(mEgl, mEglDisplay);
+ sEglConfig = getConfigChooser(mGlVersion).chooseConfig(sEgl, sEglDisplay);
/*
* Create an EGL context. We want to do this as rarely as we can, because an
* EGL context is a somewhat heavy object.
*/
- mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+ sEglContext = createContext(sEgl, sEglDisplay, sEglConfig);
}
GL createEglSurface(SurfaceHolder holder) {
// Check preconditions.
- if (mEgl == null) {
+ if (sEgl == null) {
throw new RuntimeException("egl not initialized");
}
- if (mEglDisplay == null) {
+ if (sEglDisplay == null) {
throw new RuntimeException("eglDisplay not initialized");
}
- if (mEglConfig == null) {
+ if (sEglConfig == null) {
throw new RuntimeException("mEglConfig not initialized");
}
+ if (Thread.currentThread() != sEglThread) {
+ throw new IllegalStateException("HardwareRenderer cannot be used "
+ + "from multiple threads");
+ }
/*
* The window size has changed, so we need to create a new
* surface.
*/
if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
-
/*
* Unbind and destroy the old EGL surface, if
* there is one.
*/
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+ sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
}
// Create an EGL surface we can render into.
- mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, holder, null);
+ mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
- int error = mEgl.eglGetError();
+ int error = sEgl.eglGetError();
if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
return null;
@@ -298,11 +317,11 @@ public abstract class HardwareRenderer {
* Before we can issue GL commands, we need to make sure
* the context is current and bound to a surface.
*/
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
- return mEglContext.getGL();
+ return sEglContext.getGL();
}
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
@@ -315,7 +334,6 @@ public abstract class HardwareRenderer {
@Override
void initializeIfNeeded(int width, int height, View.AttachInfo attachInfo,
SurfaceHolder holder) {
-
if (isRequested()) {
checkErrors();
super.initializeIfNeeded(width, height, attachInfo, holder);
@@ -324,28 +342,34 @@ public abstract class HardwareRenderer {
@Override
void destroy() {
- if (!isEnabled()) return;
+ if (!isEnabled() || mDestroyed) return;
+
+ mDestroyed = true;
- mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
+ checkCurrent();
+ // Destroy the Canvas first in case it needs to use a GL context
+ // to perform its cleanup.
+ destroyCanvas();
+
+ sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
- mEgl.eglTerminate(mEglDisplay);
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
- mEglContext = null;
mEglSurface = null;
- mEglDisplay = null;
- mEgl = null;
mGl = null;
- mCanvas = null;
+
+ // mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ // mEglContext = null;
+ // mEgl.eglTerminate(mEglDisplay);
+ // mEgl = null;
+ // mEglDisplay = null;
setEnabled(false);
- }
-
+ }
+
@Override
- void setup(int width, int height, View.AttachInfo attachInfo) {
- final float scale = attachInfo.mApplicationScale;
- mCanvas.setViewport((int) (width * scale + 0.5f), (int) (height * scale + 0.5f));
+ void setup(int width, int height) {
+ mCanvas.setViewport(width, height);
}
boolean canDraw() {
@@ -363,7 +387,8 @@ public abstract class HardwareRenderer {
* @param glVersion
*/
EglConfigChooser getConfigChooser(int glVersion) {
- return new ComponentSizeChooser(glVersion, 8, 8, 8, mTranslucent ? 8 : 0, 0, 0);
+ // TODO: Check for mTranslucent here, which means at least 2 EGL contexts
+ return new ComponentSizeChooser(glVersion, 8, 8, 8, 8, 0, 0);
}
@Override
@@ -373,14 +398,7 @@ public abstract class HardwareRenderer {
attachInfo.mIgnoreDirtyState = true;
view.mPrivateFlags |= View.DRAWN;
- // TODO: Don't check the current context when we have one per UI thread
- // TODO: Use a threadlocal flag to know whether the surface has changed
- if (mEgl.eglGetCurrentContext() != mEglContext ||
- mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
- if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- throw new RuntimeException("eglMakeCurrent failed");
- }
- }
+ checkCurrent();
onPreDraw();
@@ -396,11 +414,22 @@ public abstract class HardwareRenderer {
attachInfo.mIgnoreDirtyState = false;
- mEgl.eglSwapBuffers(mEglDisplay, mEglSurface);
+ sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
checkErrors();
}
}
+ private void checkCurrent() {
+ // TODO: Don't check the current context when we have one per UI thread
+ // TODO: Use a threadlocal flag to know whether the surface has changed
+ if (sEgl.eglGetCurrentContext() != sEglContext ||
+ sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
+ if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed");
+ }
+ }
+ }
+
static abstract class EglConfigChooser {
final int[] mConfigSpec;
private final int mGlVersion;
@@ -496,7 +525,7 @@ public abstract class HardwareRenderer {
int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
- if (r == mRedSize && g == mGreenSize && b == mBlueSize && a >= mAlphaSize) {
+ if (r >= mRedSize && g >= mGreenSize && b >= mBlueSize && a >= mAlphaSize) {
return config;
}
}
@@ -514,7 +543,7 @@ public abstract class HardwareRenderer {
}
}
}
-
+
/**
* Hardware renderer using OpenGL ES 2.0.
*/
@@ -526,8 +555,9 @@ public abstract class HardwareRenderer {
}
@Override
- Canvas createCanvas() {
- return mGlCanvas = new GLES20Canvas(mGl, mTranslucent);
+ GLES20Canvas createCanvas() {
+ // TODO: Pass mTranslucent instead of true
+ return mGlCanvas = new GLES20Canvas(mGl, true);
}
@Override
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index d32ccb1ddbbc..5999aba42e5e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -251,7 +251,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
mTempRect = new Rect();
mVisRect = new Rect();
mWinFrame = new Rect();
- mWindow = new W(this, context);
+ mWindow = new W(this);
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
@@ -469,6 +469,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
if (attrs != null &&
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+ destroyHardwareRenderer();
mHwRenderer = HardwareRenderer.createGlRenderer(2, translucent);
}
}
@@ -677,9 +678,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
attachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
- if (mHwRenderer != null) {
- mHwRenderer.destroy();
- }
+ destroyHardwareRenderer();
}
if (viewVisibility == View.GONE) {
// After making a window gone, we will count it as being
@@ -963,7 +962,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
if (hwIntialized) {
- mHwRenderer.setup(mWidth, mHeight, mAttachInfo);
+ mHwRenderer.setup(mWidth, mHeight);
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1598,9 +1597,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
mAttachInfo.mRootView = null;
mAttachInfo.mSurface = null;
- if (mHwRenderer != null) {
- mHwRenderer.destroy();
- }
+ destroyHardwareRenderer();
+ mHwRenderer = null;
+
mSurface.release();
if (mInputChannel != null) {
@@ -1625,6 +1624,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
}
+ private void destroyHardwareRenderer() {
+ if (mHwRenderer != null) {
+ mHwRenderer.destroy();
+ }
+ }
+
void updateConfiguration(Configuration config, boolean force) {
if (DEBUG_CONFIGURATION) Log.v(TAG,
"Applying new config to window "
@@ -2734,10 +2739,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
public void childDrawableStateChanged(View child) {
}
- protected Rect getWindowFrame() {
- return mWinFrame;
- }
-
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
@@ -2816,16 +2817,15 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
static class W extends IWindow.Stub {
private final WeakReference<ViewRoot> mViewRoot;
- public W(ViewRoot viewRoot, Context context) {
+ W(ViewRoot viewRoot) {
mViewRoot = new WeakReference<ViewRoot>(viewRoot);
}
- public void resized(int w, int h, Rect coveredInsets,
- Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
+ public void resized(int w, int h, Rect coveredInsets, Rect visibleInsets,
+ boolean reportDraw, Configuration newConfig) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
- viewRoot.dispatchResized(w, h, coveredInsets,
- visibleInsets, reportDraw, newConfig);
+ viewRoot.dispatchResized(w, h, coveredInsets, visibleInsets, reportDraw, newConfig);
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4c6ecedff6ae..98c03a65f6fb 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -34,7 +34,6 @@
#include <SkiaShader.h>
#include <SkiaColorFilter.h>
#include <Rect.h>
-#include <ui/Rect.h>
#include "TextLayout.h"
@@ -418,7 +417,7 @@ static JNINativeMethod gMethods[] = {
{ "nDrawTextRun", "(ILjava/lang/String;IIIIFFII)V",
(void*) android_view_GLES20Canvas_drawTextRun },
- { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
+ { "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_getClipBounds },
#endif
};
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3ebe7cb85cee..6ed7b7145589 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -593,6 +593,7 @@
UI style also includes a full action bar by default. -->
<style name="Theme.Light.Holo">
<item name="editTextBackground">@android:drawable/edit_text_holo_light</item>
+ <item name="android:windowActionBar">true</item>
<item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item>
<item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_light</item>
</style>
diff --git a/docs/html/resources/samples/images/sample_notepadtest_junit.png b/docs/html/resources/samples/images/sample_notepadtest_junit.png
new file mode 100644
index 000000000000..4cda54e94eae
--- /dev/null
+++ b/docs/html/resources/samples/images/sample_notepadtest_junit.png
Binary files differ
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 1eb178ebc130..d016dfa969e4 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -54,11 +54,6 @@ class SharedClient;
// ----------------------------------------------------------------------------
-// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX
-// 4 * (11 + 7 + (1 + 2*7)*16) * 31
-// 1032 * 31
-// = ~27 KiB (31992)
-
class SharedBufferStack
{
friend class SharedClient;
@@ -85,7 +80,7 @@ public:
};
struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
- static const unsigned int NUM_RECT_MAX = 6;
+ static const unsigned int NUM_RECT_MAX = 5;
uint32_t count;
SmallRect rects[NUM_RECT_MAX];
};
@@ -93,13 +88,18 @@ public:
struct BufferData {
FlatRegion dirtyRegion;
SmallRect crop;
+ uint8_t transform;
+ uint8_t reserved[3];
};
SharedBufferStack();
void init(int32_t identity);
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
+ status_t setTransform(int buffer, uint8_t transform);
Region getDirtyRegion(int buffer) const;
+ Rect getCrop(int buffer) const;
+ uint32_t getTransform(int buffer) const;
// these attributes are part of the conditions/updates
volatile int32_t head; // server's current front buffer
@@ -117,7 +117,7 @@ public:
int32_t reserved32[1];
Statistics stats;
int32_t reserved;
- BufferData buffers[NUM_BUFFER_MAX]; // 960 bytes
+ BufferData buffers[NUM_BUFFER_MAX]; // 1024 bytes
};
// ----------------------------------------------------------------------------
@@ -206,7 +206,7 @@ public:
bool needNewBuffer(int buffer) const;
status_t setDirtyRegion(int buffer, const Region& reg);
status_t setCrop(int buffer, const Rect& reg);
-
+ status_t setTransform(int buffer, uint32_t transform);
class SetBufferCountCallback {
friend class SharedBufferClient;
@@ -275,6 +275,8 @@ public:
status_t reallocateAllExcept(int buffer);
int32_t getQueuedCount() const;
Region getDirtyRegion(int buffer) const;
+ Rect getCrop(int buffer) const;
+ uint32_t getTransform(int buffer) const;
status_t resize(int newNumBuffers);
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 6fdd2ae7ba6f..a2108804af5e 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -217,6 +217,7 @@ private:
int dispatch_crop(va_list args);
int dispatch_set_buffer_count(va_list args);
int dispatch_set_buffers_geometry(va_list args);
+ int dispatch_set_buffers_transform(va_list args);
void setUsage(uint32_t reqUsage);
int connect(int api);
@@ -224,6 +225,7 @@ private:
int crop(Rect const* rect);
int setBufferCount(int bufferCount);
int setBuffersGeometry(int w, int h, int format);
+ int setBuffersTransform(int transform);
/*
* private stuff...
@@ -279,6 +281,7 @@ private:
Rect mSwapRectangle;
int mConnected;
Rect mNextBufferCrop;
+ uint32_t mNextBufferTransform;
BufferInfo mBufferInfo;
// protected by mSurfaceLock. These are also used from lock/unlock
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index ca89b06816cb..d59d72b7e520 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -85,6 +85,7 @@ enum {
NATIVE_WINDOW_SET_CROP,
NATIVE_WINDOW_SET_BUFFER_COUNT,
NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
};
/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@@ -92,6 +93,20 @@ enum {
NATIVE_WINDOW_API_EGL = 1
};
+/* parameter for NATIVE_WINDOW_SET_BUFFERS_TRANSFORM */
+enum {
+ /* flip source image horizontally */
+ NATIVE_WINDOW_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H ,
+ /* flip source image vertically */
+ NATIVE_WINDOW_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+ /* rotate source image 90 degrees clock-wise */
+ NATIVE_WINDOW_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+ /* rotate source image 180 degrees */
+ NATIVE_WINDOW_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+ /* rotate source image 270 degrees clock-wise */
+ NATIVE_WINDOW_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+};
+
struct ANativeWindow
{
#ifdef __cplusplus
@@ -196,6 +211,7 @@ struct ANativeWindow
* NATIVE_WINDOW_SET_CROP
* NATIVE_WINDOW_SET_BUFFER_COUNT
* NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
+ * NATIVE_WINDOW_SET_BUFFERS_TRANSFORM
*
*/
@@ -298,6 +314,19 @@ static inline int native_window_set_buffers_geometry(
w, h, format);
}
+/*
+ * native_window_set_buffers_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified.
+ */
+static inline int native_window_set_buffers_transform(
+ ANativeWindow* window,
+ int transform)
+{
+ return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
+ transform);
+}
+
// ---------------------------------------------------------------------------
/* FIXME: this is legacy for pixmaps */
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
new file mode 100644
index 000000000000..151e29f45a70
--- /dev/null
+++ b/libs/hwui/Caches.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_UI_CACHES_H
+#define ANDROID_UI_CACHES_H
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Singleton.h>
+
+#include "TextureCache.h"
+#include "LayerCache.h"
+#include "GradientCache.h"
+#include "PatchCache.h"
+#include "FontRenderer.h"
+#include "ProgramCache.h"
+#include "PathCache.h"
+#include "TextDropShadowCache.h"
+
+namespace android {
+namespace uirenderer {
+
+struct CacheLogger {
+ CacheLogger() {
+ LOGD("Creating caches");
+ }
+}; // struct CacheLogger
+
+class Caches: public Singleton<Caches> {
+ Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
+ lastDstMode(GL_ZERO), currentProgram(NULL) {
+ dropShadowCache.setFontRenderer(fontRenderer);
+ }
+
+ friend class Singleton<Caches>;
+
+ CacheLogger logger;
+
+public:
+ bool blend;
+ GLenum lastSrcMode;
+ GLenum lastDstMode;
+ Program* currentProgram;
+
+ TextureCache textureCache;
+ LayerCache layerCache;
+ GradientCache gradientCache;
+ ProgramCache programCache;
+ PathCache pathCache;
+ PatchCache patchCache;
+ TextDropShadowCache dropShadowCache;
+ FontRenderer fontRenderer;
+}; // class Caches
+
+}; // namespace uirenderer
+
+#ifdef USE_OPENGL_RENDERER
+using namespace uirenderer;
+ANDROID_SINGLETON_STATIC_INSTANCE(Caches);
+#endif
+
+}; // namespace android
+
+#endif // ANDROID_UI_CACHES_H
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
index 45b3ffaf074a..c358c8096cfd 100644
--- a/libs/hwui/GenerationCache.h
+++ b/libs/hwui/GenerationCache.h
@@ -104,12 +104,14 @@ void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* list
template<typename K, typename V>
void GenerationCache<K, V>::clear() {
if (mListener) {
- while (mCache.size() > 0) {
- removeOldest();
+ for (uint32_t i = 0; i < mCache.size(); i++) {
+ sp<Entry<K, V> > entry = mCache.valueAt(i);
+ if (mListener) {
+ (*mListener)(entry->key, entry->value);
+ }
}
- } else {
- mCache.clear();
}
+ mCache.clear();
mYoungest.clear();
mOldest.clear();
}
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 59fa0a7badcd..58920bd6f96d 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -22,6 +22,7 @@
#include <SkGradientShader.h>
#include "GradientCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -30,6 +31,20 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+GradientCache::GradientCache():
+ mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(MB(DEFAULT_GRADIENT_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting gradient cache size to %sMB", property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
+ }
+
+ mCache.setOnEntryRemovedListener(this);
+}
+
GradientCache::GradientCache(uint32_t maxByteSize):
mCache(GenerationCache<SkShader*, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 12c8a231aabe..8795920e6944 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -32,6 +32,7 @@ namespace uirenderer {
*/
class GradientCache: public OnEntryRemoved<SkShader*, Texture*> {
public:
+ GradientCache();
GradientCache(uint32_t maxByteSize);
~GradientCache();
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 3d263a3f71df..a20477801211 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -21,6 +21,7 @@
#include <utils/Log.h>
#include "LayerCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -29,6 +30,18 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+LayerCache::LayerCache():
+ mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
+ mIdGenerator(1), mSize(0), mMaxSize(MB(DEFAULT_LAYER_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting layer cache size to %sMB", property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
+ }
+}
+
LayerCache::LayerCache(uint32_t maxByteSize):
mCache(GenerationCache<LayerSize, Layer*>::kUnlimitedCapacity),
mIdGenerator(1), mSize(0), mMaxSize(maxByteSize) {
diff --git a/libs/hwui/LayerCache.h b/libs/hwui/LayerCache.h
index 258055130b67..9860994d1922 100644
--- a/libs/hwui/LayerCache.h
+++ b/libs/hwui/LayerCache.h
@@ -43,6 +43,7 @@ namespace uirenderer {
class LayerCache: public OnEntryRemoved<LayerSize, Layer*> {
public:
+ LayerCache();
LayerCache(uint32_t maxByteSize);
~LayerCache();
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 49d49da44f44..033d8e2efd58 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -23,11 +23,9 @@
#include <SkCanvas.h>
#include <SkTypeface.h>
-#include <cutils/properties.h>
#include <utils/Log.h>
#include "OpenGLRenderer.h"
-#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -36,18 +34,8 @@ namespace uirenderer {
// Defines
///////////////////////////////////////////////////////////////////////////////
-#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
-#define DEFAULT_LAYER_CACHE_SIZE 6.0f
-#define DEFAULT_PATH_CACHE_SIZE 6.0f
-#define DEFAULT_PATCH_CACHE_SIZE 100
-#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
-#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
-
#define REQUIRED_TEXTURE_UNITS_COUNT 3
-// Converts a number of mega-bytes into bytes
-#define MB(s) s * 1024 * 1024
-
// Generates simple and textured vertices
#define FV(x, y, u, v) { { x, y }, { u, v } }
@@ -102,54 +90,9 @@ static const GLenum gTextureUnits[] = {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-OpenGLRenderer::OpenGLRenderer():
- mBlend(false), mLastSrcMode(GL_ZERO), mLastDstMode(GL_ZERO),
- mTextureCache(MB(DEFAULT_TEXTURE_CACHE_SIZE)),
- mLayerCache(MB(DEFAULT_LAYER_CACHE_SIZE)),
- mGradientCache(MB(DEFAULT_GRADIENT_CACHE_SIZE)),
- mPathCache(MB(DEFAULT_PATH_CACHE_SIZE)),
- mPatchCache(DEFAULT_PATCH_CACHE_SIZE),
- mDropShadowCache(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
+OpenGLRenderer::OpenGLRenderer(): mCaches(Caches::getInstance()) {
LOGD("Create OpenGLRenderer");
- char property[PROPERTY_VALUE_MAX];
- if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
- LOGD(" Setting texture cache size to %sMB", property);
- mTextureCache.setMaxSize(MB(atof(property)));
- } else {
- LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
- }
-
- if (property_get(PROPERTY_LAYER_CACHE_SIZE, property, NULL) > 0) {
- LOGD(" Setting layer cache size to %sMB", property);
- mLayerCache.setMaxSize(MB(atof(property)));
- } else {
- LOGD(" Using default layer cache size of %.2fMB", DEFAULT_LAYER_CACHE_SIZE);
- }
-
- if (property_get(PROPERTY_GRADIENT_CACHE_SIZE, property, NULL) > 0) {
- LOGD(" Setting gradient cache size to %sMB", property);
- mGradientCache.setMaxSize(MB(atof(property)));
- } else {
- LOGD(" Using default gradient cache size of %.2fMB", DEFAULT_GRADIENT_CACHE_SIZE);
- }
-
- if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
- LOGD(" Setting path cache size to %sMB", property);
- mPathCache.setMaxSize(MB(atof(property)));
- } else {
- LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE);
- }
-
- if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
- LOGD(" Setting drop shadow cache size to %sMB", property);
- mDropShadowCache.setMaxSize(MB(atof(property)));
- } else {
- LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE);
- }
- mDropShadowCache.setFontRenderer(mFontRenderer);
-
- mCurrentProgram = NULL;
mShader = NULL;
mColorFilter = NULL;
mHasShadow = false;
@@ -167,14 +110,6 @@ OpenGLRenderer::OpenGLRenderer():
OpenGLRenderer::~OpenGLRenderer() {
LOGD("Destroy OpenGLRenderer");
-
- mTextureCache.clear();
- mLayerCache.clear();
- mGradientCache.clear();
- mPathCache.clear();
- mPatchCache.clear();
- mProgramCache.clear();
- mDropShadowCache.clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -195,6 +130,8 @@ void OpenGLRenderer::prepare() {
mSnapshot = new Snapshot(mFirstSnapshot);
mSaveCount = 1;
+ glViewport(0, 0, mWidth, mHeight);
+
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -310,12 +247,12 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot
bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
- LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize());
+ LAYER_LOGD("Layer cache size = %d", mCaches.layerCache.getSize());
GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
LayerSize size(right - left, bottom - top);
- Layer* layer = mLayerCache.get(size, previousFbo);
+ Layer* layer = mCaches.layerCache.get(size, previousFbo);
if (!layer) {
return false;
}
@@ -380,7 +317,7 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
LayerSize size(rect.getWidth(), rect.getHeight());
// Failing to add the layer to the cache should happen only if the
// layer is too large
- if (!mLayerCache.put(size, layer)) {
+ if (!mCaches.layerCache.put(size, layer)) {
LAYER_LOGD("Deleting layer");
glDeleteFramebuffers(1, &layer->fbo);
@@ -461,7 +398,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const S
}
glActiveTexture(GL_TEXTURE0);
- const Texture* texture = mTextureCache.get(bitmap);
+ const Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -478,7 +415,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const
}
glActiveTexture(GL_TEXTURE0);
- const Texture* texture = mTextureCache.get(bitmap);
+ const Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -494,7 +431,7 @@ void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
}
glActiveTexture(GL_TEXTURE0);
- const Texture* texture = mTextureCache.get(bitmap);
+ const Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -520,7 +457,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
}
glActiveTexture(GL_TEXTURE0);
- const Texture* texture = mTextureCache.get(bitmap);
+ const Texture* texture = mCaches.textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -528,7 +465,7 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- Patch* mesh = mPatchCache.get(patch);
+ Patch* mesh = mCaches.patchCache.get(patch);
mesh->updateVertices(bitmap, left, top, right, bottom,
&patch->xDivs[0], &patch->yDivs[0], patch->numXDivs, patch->numYDivs);
@@ -607,10 +544,11 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
- mFontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()), paint->getTextSize());
+ mCaches.fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
+ paint->getTextSize());
if (mHasShadow) {
glActiveTexture(gTextureUnits[0]);
- const ShadowTexture* shadow = mDropShadowCache.get(paint, text, bytesCount,
+ const ShadowTexture* shadow = mCaches.dropShadowCache.get(paint, text, bytesCount,
count, mShadowRadius);
const AutoTexture autoCleanup(shadow);
@@ -618,20 +556,20 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count,
// Draw the mesh
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
- glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
+ glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
}
GLuint textureUnit = 0;
glActiveTexture(gTextureUnits[textureUnit]);
- setupTextureAlpha8(mFontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
+ setupTextureAlpha8(mCaches.fontRenderer.getTexture(), 0, 0, textureUnit, x, y, r, g, b, a,
mode, false, true);
const Rect& clip = mSnapshot->getLocalClip();
- mFontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
+ mCaches.fontRenderer.renderText(paint, &clip, text, 0, bytesCount, count, x, y);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
+ glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
drawTextDecorations(text, bytesCount, length, x, y, paint);
@@ -646,7 +584,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
GLuint textureUnit = 0;
glActiveTexture(gTextureUnits[textureUnit]);
- const PathTexture* texture = mPathCache.get(path, paint);
+ const PathTexture* texture = mCaches.pathCache.get(path, paint);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -671,7 +609,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
// Draw the mesh
glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
- glDisableVertexAttribArray(mCurrentProgram->getAttrib("texCoords"));
+ glDisableVertexAttribArray(mCaches.currentProgram->getAttrib("texCoords"));
}
///////////////////////////////////////////////////////////////////////////////
@@ -685,7 +623,7 @@ void OpenGLRenderer::resetShader() {
void OpenGLRenderer::setupShader(SkiaShader* shader) {
mShader = shader;
if (mShader) {
- mShader->set(&mTextureCache, &mGradientCache);
+ mShader->set(&mCaches.textureCache, &mCaches.gradientCache);
}
}
@@ -761,18 +699,18 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t
}
// Build and use the appropriate shader
- useProgram(mProgramCache.get(description));
+ useProgram(mCaches.programCache.get(description));
// Setup the blending mode
chooseBlending(true, mode);
bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, textureUnit);
- glUniform1i(mCurrentProgram->getUniform("sampler"), textureUnit);
+ glUniform1i(mCaches.currentProgram->getUniform("sampler"), textureUnit);
- int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
+ int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
glEnableVertexAttribArray(texCoordsSlot);
// Setup attributes
- glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mMeshVertices[0].position[0]);
glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mMeshVertices[0].texture[0]);
@@ -784,17 +722,17 @@ void OpenGLRenderer::setupTextureAlpha8(GLuint texture, uint32_t width, uint32_t
} else {
mModelView.loadIdentity();
}
- mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
- glUniform4f(mCurrentProgram->color, r, g, b, a);
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ glUniform4f(mCaches.currentProgram->color, r, g, b, a);
textureUnit++;
if (applyFilters) {
// Setup attributes and uniforms required by the shaders
if (mShader) {
- mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
+ mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
}
if (mColorFilter) {
- mColorFilter->setupProgram(mCurrentProgram);
+ mColorFilter->setupProgram(mCaches.currentProgram);
}
}
}
@@ -879,29 +817,29 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
}
// Build and use the appropriate shader
- useProgram(mProgramCache.get(description));
+ useProgram(mCaches.programCache.get(description));
// Setup attributes
- glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, &mMeshVertices[0].position[0]);
// Setup uniforms
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
if (!ignoreTransform) {
- mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
} else {
mat4 identity;
- mCurrentProgram->set(mOrthoMatrix, mModelView, identity);
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
}
- glUniform4f(mCurrentProgram->color, r, g, b, a);
+ glUniform4f(mCaches.currentProgram->color, r, g, b, a);
// Setup attributes and uniforms required by the shaders
if (mShader) {
- mShader->setupProgram(mCurrentProgram, mModelView, *mSnapshot, &textureUnit);
+ mShader->setupProgram(mCaches.currentProgram, mModelView, *mSnapshot, &textureUnit);
}
if (mColorFilter) {
- mColorFilter->setupProgram(mCurrentProgram);
+ mColorFilter->setupProgram(mCaches.currentProgram);
}
// Draw the mesh
@@ -936,28 +874,28 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
mModelView.loadTranslate(left, top, 0.0f);
mModelView.scale(right - left, bottom - top, 1.0f);
- useProgram(mProgramCache.get(description));
- mCurrentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
+ useProgram(mCaches.programCache.get(description));
+ mCaches.currentProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
chooseBlending(blend || alpha < 1.0f, mode);
// Texture
bindTexture(texture, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0);
- glUniform1i(mCurrentProgram->getUniform("sampler"), 0);
+ glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
// Always premultiplied
- glUniform4f(mCurrentProgram->color, alpha, alpha, alpha, alpha);
+ glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha);
// Mesh
- int texCoordsSlot = mCurrentProgram->getAttrib("texCoords");
+ int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
glEnableVertexAttribArray(texCoordsSlot);
- glVertexAttribPointer(mCurrentProgram->position, 2, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(mCaches.currentProgram->position, 2, GL_FLOAT, GL_FALSE,
gMeshStride, vertices);
glVertexAttribPointer(texCoordsSlot, 2, GL_FLOAT, GL_FALSE, gMeshStride, texCoords);
// Color filter
if (mColorFilter) {
- mColorFilter->setupProgram(mCurrentProgram);
+ mColorFilter->setupProgram(mCaches.currentProgram);
}
if (!indices) {
@@ -971,7 +909,7 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied) {
blend = blend || mode != SkXfermode::kSrcOver_Mode;
if (blend) {
- if (!mBlend) {
+ if (!mCaches.blend) {
glEnable(GL_BLEND);
}
@@ -981,22 +919,22 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr
sourceMode = GL_SRC_ALPHA;
}
- if (sourceMode != mLastSrcMode || destMode != mLastDstMode) {
+ if (sourceMode != mCaches.lastSrcMode || destMode != mCaches.lastDstMode) {
glBlendFunc(sourceMode, destMode);
- mLastSrcMode = sourceMode;
- mLastDstMode = destMode;
+ mCaches.lastSrcMode = sourceMode;
+ mCaches.lastDstMode = destMode;
}
- } else if (mBlend) {
+ } else if (mCaches.blend) {
glDisable(GL_BLEND);
}
- mBlend = blend;
+ mCaches.blend = blend;
}
bool OpenGLRenderer::useProgram(Program* program) {
if (!program->isInUse()) {
- if (mCurrentProgram != NULL) mCurrentProgram->remove();
+ if (mCaches.currentProgram != NULL) mCaches.currentProgram->remove();
program->use();
- mCurrentProgram = program;
+ mCaches.currentProgram = program;
return false;
}
return true;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5c0089f35214..5748d57d8787 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -35,17 +35,10 @@
#include "Program.h"
#include "Rect.h"
#include "Snapshot.h"
-#include "TextureCache.h"
-#include "LayerCache.h"
-#include "GradientCache.h"
-#include "PatchCache.h"
#include "Vertex.h"
-#include "FontRenderer.h"
-#include "ProgramCache.h"
#include "SkiaShader.h"
#include "SkiaColorFilter.h"
-#include "PathCache.h"
-#include "TextDropShadowCache.h"
+#include "Caches.h"
namespace android {
namespace uirenderer {
@@ -356,7 +349,6 @@ private:
sp<Snapshot> mSnapshot;
// Shaders
- Program* mCurrentProgram;
SkiaShader* mShader;
// Color filters
@@ -365,17 +357,9 @@ private:
// Used to draw textured quads
TextureVertex mMeshVertices[4];
- // Last known blend state
- bool mBlend;
- GLenum mLastSrcMode;
- GLenum mLastDstMode;
-
// GL extensions
Extensions mExtensions;
- // Font renderer
- FontRenderer mFontRenderer;
-
// Drop shadow
bool mHasShadow;
float mShadowRadius;
@@ -384,13 +368,7 @@ private:
int mShadowColor;
// Various caches
- TextureCache mTextureCache;
- LayerCache mLayerCache;
- GradientCache mGradientCache;
- ProgramCache mProgramCache;
- PathCache mPathCache;
- PatchCache mPatchCache;
- TextDropShadowCache mDropShadowCache;
+ Caches& mCaches;
}; // class OpenGLRenderer
}; // namespace uirenderer
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 694e3fd6205c..a7c0ccef89f8 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -20,6 +20,7 @@
#include <utils/ResourceTypes.h>
#include "PatchCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -28,6 +29,9 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+PatchCache::PatchCache(): mCache(DEFAULT_PATCH_CACHE_SIZE) {
+}
+
PatchCache::PatchCache(uint32_t maxEntries): mCache(maxEntries) {
}
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index de9508717df3..e874a1686e5c 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -43,6 +43,7 @@ namespace uirenderer {
class PatchCache: public OnEntryRemoved<PatchDescription, Patch*> {
public:
+ PatchCache();
PatchCache(uint32_t maxCapacity);
~PatchCache();
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 10440ea3cebf..158c0cc70ff0 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -22,6 +22,7 @@
#include <SkRect.h>
#include "PathCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -30,9 +31,30 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+PathCache::PathCache():
+ mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(MB(DEFAULT_PATH_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_PATH_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting path cache size to %sMB", property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default path cache size of %.2fMB", DEFAULT_PATH_CACHE_SIZE);
+ }
+ init();
+}
+
PathCache::PathCache(uint32_t maxByteSize):
mCache(GenerationCache<PathCacheEntry, PathTexture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
+ init();
+}
+
+PathCache::~PathCache() {
+ mCache.clear();
+}
+
+void PathCache::init() {
mCache.setOnEntryRemovedListener(this);
GLint maxTextureSize;
@@ -40,10 +62,6 @@ PathCache::PathCache(uint32_t maxByteSize):
mMaxTextureSize = maxTextureSize;
}
-PathCache::~PathCache() {
- mCache.clear();
-}
-
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index d09789f03763..522e5e0f65ad 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -95,6 +95,7 @@ struct PathTexture: public Texture {
*/
class PathCache: public OnEntryRemoved<PathCacheEntry, PathTexture*> {
public:
+ PathCache();
PathCache(uint32_t maxByteSize);
~PathCache();
@@ -135,6 +136,8 @@ private:
PathTexture* addTexture(const PathCacheEntry& entry, const SkPath *path, const SkPaint* paint);
+ void init();
+
GenerationCache<PathCacheEntry, PathTexture*> mCache;
uint32_t mSize;
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index fa4b8c4b3e47..f211ab60261f 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -183,7 +183,6 @@ private:
void printLongString(const String8& shader) const;
KeyedVector<programid, Program*> mCache;
-
}; // class ProgramCache
}; // namespace uirenderer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7514b6f0d905..dfe022ac9377 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_UI_PROPERTIES_H
#define ANDROID_UI_PROPERTIES_H
+#include <cutils/properties.h>
+
/**
* This file contains the list of system properties used to configure
* the OpenGLRenderer.
@@ -33,4 +35,14 @@
#define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
#define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height"
+// Converts a number of mega-bytes into bytes
+#define MB(s) s * 1024 * 1024
+
+#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
+#define DEFAULT_LAYER_CACHE_SIZE 6.0f
+#define DEFAULT_PATH_CACHE_SIZE 6.0f
+#define DEFAULT_PATCH_CACHE_SIZE 100
+#define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
+#define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
+
#endif // ANDROID_UI_PROPERTIES_H
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index aab5bd4d347d..f95d2be3acf9 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -25,6 +25,20 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+TextDropShadowCache::TextDropShadowCache():
+ mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(MB(DEFAULT_DROP_SHADOW_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_DROP_SHADOW_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting drop shadow cache size to %sMB", property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default drop shadow cache size of %.2fMB", DEFAULT_DROP_SHADOW_CACHE_SIZE);
+ }
+
+ mCache.setOnEntryRemovedListener(this);
+}
+
TextDropShadowCache::TextDropShadowCache(uint32_t maxByteSize):
mCache(GenerationCache<ShadowText, ShadowTexture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index c3be4832b93f..b65d62acc522 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -69,16 +69,16 @@ struct ShadowText {
char *text;
bool operator<(const ShadowText& rhs) const {
- if (len < rhs.len) return true;
- else if (len == rhs.len) {
- if (radius < rhs.radius) return true;
- else if (radius == rhs.radius) {
- if (textSize < rhs.textSize) return true;
- else if (textSize == rhs.textSize) {
- if (typeface < rhs.typeface) return true;
- else if (typeface == rhs.typeface) {
- if (hash < rhs.hash) return true;
- if (hash == rhs.hash) {
+ if (hash < rhs.hash) return true;
+ else if (hash == rhs.hash) {
+ if (len < rhs.len) return true;
+ else if (len == rhs.len) {
+ if (radius < rhs.radius) return true;
+ else if (radius == rhs.radius) {
+ if (textSize < rhs.textSize) return true;
+ else if (textSize == rhs.textSize) {
+ if (typeface < rhs.typeface) return true;
+ else if (typeface == rhs.typeface) {
return strncmp(text, rhs.text, len) < 0;
}
}
@@ -102,6 +102,7 @@ struct ShadowTexture: public Texture {
class TextDropShadowCache: public OnEntryRemoved<ShadowText, ShadowTexture*> {
public:
+ TextDropShadowCache();
TextDropShadowCache(uint32_t maxByteSize);
~TextDropShadowCache();
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 2e8a8be3cf86..753c5446b5bc 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -19,6 +19,7 @@
#include <GLES2/gl2.h>
#include "TextureCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -27,19 +28,37 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
+TextureCache::TextureCache():
+ mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity),
+ mSize(0), mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE)) {
+ char property[PROPERTY_VALUE_MAX];
+ if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, NULL) > 0) {
+ LOGD(" Setting texture cache size to %sMB", property);
+ setMaxSize(MB(atof(property)));
+ } else {
+ LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
+ }
+
+ init();
+}
+
TextureCache::TextureCache(uint32_t maxByteSize):
mCache(GenerationCache<SkBitmap*, Texture*>::kUnlimitedCapacity),
mSize(0), mMaxSize(maxByteSize) {
- mCache.setOnEntryRemovedListener(this);
-
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
- LOGD("Maximum texture dimension is %d pixels", mMaxTextureSize);
+ init();
}
TextureCache::~TextureCache() {
mCache.clear();
}
+void TextureCache::init() {
+ mCache.setOnEntryRemovedListener(this);
+
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
+ LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize);
+}
+
///////////////////////////////////////////////////////////////////////////////
// Size management
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 452716c947ff..b5e4c7c19038 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -32,6 +32,7 @@ namespace uirenderer {
*/
class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> {
public:
+ TextureCache();
TextureCache(uint32_t maxByteSize);
~TextureCache();
@@ -78,6 +79,8 @@ private:
*/
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
+ void init();
+
GenerationCache<SkBitmap*, Texture*> mCache;
uint32_t mSize;
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 47ec78a7dd13..4c01cd229225 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -75,6 +75,14 @@ status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
return NO_ERROR;
}
+status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return BAD_INDEX;
+ buffers[buffer].transform = transform;
+ return NO_ERROR;
+}
+
status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
{
if (uint32_t(buffer) >= NUM_BUFFER_MAX)
@@ -137,6 +145,26 @@ Region SharedBufferStack::getDirtyRegion(int buffer) const
return res;
}
+Rect SharedBufferStack::getCrop(int buffer) const
+{
+ Rect res(-1, -1);
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return res;
+ res.left = buffers[buffer].crop.l;
+ res.top = buffers[buffer].crop.t;
+ res.right = buffers[buffer].crop.r;
+ res.bottom = buffers[buffer].crop.b;
+ return res;
+}
+
+uint32_t SharedBufferStack::getTransform(int buffer) const
+{
+ if (uint32_t(buffer) >= NUM_BUFFER_MAX)
+ return 0;
+ return buffers[buffer].transform;
+}
+
+
// ----------------------------------------------------------------------------
SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
@@ -428,6 +456,12 @@ status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
return stack.setCrop(buf, crop);
}
+status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.setTransform(buf, uint8_t(transform));
+}
+
status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
{
SharedBufferStack& stack( *mSharedStack );
@@ -544,6 +578,18 @@ Region SharedBufferServer::getDirtyRegion(int buf) const
return stack.getDirtyRegion(buf);
}
+Rect SharedBufferServer::getCrop(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getCrop(buf);
+}
+
+uint32_t SharedBufferServer::getTransform(int buf) const
+{
+ SharedBufferStack& stack( *mSharedStack );
+ return stack.getTransform(buf);
+}
+
/*
* NOTE: this is not thread-safe on the server-side, meaning
* 'head' cannot move during this operation. The client-side
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index f52447650a39..2bc5fadecf43 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -429,8 +429,10 @@ void Surface::init()
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+ mNextBufferTransform = 0;
mConnected = 0;
mSwapRectangle.makeInvalid();
+ mNextBufferCrop = Rect(0,0);
// two buffers by default
mBuffers.setCapacity(2);
mBuffers.insertAt(0, 2);
@@ -641,6 +643,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer)
}
int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
+ mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
err = mSharedBufferClient->queue(bufIdx);
@@ -695,6 +698,9 @@ int Surface::perform(int operation, va_list args)
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
res = dispatch_set_buffers_geometry( args );
break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatch_set_buffers_transform( args );
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -729,6 +735,11 @@ int Surface::dispatch_set_buffers_geometry(va_list args) {
return setBuffersGeometry(w, h, f);
}
+int Surface::dispatch_set_buffers_transform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
void Surface::setUsage(uint32_t reqUsage)
{
Mutex::Autolock _l(mSurfaceLock);
@@ -775,6 +786,10 @@ int Surface::disconnect(int api)
int Surface::crop(Rect const* rect)
{
+ // empty/invalid rects are not allowed
+ if (rect->isEmpty())
+ return BAD_VALUE;
+
Mutex::Autolock _l(mSurfaceLock);
// TODO: validate rect size
mNextBufferCrop = *rect;
@@ -814,6 +829,13 @@ int Surface::setBuffersGeometry(int w, int h, int format)
return NO_ERROR;
}
+int Surface::setBuffersTransform(int transform)
+{
+ Mutex::Autolock _l(mSurfaceLock);
+ mNextBufferTransform = transform;
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
int Surface::getConnectedApi() const
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b7beb6b06fd6..e167afa2bd37 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -199,6 +199,7 @@ AwesomePlayer::AwesomePlayer()
mExtractorFlags(0),
mLastVideoBuffer(NULL),
mVideoBuffer(NULL),
+ mRTSPTimeOffset(0),
mSuspensionState(NULL) {
CHECK_EQ(mClient.connect(), OK);
@@ -396,7 +397,11 @@ void AwesomePlayer::reset_l() {
mVideoBuffer = NULL;
}
- mRTSPController.clear();
+ if (mRTSPController != NULL) {
+ mRTSPController->disconnect();
+ mRTSPController.clear();
+ }
+
mRTPPusher.clear();
mRTCPPusher.clear();
mRTPSession.clear();
@@ -758,6 +763,10 @@ status_t AwesomePlayer::getPosition(int64_t *positionUs) {
*positionUs = 0;
}
+ if (mRTSPController != NULL) {
+ *positionUs += mRTSPTimeOffset;
+ }
+
return OK;
}
@@ -773,6 +782,17 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) {
}
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
+ if (mRTSPController != NULL) {
+ pause_l();
+ mRTSPController->seek(timeUs);
+ play_l();
+
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ mSeekNotificationSent = true;
+ mRTSPTimeOffset = timeUs;
+ return OK;
+ }
+
if (mFlags & CACHE_UNDERRUN) {
mFlags &= ~CACHE_UNDERRUN;
play_l();
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 2542e4ecc209..70205648b54e 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -33,6 +33,8 @@ struct ARTSPController : public MediaExtractor {
status_t connect(const char *url);
void disconnect();
+ void seek(int64_t timeUs);
+
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index f34eb45615b5..f5df1b57c7a6 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -182,6 +182,7 @@ private:
sp<ALooper> mLooper;
sp<ARTSPController> mRTSPController;
+ int64_t mRTSPTimeOffset;
sp<ARTPSession> mRTPSession;
sp<UDPPusher> mRTPPusher, mRTCPPusher;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 8c56cb785608..b930184e7438 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -406,9 +406,7 @@ APacketSource::APacketSource(
const sp<ASessionDescription> &sessionDesc, size_t index)
: mInitCheck(NO_INIT),
mFormat(new MetaData),
- mEOSResult(OK),
- mFirstAccessUnit(true),
- mFirstAccessUnitNTP(0) {
+ mEOSResult(OK) {
unsigned long PT;
AString desc;
AString params;
@@ -550,9 +548,6 @@ status_t APacketSource::initCheck() const {
}
status_t APacketSource::start(MetaData *params) {
- mFirstAccessUnit = true;
- mFirstAccessUnitNTP = 0;
-
return OK;
}
@@ -600,25 +595,6 @@ void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
return;
}
- uint64_t ntpTime;
- CHECK(buffer->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
- if (mFirstAccessUnit) {
- mFirstAccessUnit = false;
- mFirstAccessUnitNTP = ntpTime;
- }
-
- if (ntpTime > mFirstAccessUnitNTP) {
- ntpTime -= mFirstAccessUnitNTP;
- } else {
- ntpTime = 0;
- }
-
- int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
-
- buffer->meta()->setInt64("timeUs", timeUs);
-
Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer);
mCondition.signal();
@@ -632,31 +608,9 @@ void APacketSource::signalEOS(status_t result) {
mCondition.signal();
}
-int64_t APacketSource::getQueuedDuration(bool *eos) {
+void APacketSource::flushQueue() {
Mutex::Autolock autoLock(mLock);
-
- *eos = (mEOSResult != OK);
-
- if (mBuffers.empty()) {
- return 0;
- }
-
- sp<ABuffer> buffer = *mBuffers.begin();
-
- uint64_t ntpTime;
- CHECK(buffer->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
- int64_t firstTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
-
- buffer = *--mBuffers.end();
-
- CHECK(buffer->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
- int64_t lastTimeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
-
- return lastTimeUs - firstTimeUs;
+ mBuffers.clear();
}
} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 647da6e5f66f..197af3ed54f1 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -43,7 +43,7 @@ struct APacketSource : public MediaSource {
void queueAccessUnit(const sp<ABuffer> &buffer);
void signalEOS(status_t result);
- int64_t getQueuedDuration(bool *eos);
+ void flushQueue();
protected:
virtual ~APacketSource();
@@ -58,9 +58,6 @@ private:
List<sp<ABuffer> > mBuffers;
status_t mEOSResult;
- bool mFirstAccessUnit;
- uint64_t mFirstAccessUnitNTP;
-
DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
};
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index ceae3a676ea3..9df17cbad45c 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -33,7 +33,7 @@ ARTSPController::ARTSPController(const sp<ALooper> &looper)
}
ARTSPController::~ARTSPController() {
- disconnect();
+ CHECK_EQ((int)mState, (int)DISCONNECTED);
mLooper->unregisterHandler(mReflector->id());
}
@@ -80,6 +80,16 @@ void ARTSPController::disconnect() {
mHandler.clear();
}
+void ARTSPController::seek(int64_t timeUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mState != CONNECTED) {
+ return;
+ }
+
+ mHandler->seek(timeUs);
+}
+
size_t ARTSPController::countTracks() {
if (mHandler == NULL) {
return 0;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index b2419bf14a76..caff43556e86 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -38,7 +38,10 @@ struct MyHandler : public AHandler {
mConn(new ARTSPConnection),
mRTPConn(new ARTPConnection),
mSessionURL(url),
- mSetupTracksSuccessful(false) {
+ mSetupTracksSuccessful(false),
+ mSeekPending(false),
+ mFirstAccessUnit(true),
+ mFirstAccessUnitNTP(0) {
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
@@ -62,6 +65,12 @@ struct MyHandler : public AHandler {
(new AMessage('abor', id()))->post();
}
+ void seek(int64_t timeUs) {
+ sp<AMessage> msg = new AMessage('seek', id());
+ msg->setInt64("time", timeUs);
+ msg->post();
+ }
+
virtual void onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case 'conn':
@@ -88,8 +97,6 @@ struct MyHandler : public AHandler {
case 'disc':
{
- LOG(INFO) << "disconnect completed";
-
(new AMessage('quit', id()))->post();
break;
}
@@ -337,7 +344,20 @@ struct MyHandler : public AHandler {
CHECK(accessUnit->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime));
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ if (mFirstAccessUnit) {
+ mFirstAccessUnit = false;
+ mFirstAccessUnitNTP = ntpTime;
+ }
+
+ if (ntpTime >= mFirstAccessUnitNTP) {
+ ntpTime -= mFirstAccessUnitNTP;
+ } else {
+ ntpTime = 0;
+ }
+
+ int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
+
+ accessUnit->meta()->setInt64("timeUs", timeUs);
#if 0
int32_t damaged;
@@ -353,6 +373,84 @@ struct MyHandler : public AHandler {
break;
}
+ case 'seek':
+ {
+ if (mSeekPending) {
+ break;
+ }
+
+ int64_t timeUs;
+ CHECK(msg->findInt64("time", &timeUs));
+
+ mSeekPending = true;
+
+ AString request = "PAUSE ";
+ request.append(mSessionURL);
+ request.append(" RTSP/1.0\r\n");
+
+ request.append("Session: ");
+ request.append(mSessionID);
+ request.append("\r\n");
+
+ request.append("\r\n");
+
+ sp<AMessage> reply = new AMessage('see1', id());
+ reply->setInt64("time", timeUs);
+ mConn->sendRequest(request.c_str(), reply);
+ break;
+ }
+
+ case 'see1':
+ {
+ int64_t timeUs;
+ CHECK(msg->findInt64("time", &timeUs));
+
+ AString request = "PLAY ";
+ request.append(mSessionURL);
+ request.append(" RTSP/1.0\r\n");
+
+ request.append("Session: ");
+ request.append(mSessionID);
+ request.append("\r\n");
+
+ request.append(
+ StringPrintf(
+ "Range: npt=%lld-\r\n", timeUs / 1000000ll));
+
+ request.append("\r\n");
+
+ sp<AMessage> reply = new AMessage('see2', id());
+ mConn->sendRequest(request.c_str(), reply);
+ break;
+ }
+
+ case 'see2':
+ {
+ CHECK(mSeekPending);
+
+ LOG(INFO) << "seek completed.";
+ mSeekPending = false;
+
+ int32_t result;
+ CHECK(msg->findInt32("result", &result));
+ if (result != OK) {
+ LOG(ERROR) << "seek FAILED";
+ break;
+ }
+
+ sp<RefBase> obj;
+ CHECK(msg->findObject("response", &obj));
+ sp<ARTSPResponse> response =
+ static_cast<ARTSPResponse *>(obj.get());
+
+ CHECK_EQ(response->mStatusCode, 200u);
+
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ mTracks.editItemAt(i).mPacketSource->flushQueue();
+ }
+ break;
+ }
+
default:
TRESPASS();
break;
@@ -380,6 +478,9 @@ private:
AString mBaseURL;
AString mSessionID;
bool mSetupTracksSuccessful;
+ bool mSeekPending;
+ bool mFirstAccessUnit;
+ uint64_t mFirstAccessUnitNTP;
struct TrackInfo {
int mRTPSocket;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 185d72a966e3..8349fe6fa797 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -47,7 +47,8 @@
<bool name="def_networks_available_notification_on">true</bool>
<bool name="def_backup_enabled">false</bool>
- <string name="def_backup_transport" translatable="false"></string>
+ <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string>
+
<!-- Default value for whether or not to pulse the notification LED when there is a
pending notification -->
<bool name="def_notification_pulse">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2e95932c2927..81d82dea6aef 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -22,6 +22,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import android.app.backup.BackupManager;
import android.content.ContentProvider;
@@ -37,6 +39,7 @@ import android.database.sqlite.SQLiteQueryBuilder;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.provider.DrmStore;
@@ -56,9 +59,15 @@ public class SettingsProvider extends ContentProvider {
// Cache for settings, access-ordered for acting as LRU.
// Guarded by themselves.
- private static final int MAX_CACHE_ENTRIES = 50;
- private static final SettingsCache sSystemCache = new SettingsCache();
- private static final SettingsCache sSecureCache = new SettingsCache();
+ private static final int MAX_CACHE_ENTRIES = 200;
+ private static final SettingsCache sSystemCache = new SettingsCache("system");
+ private static final SettingsCache sSecureCache = new SettingsCache("secure");
+
+ // The count of how many known (handled by SettingsProvider)
+ // database mutations are currently being handled. Used by
+ // sFileObserver to not reload the database when it's ourselves
+ // modifying it.
+ private static final AtomicInteger sKnownMutationsInFlight = new AtomicInteger(0);
// Over this size we don't reject loading or saving settings but
// we do consider them broken/malicious and don't keep them in
@@ -67,6 +76,10 @@ public class SettingsProvider extends ContentProvider {
private static final Bundle NULL_SETTING = Bundle.forPair("value", null);
+ // Used as a sentinel value in an instance equality test when we
+ // want to cache the existence of a key, but not store its value.
+ private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
+
protected DatabaseHelper mOpenHelper;
private BackupManager mBackupManager;
@@ -201,6 +214,43 @@ public class SettingsProvider extends ContentProvider {
}
}
+ // FileObserver for external modifications to the database file.
+ // Note that this is for platform developers only with
+ // userdebug/eng builds who should be able to tinker with the
+ // sqlite database out from under the SettingsProvider, which is
+ // normally the exclusive owner of the database. But we keep this
+ // enabled all the time to minimize development-vs-user
+ // differences in testing.
+ private static SettingsFileObserver sObserverInstance;
+ private class SettingsFileObserver extends FileObserver {
+ private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
+ private final String mPath;
+
+ public SettingsFileObserver(String path) {
+ super(path, FileObserver.CLOSE_WRITE |
+ FileObserver.CREATE | FileObserver.DELETE |
+ FileObserver.MOVED_TO | FileObserver.MODIFY);
+ mPath = path;
+ }
+
+ public void onEvent(int event, String path) {
+ int modsInFlight = sKnownMutationsInFlight.get();
+ if (modsInFlight > 0) {
+ // our own modification.
+ return;
+ }
+ Log.d(TAG, "external modification to " + mPath + "; event=" + event);
+ if (!mIsDirty.compareAndSet(false, true)) {
+ // already handled. (we get a few update events
+ // during an sqlite write)
+ return;
+ }
+ Log.d(TAG, "updating our caches for " + mPath);
+ fullyPopulateCaches();
+ mIsDirty.set(false);
+ }
+ }
+
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
@@ -210,9 +260,65 @@ public class SettingsProvider extends ContentProvider {
return false;
}
+ // Watch for external modifications to the database file,
+ // keeping our cache in sync.
+ // It's kinda lame to call mOpenHelper.getReadableDatabase()
+ // during onCreate(), but since ensureAndroidIdIsSet has
+ // already done it above and initialized/upgraded the
+ // database, might as well just use it...
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ sObserverInstance = new SettingsFileObserver(db.getPath());
+ sObserverInstance.startWatching();
+ startAsyncCachePopulation();
return true;
}
+ private void startAsyncCachePopulation() {
+ new Thread("populate-settings-caches") {
+ public void run() {
+ fullyPopulateCaches();
+ }
+ }.start();
+ }
+
+ private void fullyPopulateCaches() {
+ fullyPopulateCache("secure", sSecureCache);
+ fullyPopulateCache("system", sSystemCache);
+ }
+
+ // Slurp all values (if sane in number & size) into cache.
+ private void fullyPopulateCache(String table, SettingsCache cache) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor c = db.query(
+ table,
+ new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
+ null, null, null, null, null,
+ "" + (MAX_CACHE_ENTRIES + 1) /* limit */);
+ try {
+ synchronized (cache) {
+ cache.clear();
+ cache.setFullyMatchesDisk(true); // optimistic
+ int rows = 0;
+ while (c.moveToNext()) {
+ rows++;
+ String name = c.getString(0);
+ String value = c.getString(1);
+ cache.populate(name, value);
+ }
+ if (rows > MAX_CACHE_ENTRIES) {
+ // Somewhat redundant, as removeEldestEntry() will
+ // have already done this, but to be explicit:
+ cache.setFullyMatchesDisk(false);
+ Log.d(TAG, "row count exceeds max cache entries for table " + table);
+ }
+ Log.d(TAG, "cache for settings table '" + table + "' fullycached=" +
+ cache.fullyMatchesDisk());
+ }
+ } finally {
+ c.close();
+ }
+ }
+
private boolean ensureAndroidIdIsSet() {
final Cursor c = query(Settings.Secure.CONTENT_URI,
new String[] { Settings.NameValueTable.VALUE },
@@ -262,7 +368,19 @@ public class SettingsProvider extends ContentProvider {
private Bundle lookupValue(String table, SettingsCache cache, String key) {
synchronized (cache) {
if (cache.containsKey(key)) {
- return cache.get(key);
+ Bundle value = cache.get(key);
+ if (value != TOO_LARGE_TO_CACHE_MARKER) {
+ return value;
+ }
+ // else we fall through and read the value from disk
+ } else if (cache.fullyMatchesDisk()) {
+ // Fast path (very common). Don't even try touch disk
+ // if we know we've slurped it all in. Trying to
+ // touch the disk would mean waiting for yaffs2 to
+ // give us access, which could takes hundreds of
+ // milliseconds. And we're very likely being called
+ // from somebody's UI thread...
+ return NULL_SETTING;
}
}
@@ -338,6 +456,7 @@ public class SettingsProvider extends ContentProvider {
checkWritePermissions(args);
SettingsCache cache = SettingsCache.forTable(args.table);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.beginTransaction();
try {
@@ -350,6 +469,7 @@ public class SettingsProvider extends ContentProvider {
db.setTransactionSuccessful();
} finally {
db.endTransaction();
+ sKnownMutationsInFlight.decrementAndGet();
}
sendNotify(uri);
@@ -449,8 +569,10 @@ public class SettingsProvider extends ContentProvider {
return Uri.withAppendedPath(url, name);
}
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final long rowId = db.insert(args.table, null, initialValues);
+ sKnownMutationsInFlight.decrementAndGet();
if (rowId <= 0) return null;
SettingsCache.populate(cache, initialValues); // before we notify
@@ -471,12 +593,15 @@ public class SettingsProvider extends ContentProvider {
}
checkWritePermissions(args);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int count = db.delete(args.table, args.where, args.args);
+ sKnownMutationsInFlight.decrementAndGet();
if (count > 0) {
SettingsCache.wipe(args.table); // before we notify
sendNotify(url);
}
+ startAsyncCachePopulation();
if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
return count;
}
@@ -489,12 +614,15 @@ public class SettingsProvider extends ContentProvider {
}
checkWritePermissions(args);
+ sKnownMutationsInFlight.incrementAndGet();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ sKnownMutationsInFlight.decrementAndGet();
int count = db.update(args.table, initialValues, args.where, args.args);
if (count > 0) {
SettingsCache.wipe(args.table); // before we notify
sendNotify(url);
}
+ startAsyncCachePopulation();
if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
return count;
}
@@ -506,12 +634,12 @@ public class SettingsProvider extends ContentProvider {
* When a client attempts to openFile the default ringtone or
* notification setting Uri, we will proxy the call to the current
* default ringtone's Uri (if it is in the DRM or media provider).
- */
+ */
int ringtoneType = RingtoneManager.getDefaultType(uri);
// Above call returns -1 if the Uri doesn't match a default type
if (ringtoneType != -1) {
Context context = getContext();
-
+
// Get the current value for the default sound
Uri soundUri = RingtoneManager.getActualDefaultRingtoneUri(context, ringtoneType);
@@ -531,7 +659,7 @@ public class SettingsProvider extends ContentProvider {
throw new FileNotFoundException(e.getMessage());
}
}
-
+
return context.getContentResolver().openFileDescriptor(soundUri, mode);
}
}
@@ -607,13 +735,38 @@ public class SettingsProvider extends ContentProvider {
*/
private static final class SettingsCache extends LinkedHashMap<String, Bundle> {
- public SettingsCache() {
+ private final String mCacheName;
+ private boolean mCacheFullyMatchesDisk = false; // has the whole database slurped.
+
+ public SettingsCache(String name) {
super(MAX_CACHE_ENTRIES, 0.75f /* load factor */, true /* access ordered */);
+ mCacheName = name;
+ }
+
+ /**
+ * Is the whole database table slurped into this cache?
+ */
+ public boolean fullyMatchesDisk() {
+ synchronized (this) {
+ return mCacheFullyMatchesDisk;
+ }
+ }
+
+ public void setFullyMatchesDisk(boolean value) {
+ synchronized (this) {
+ mCacheFullyMatchesDisk = value;
+ }
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > MAX_CACHE_ENTRIES;
+ if (size() <= MAX_CACHE_ENTRIES) {
+ return false;
+ }
+ synchronized (this) {
+ mCacheFullyMatchesDisk = false;
+ }
+ return true;
}
/**
@@ -658,11 +811,15 @@ public class SettingsProvider extends ContentProvider {
return;
}
String value = contentValues.getAsString(Settings.NameValueTable.VALUE);
- synchronized (cache) {
+ cache.populate(name, value);
+ }
+
+ public void populate(String name, String value) {
+ synchronized (this) {
if (value == null || value.length() <= MAX_CACHE_ENTRY_SIZE) {
- cache.put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
+ put(name, Bundle.forPair(Settings.NameValueTable.VALUE, value));
} else {
- cache.remove(name);
+ put(name, TOO_LARGE_TO_CACHE_MARKER);
}
}
}
@@ -678,6 +835,7 @@ public class SettingsProvider extends ContentProvider {
}
synchronized (cache) {
cache.clear();
+ cache.mCacheFullyMatchesDisk = true;
}
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3720e166992b..212c08bff93d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -530,9 +530,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
return;
}
- // get the dirty region
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
+ // get the dirty region
// compute the posted region
const Region dirty(lcblk->getDirtyRegion(buf));
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
@@ -568,6 +568,13 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions)
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
+
+ // get the crop region
+ setBufferCrop( lcblk->getCrop(buf) );
+
+ // get the transformation
+ setBufferTransform( lcblk->getTransform(buf) );
+
} else {
// this should not happen unless we ran out of memory while
// allocating the buffer. we're hoping that things will get back
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 043d54d96210..3d049a79616f 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -54,6 +54,8 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
+ mBufferCrop.makeInvalid();
+ mBufferTransform = 0;
}
LayerBase::~LayerBase()
@@ -354,6 +356,14 @@ void LayerBase::clearWithOpenGL(const Region& clip) const
clearWithOpenGL(clip,0,0,0,0);
}
+template <typename T>
+static inline
+void swap(T& a, T& b) {
+ T t(a);
+ a = b;
+ b = t;
+}
+
void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
@@ -387,38 +397,73 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
}
}
- Region::const_iterator it = clip.begin();
- Region::const_iterator const end = clip.end();
- const GLfloat texCoords[4][2] = {
- { 0, 0 },
- { 0, 1 },
- { 1, 1 },
- { 1, 0 }
+ /*
+ * compute texture coordinates
+ * here, we handle NPOT, cropping and buffer transformations
+ */
+
+ GLfloat cl, ct, cr, cb;
+ if (!mBufferCrop.isEmpty()) {
+ // source is cropped
+ const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
+ const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
+ cl = mBufferCrop.left * us;
+ ct = mBufferCrop.top * vs;
+ cr = mBufferCrop.right * us;
+ cb = mBufferCrop.bottom * vs;
+ } else {
+ cl = 0;
+ ct = 0;
+ cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
+ cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
+ }
+
+ struct TexCoords {
+ GLfloat u;
+ GLfloat v;
+ };
+
+ enum {
+ // name of the corners in the texture map
+ LB = 0, // left-bottom
+ LT = 1, // left-top
+ RT = 2, // right-top
+ RB = 3 // right-bottom
};
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
+ // vertices in screen space
+ int vLT = LB;
+ int vLB = LT;
+ int vRB = RT;
+ int vRT = RB;
// the texture's source is rotated
- switch (texture.transform) {
- case HAL_TRANSFORM_ROT_90:
- glTranslatef(0, 1, 0);
- glRotatef(-90, 0, 0, 1);
- break;
- case HAL_TRANSFORM_ROT_180:
- glTranslatef(1, 1, 0);
- glRotatef(-180, 0, 0, 1);
- break;
- case HAL_TRANSFORM_ROT_270:
- glTranslatef(1, 0, 0);
- glRotatef(-270, 0, 0, 1);
- break;
+ uint32_t transform = mBufferTransform;
+ if (transform & HAL_TRANSFORM_ROT_90) {
+ vLT = RB;
+ vLB = LB;
+ vRB = LT;
+ vRT = RT;
}
-
- if (texture.NPOTAdjust) {
- glScalef(texture.wScale, texture.hScale, 1.0f);
+ if (transform & HAL_TRANSFORM_FLIP_V) {
+ swap(vLT, vLB);
+ swap(vRB, vRT);
+ }
+ if (transform & HAL_TRANSFORM_FLIP_H) {
+ swap(vLT, vRB);
+ swap(vLB, vRT);
}
+ TexCoords texCoords[4];
+ texCoords[vLT].u = cl;
+ texCoords[vLT].v = ct;
+ texCoords[vLB].u = cl;
+ texCoords[vLB].v = cb;
+ texCoords[vRB].u = cr;
+ texCoords[vRB].v = cb;
+ texCoords[vRT].u = cr;
+ texCoords[vRT].v = ct;
+
if (needsDithering()) {
glEnable(GL_DITHER);
} else {
@@ -429,6 +474,8 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glVertexPointer(2, GL_FLOAT, 0, mVertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+ Region::const_iterator it = clip.begin();
+ Region::const_iterator const end = clip.end();
while (it != end) {
const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
@@ -438,6 +485,16 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
+void LayerBase::setBufferCrop(const Rect& crop) {
+ if (!crop.isEmpty()) {
+ mBufferCrop = crop;
+ }
+}
+
+void LayerBase::setBufferTransform(uint32_t transform) {
+ mBufferTransform = transform;
+}
+
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index dd1cd05f1b93..c66dc3450ba8 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -232,9 +232,17 @@ protected:
void clearWithOpenGL(const Region& clip) const;
void drawWithOpenGL(const Region& clip, const Texture& texture) const;
+ // these must be called from the post/drawing thread
+ void setBufferCrop(const Rect& crop);
+ void setBufferTransform(uint32_t transform);
+
sp<SurfaceFlinger> mFlinger;
uint32_t mFlags;
+ // post/drawing thread
+ Rect mBufferCrop;
+ uint32_t mBufferTransform;
+
// cached during validateVisibility()
bool mNeedsFiltering;
int32_t mOrientation;
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
index 64a43c78f446..2ee21b92b531 100644
--- a/services/surfaceflinger/LayerBlur.cpp
+++ b/services/surfaceflinger/LayerBlur.cpp
@@ -241,6 +241,8 @@ void LayerBlur::onDraw(const Region& clip) const
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
}
}
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index e8b2ebf16745..fdf9abc81ada 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -485,7 +485,7 @@ void LayerBuffer::BufferSource::onDraw(const Region& clip) const
mTextureManager.loadTexture(&mTexture, dirty, t);
}
- mTexture.transform = mBufferHeap.transform;
+ mLayer.setBufferTransform(mBufferHeap.transform);
mLayer.drawWithOpenGL(clip, mTexture);
}
diff --git a/services/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h
index c7c14e70bb44..18c4348693ff 100644
--- a/services/surfaceflinger/TextureManager.h
+++ b/services/surfaceflinger/TextureManager.h
@@ -40,12 +40,11 @@ class GraphicBuffer;
struct Image {
enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 };
Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0),
- transform(0), dirty(1), target(TEXTURE_2D) { }
+ dirty(1), target(TEXTURE_2D) { }
GLuint name;
EGLImageKHR image;
GLuint width;
GLuint height;
- uint32_t transform;
unsigned dirty : 1;
unsigned target : 1;
};
diff --git a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java
index c6389587e5d5..94b936b13844 100644
--- a/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java
+++ b/tests/HwAccelerationTest/src/com/google/android/test/hwui/ListActivity.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.DisplayMetrics;
+import android.view.ContextMenu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
@@ -83,6 +84,17 @@ public class ListActivity extends Activity {
ListView list = (ListView) findViewById(R.id.list);
list.setAdapter(adapter);
+
+ registerForContextMenu(list);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ menu.setHeaderTitle("Context menu");
+ menu.add("List item 1");
+ menu.add("List item 2");
+ menu.add("List item 3");
}
private static class SimpleListAdapter extends ArrayAdapter<String> {
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index e71c29318392..ec8d0ed2c395 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -35,7 +35,7 @@ import javax.sip.address.URI;
* Class containing a SIP account, domain and server information.
* @hide
*/
-public class SipProfile implements Parcelable, Serializable {
+public class SipProfile implements Parcelable, Serializable, Cloneable {
private static final long serialVersionUID = 1L;
private static final int DEFAULT_PORT = 5060;
private Address mAddress;
@@ -46,6 +46,7 @@ public class SipProfile implements Parcelable, Serializable {
private String mProfileName;
private boolean mSendKeepAlive = false;
private boolean mAutoRegistration = true;
+ private boolean mAllowOutgoingCall = false;
/** @hide */
public static final Parcelable.Creator<SipProfile> CREATOR =
@@ -79,6 +80,23 @@ public class SipProfile implements Parcelable, Serializable {
}
/**
+ * Creates a builder based on the given profile.
+ */
+ public Builder(SipProfile profile) {
+ if (profile == null) throw new NullPointerException();
+ try {
+ mProfile = (SipProfile) profile.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("should not occur", e);
+ }
+ mProfile.mAddress = null;
+ mUri = profile.getUri();
+ mUri.setUserPassword(profile.getPassword());
+ mDisplayName = profile.getDisplayName();
+ mProxyAddress = profile.getProxyAddress();
+ }
+
+ /**
* Constructor.
*
* @param uriString the URI string as "sip:<user_name>@<domain>"
@@ -226,6 +244,18 @@ public class SipProfile implements Parcelable, Serializable {
}
/**
+ * Sets the allow-outgoing-call flag.
+ *
+ * @param flag true if allowing to make outgoing call on the profile;
+ * false otherwise
+ * @return this builder object
+ */
+ public Builder setOutgoingCallAllowed(boolean flag) {
+ mProfile.mAllowOutgoingCall = flag;
+ return this;
+ }
+
+ /**
* Builds and returns the SIP profile object.
*
* @return the profile object created
@@ -262,6 +292,7 @@ public class SipProfile implements Parcelable, Serializable {
mProfileName = in.readString();
mSendKeepAlive = (in.readInt() == 0) ? false : true;
mAutoRegistration = (in.readInt() == 0) ? false : true;
+ mAllowOutgoingCall = (in.readInt() == 0) ? false : true;
}
/** @hide */
@@ -274,6 +305,7 @@ public class SipProfile implements Parcelable, Serializable {
out.writeString(mProfileName);
out.writeInt(mSendKeepAlive ? 1 : 0);
out.writeInt(mAutoRegistration ? 1 : 0);
+ out.writeInt(mAllowOutgoingCall ? 1 : 0);
}
/** @hide */
@@ -398,4 +430,11 @@ public class SipProfile implements Parcelable, Serializable {
public boolean getAutoRegistration() {
return mAutoRegistration;
}
+
+ /**
+ * Returns true if allowing to make outgoing calls on this profile.
+ */
+ public boolean isOutgoingCallAllowed() {
+ return mAllowOutgoingCall;
+ }
}