summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/RenderNode.java27
-rw-r--r--core/java/android/widget/Editor.java20
-rw-r--r--core/java/android/widget/TextView.java7
-rw-r--r--core/java/android/widget/TextViewMetrics.java40
-rw-r--r--core/jni/android/graphics/Paint.cpp12
-rw-r--r--core/jni/android_view_RenderNode.cpp5
-rw-r--r--graphics/java/android/graphics/Paint.java26
-rw-r--r--graphics/tests/graphicstests/src/android/graphics/PaintTest.java9
-rw-r--r--libs/hwui/Android.mk3
-rw-r--r--libs/hwui/OpenGLReadback.cpp (renamed from libs/hwui/Readback.cpp)141
-rw-r--r--libs/hwui/OpenGLReadback.h56
-rw-r--r--libs/hwui/Readback.h17
-rw-r--r--libs/hwui/hwui/MinikinUtils.cpp1
-rw-r--r--libs/hwui/hwui/Paint.h9
-rw-r--r--libs/hwui/hwui/PaintImpl.cpp11
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp25
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h1
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp16
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp121
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.h35
-rw-r--r--libs/hwui/renderthread/OpenGLPipeline.cpp6
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp26
-rw-r--r--libs/hwui/renderthread/RenderThread.h3
-rw-r--r--media/java/android/media/ExifInterface.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java3
-rw-r--r--proto/src/metrics_constants.proto6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java20
31 files changed, 546 insertions, 125 deletions
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 7a3c95e004c5..8eca43158ef2 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -26,6 +26,8 @@ import android.graphics.drawable.AnimatedVectorDrawable;
import dalvik.annotation.optimization.FastNative;
+import libcore.util.NativeAllocationRegistry;
+
/**
* <p>A display list records a series of graphics related operations and can replay
* them later. Display lists are usually built by recording operations on a
@@ -130,13 +132,20 @@ import dalvik.annotation.optimization.FastNative;
*/
public class RenderNode {
+ // Use a Holder to allow static initialization in the boot image.
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
+ }
+
private boolean mValid;
// Do not access directly unless you are ThreadedRenderer
- long mNativeRenderNode;
+ final long mNativeRenderNode;
private final View mOwningView;
private RenderNode(String name, View owningView) {
mNativeRenderNode = nCreate(name);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mOwningView = owningView;
}
@@ -145,6 +154,7 @@ public class RenderNode {
*/
private RenderNode(long nativePtr) {
mNativeRenderNode = nativePtr;
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mOwningView = null;
}
@@ -154,19 +164,7 @@ public class RenderNode {
* is not feasible.
*/
public void destroy() {
- if (mNativeRenderNode != 0) {
- nFinalize(mNativeRenderNode);
- mNativeRenderNode = 0;
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } finally {
- super.finalize();
- }
+ // TODO: Removed temporarily
}
/**
@@ -835,7 +833,6 @@ public class RenderNode {
// Intentionally not static because it acquires a reference to 'this'
private native long nCreate(String name);
- private native void nFinalize(long renderNode);
private static native long nGetNativeFinalizer();
private static native void nSetDisplayList(long renderNode, long newData);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 5eaabe7c137b..541fbe0528f1 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -111,6 +111,8 @@ import android.widget.TextView.Drawables;
import android.widget.TextView.OnEditorActionListener;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
@@ -1119,14 +1121,26 @@ public class Editor {
getInsertionController().show();
mIsInsertionActionModeStartPending = true;
handled = true;
+ MetricsLogger.action(
+ mTextView.getContext(),
+ MetricsEvent.TEXT_LONGPRESS,
+ TextViewMetrics.SUBTYPE_LONG_PRESS_OTHER);
}
if (!handled && mTextActionMode != null) {
if (touchPositionIsInSelection()) {
startDragAndDrop();
+ MetricsLogger.action(
+ mTextView.getContext(),
+ MetricsEvent.TEXT_LONGPRESS,
+ TextViewMetrics.SUBTYPE_LONG_PRESS_DRAG_AND_DROP);
} else {
stopTextActionMode();
selectCurrentWordAndStartDrag();
+ MetricsLogger.action(
+ mTextView.getContext(),
+ MetricsEvent.TEXT_LONGPRESS,
+ TextViewMetrics.SUBTYPE_LONG_PRESS_SELECTION);
}
handled = true;
}
@@ -1134,6 +1148,12 @@ public class Editor {
// Start a new selection
if (!handled) {
handled = selectCurrentWordAndStartDrag();
+ if (handled) {
+ MetricsLogger.action(
+ mTextView.getContext(),
+ MetricsEvent.TEXT_LONGPRESS,
+ TextViewMetrics.SUBTYPE_LONG_PRESS_SELECTION);
+ }
}
return handled;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5426a37cdd80..69f463cdd856 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -148,6 +148,8 @@ import android.view.textservice.TextServicesManager;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FastMath;
import com.android.internal.widget.EditableInputConnection;
@@ -9685,6 +9687,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (handled) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
if (mEditor != null) mEditor.mDiscardNextActionUp = true;
+ } else {
+ MetricsLogger.action(
+ mContext,
+ MetricsEvent.TEXT_LONGPRESS,
+ TextViewMetrics.SUBTYPE_LONG_PRESS_OTHER);
}
return handled;
diff --git a/core/java/android/widget/TextViewMetrics.java b/core/java/android/widget/TextViewMetrics.java
new file mode 100644
index 000000000000..0a14d3e8b466
--- /dev/null
+++ b/core/java/android/widget/TextViewMetrics.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+/**
+ * {@link com.android.internal.logging.MetricsLogger} values for TextView.
+ *
+ * @hide
+ */
+final class TextViewMetrics {
+
+ private TextViewMetrics() {}
+
+ /**
+ * Long press on TextView - no special classification.
+ */
+ static final int SUBTYPE_LONG_PRESS_OTHER = 0;
+ /**
+ * Long press on TextView - selection started.
+ */
+ static final int SUBTYPE_LONG_PRESS_SELECTION = 1;
+ /**
+ * Long press on TextView - drag and drop started.
+ */
+ static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2;
+}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e10fdbdb2845..34568391167d 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -915,6 +915,16 @@ namespace PaintGlue {
paint->setLetterSpacing(letterSpacing);
}
+ static jfloat getWordSpacing(jlong paintHandle) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ return paint->getWordSpacing();
+ }
+
+ static void setWordSpacing(jlong paintHandle, jfloat wordSpacing) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ paint->setWordSpacing(wordSpacing);
+ }
+
static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
return paint->getHyphenEdit();
@@ -1043,6 +1053,8 @@ static const JNINativeMethod methods[] = {
{"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
{"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
{"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
+ {"nGetWordSpacing","(J)F", (void*) PaintGlue::getWordSpacing},
+ {"nSetWordSpacing","(JF)V", (void*) PaintGlue::setWordSpacing},
{"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
{"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
{"nAscent","(JJ)F", (void*) PaintGlue::ascent},
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index f88de51a9a12..dd2a7a98b7a0 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -124,10 +124,6 @@ static void releaseRenderNode(RenderNode* renderNode) {
renderNode->decStrong(0);
}
-static void android_view_RenderNode_finalize(JNIEnv* env, jobject clazz, jlong renderNodePtr) {
- releaseRenderNode(reinterpret_cast<RenderNode*>(renderNodePtr));
-}
-
static jlong android_view_RenderNode_getNativeFinalizer(JNIEnv* env,
jobject clazz) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&releaseRenderNode));
@@ -654,7 +650,6 @@ static const JNINativeMethod gMethods[] = {
// Regular JNI
// ----------------------------------------------------------------------------
{ "nCreate", "(Ljava/lang/String;)J", (void*) android_view_RenderNode_create },
- { "nFinalize", "(J)V", (void*) android_view_RenderNode_finalize },
{ "nGetNativeFinalizer", "()J", (void*) android_view_RenderNode_getNativeFinalizer },
{ "nSetDisplayList", "(JJ)V", (void*) android_view_RenderNode_setDisplayList },
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 98d45dc33ead..554e5d2614dd 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1442,6 +1442,28 @@ public class Paint {
}
/**
+ * Return the paint's word-spacing for text. The default value is 0.
+ *
+ * @return the paint's word-spacing for drawing text.
+ * @hide
+ */
+ public float getWordSpacing() {
+ return nGetWordSpacing(mNativePaint);
+ }
+
+ /**
+ * Set the paint's word-spacing for text. The default value is 0.
+ * The value is in pixels (note the units are not the same as for
+ * letter-spacing).
+ *
+ * @param wordSpacing set the paint's word-spacing for drawing text.
+ * @hide
+ */
+ public void setWordSpacing(float wordSpacing) {
+ nSetWordSpacing(mNativePaint, wordSpacing);
+ }
+
+ /**
* Returns the font feature settings. The format is the same as the CSS
* font-feature-settings attribute:
* <a href="https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop">
@@ -2711,6 +2733,10 @@ public class Paint {
@CriticalNative
private static native void nSetLetterSpacing(long paintPtr, float letterSpacing);
@CriticalNative
+ private static native float nGetWordSpacing(long paintPtr);
+ @CriticalNative
+ private static native void nSetWordSpacing(long paintPtr, float wordSpacing);
+ @CriticalNative
private static native int nGetHyphenEdit(long paintPtr);
@CriticalNative
private static native void nSetHyphenEdit(long paintPtr, int hyphen);
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
index 6763dd1970ae..318bfb6bfd39 100644
--- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
@@ -218,4 +218,13 @@ public class PaintTest extends AndroidTestCase {
assertEquals(width, p.measureText(bidiText), 1.0f);
}
}
+
+ public void testSetGetWordSpacing() {
+ Paint p = new Paint();
+ assertEquals(0.0f, p.getWordSpacing()); // The default value should be 0.
+ p.setWordSpacing(1.0f);
+ assertEquals(1.0f, p.getWordSpacing());
+ p.setWordSpacing(-2.0f);
+ assertEquals(-2.0f, p.getWordSpacing());
+ }
}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 47220508f2bd..fdf4d52f357b 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -24,6 +24,7 @@ hwui_src_files := \
pipeline/skia/ReorderBarrierDrawables.cpp \
pipeline/skia/SkiaDisplayList.cpp \
pipeline/skia/SkiaOpenGLPipeline.cpp \
+ pipeline/skia/SkiaOpenGLReadback.cpp \
pipeline/skia/SkiaPipeline.cpp \
pipeline/skia/SkiaProfileRenderer.cpp \
pipeline/skia/SkiaRecordingCanvas.cpp \
@@ -84,6 +85,7 @@ hwui_src_files := \
LayerUpdateQueue.cpp \
Matrix.cpp \
OpDumper.cpp \
+ OpenGLReadback.cpp \
Patch.cpp \
PatchCache.cpp \
PathCache.cpp \
@@ -96,7 +98,6 @@ hwui_src_files := \
Properties.cpp \
PropertyValuesAnimatorSet.cpp \
PropertyValuesHolder.cpp \
- Readback.cpp \
RecordingCanvas.cpp \
RenderBufferCache.cpp \
RenderNode.cpp \
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/OpenGLReadback.cpp
index 1645218495eb..da6d994f436c 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Readback.h"
+#include "OpenGLReadback.h"
#include "Caches.h"
#include "Image.h"
@@ -31,8 +31,69 @@
namespace android {
namespace uirenderer {
-static CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
- Texture& sourceTexture, Matrix4& texTransform, const Rect& srcRect,
+CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
+ SkBitmap* bitmap) {
+ ATRACE_CALL();
+ mRenderThread.eglManager().initialize();
+
+ // Setup the source
+ sp<GraphicBuffer> sourceBuffer;
+ sp<Fence> sourceFence;
+ Matrix4 texTransform;
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
+ texTransform.data);
+ texTransform.invalidateType();
+ if (err != NO_ERROR) {
+ ALOGW("Failed to get last queued buffer, error = %d", err);
+ return CopyResult::UnknownError;
+ }
+ if (!sourceBuffer.get()) {
+ ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
+ return CopyResult::SourceEmpty;
+ }
+ if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
+ ALOGW("Surface is protected, unable to copy from it");
+ return CopyResult::SourceInvalid;
+ }
+ err = sourceFence->wait(500 /* ms */);
+ if (err != NO_ERROR) {
+ ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
+ return CopyResult::Timeout;
+ }
+
+ // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
+ // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
+ // to be able to properly sample from the buffer.
+
+ // Create the EGLImage object that maps the GraphicBuffer
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
+ EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+
+ EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+
+ if (sourceImage == EGL_NO_IMAGE_KHR) {
+ ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
+ return CopyResult::UnknownError;
+ }
+
+ CopyResult copyResult = copyImageInto(sourceImage, texTransform, sourceBuffer->getWidth(),
+ sourceBuffer->getHeight(), srcRect, bitmap);
+
+ // All we're flushing & finishing is the deletion of the texture since
+ // copyImageInto already did a major flush & finish as an implicit
+ // part of glReadPixels, so this shouldn't pose any major stalls.
+ glFinish();
+ eglDestroyImageKHR(display, sourceImage);
+ return copyResult;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
+ Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect,
SkBitmap* bitmap) {
int destWidth = bitmap->width();
int destHeight = bitmap->height();
@@ -134,88 +195,40 @@ static CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
return CopyResult::Success;
}
-CopyResult Readback::copySurfaceInto(renderthread::RenderThread& renderThread,
- Surface& surface, const Rect& srcRect, SkBitmap* bitmap) {
- ATRACE_CALL();
- renderThread.eglManager().initialize();
+CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
+ const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) {
Caches& caches = Caches::getInstance();
-
- // Setup the source
- sp<GraphicBuffer> sourceBuffer;
- sp<Fence> sourceFence;
- Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
- texTransform.data);
- texTransform.invalidateType();
- if (err != NO_ERROR) {
- ALOGW("Failed to get last queued buffer, error = %d", err);
- return CopyResult::UnknownError;
- }
- if (!sourceBuffer.get()) {
- ALOGW("Surface doesn't have any previously queued frames, nothing to readback from");
- return CopyResult::SourceEmpty;
- }
- if (sourceBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) {
- ALOGW("Surface is protected, unable to copy from it");
- return CopyResult::SourceInvalid;
- }
- err = sourceFence->wait(500 /* ms */);
- if (err != NO_ERROR) {
- ALOGE("Timeout (500ms) exceeded waiting for buffer fence, abandoning readback attempt");
- return CopyResult::Timeout;
- }
-
- // TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
- // GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
- // to be able to properly sample from the buffer.
-
- // Create the EGLImage object that maps the GraphicBuffer
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
- EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
-
- EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
-
- if (sourceImage == EGL_NO_IMAGE_KHR) {
- ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
- return CopyResult::UnknownError;
- }
GLuint sourceTexId;
// Create a 2D texture to sample from the EGLImage
glGenTextures(1, &sourceTexId);
caches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, sourceImage);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
GLenum status = GL_NO_ERROR;
while ((status = glGetError()) != GL_NO_ERROR) {
ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
- eglDestroyImageKHR(display, sourceImage);
return CopyResult::UnknownError;
}
Texture sourceTexture(caches);
- sourceTexture.wrap(sourceTexId, sourceBuffer->getWidth(),
- sourceBuffer->getHeight(), 0, 0 /* total lie */, GL_TEXTURE_EXTERNAL_OES);
+ sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
+ GL_TEXTURE_EXTERNAL_OES);
- CopyResult copyResult = copyTextureInto(caches, renderThread.renderState(),
- sourceTexture, texTransform, srcRect, bitmap);
+ CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(),
+ sourceTexture, imgTransform, srcRect, bitmap);
sourceTexture.deleteTexture();
- // All we're flushing & finishing is the deletion of the texture since
- // copyTextureInto already did a major flush & finish as an implicit
- // part of glReadPixels, so this shouldn't pose any major stalls.
- glFinish();
- eglDestroyImageKHR(display, sourceImage);
return copyResult;
}
-CopyResult Readback::copyTextureLayerInto(renderthread::RenderThread& renderThread,
+bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
Layer& layer, SkBitmap* bitmap) {
- ATRACE_CALL();
- return copyTextureInto(Caches::getInstance(), renderThread.renderState(),
- layer.getTexture(), layer.getTexTransform(), Rect(), bitmap);
+ return CopyResult::Success == copyTextureInto(Caches::getInstance(),
+ renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
+ Rect(), bitmap);
}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h
new file mode 100644
index 000000000000..7ec2a96a9ac6
--- /dev/null
+++ b/libs/hwui/OpenGLReadback.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "Readback.h"
+
+namespace android {
+namespace uirenderer {
+
+class Matrix4;
+class Layer;
+
+class OpenGLReadback : public Readback {
+public:
+ virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
+ SkBitmap* bitmap) override;
+
+protected:
+ explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
+ virtual ~OpenGLReadback() {}
+
+ virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
+};
+
+class OpenGLReadbackImpl : public OpenGLReadback {
+public:
+ OpenGLReadbackImpl(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
+
+ /**
+ * Copies the layer's contents into the provided bitmap.
+ */
+ static bool copyLayerInto(renderthread::RenderThread& renderThread, Layer& layer,
+ SkBitmap* bitmap);
+
+protected:
+ virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+};
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index 55c943c0ebee..7fbc4bf48c4e 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -25,8 +25,6 @@
namespace android {
namespace uirenderer {
-class Layer;
-
// Keep in sync with PixelCopy.java codes
enum class CopyResult {
Success = 0,
@@ -42,15 +40,14 @@ public:
/**
* Copies the surface's most recently queued buffer into the provided bitmap.
*/
- static CopyResult copySurfaceInto(renderthread::RenderThread& renderThread,
- Surface& surface, const Rect& srcRect, SkBitmap* bitmap);
+ virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
+ SkBitmap* bitmap) = 0;
- /**
- * Copies the TextureLayer's texture content (thus, the currently rendering buffer) into the
- * provided bitmap.
- */
- static CopyResult copyTextureLayerInto(renderthread::RenderThread& renderThread,
- Layer& layer, SkBitmap* bitmap);
+protected:
+ explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
+ virtual ~Readback() {}
+
+ renderthread::RenderThread& mRenderThread;
};
} // namespace uirenderer
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index a06cc37f944e..8dd165c46d21 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -45,6 +45,7 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini
minikinPaint->scaleX = paint->getTextScaleX();
minikinPaint->skewX = paint->getTextSkewX();
minikinPaint->letterSpacing = paint->getLetterSpacing();
+ minikinPaint->wordSpacing = paint->getWordSpacing();
minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
minikinPaint->hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 10a1db9ace3d..c9b5f0031a7b 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -48,6 +48,14 @@ public:
return mLetterSpacing;
}
+ void setWordSpacing(float wordSpacing) {
+ mWordSpacing = wordSpacing;
+ }
+
+ float getWordSpacing() const {
+ return mWordSpacing;
+ }
+
void setFontFeatureSettings(const std::string& fontFeatureSettings) {
mFontFeatureSettings = fontFeatureSettings;
}
@@ -82,6 +90,7 @@ public:
private:
float mLetterSpacing = 0;
+ float mWordSpacing = 0;
std::string mFontFeatureSettings;
uint32_t mMinikinLangListId;
minikin::FontVariant mFontVariant;
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 84122d768089..67427433bb89 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -19,18 +19,19 @@
namespace android {
Paint::Paint() :
- SkPaint(), mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
- mFontVariant(minikin::VARIANT_DEFAULT) {
+ SkPaint(), mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(),
+ mMinikinLangListId(0), mFontVariant(minikin::VARIANT_DEFAULT) {
}
Paint::Paint(const Paint& paint) : SkPaint(paint),
- mLetterSpacing(paint.mLetterSpacing), mFontFeatureSettings(paint.mFontFeatureSettings),
+ mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing),
+ mFontFeatureSettings(paint.mFontFeatureSettings),
mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant),
mHyphenEdit(paint.mHyphenEdit) {
}
Paint::Paint(const SkPaint& paint) : SkPaint(paint),
- mLetterSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
+ mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
mFontVariant(minikin::VARIANT_DEFAULT) {
}
@@ -40,6 +41,7 @@ Paint::~Paint() {
Paint& Paint::operator=(const Paint& other) {
SkPaint::operator=(other);
mLetterSpacing = other.mLetterSpacing;
+ mWordSpacing = other.mWordSpacing;
mFontFeatureSettings = other.mFontFeatureSettings;
mMinikinLangListId = other.mMinikinLangListId;
mFontVariant = other.mFontVariant;
@@ -50,6 +52,7 @@ Paint& Paint::operator=(const Paint& other) {
bool operator==(const Paint& a, const Paint& b) {
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b)
&& a.mLetterSpacing == b.mLetterSpacing
+ && a.mWordSpacing == b.mWordSpacing
&& a.mFontFeatureSettings == b.mFontFeatureSettings
&& a.mMinikinLangListId == b.mMinikinLangListId
&& a.mFontVariant == b.mFontVariant
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 13a0ed852816..f2af4a891b12 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -23,36 +23,41 @@ namespace uirenderer {
namespace skiapipeline {
void LayerDrawable::onDraw(SkCanvas* canvas) {
+ DrawLayer(canvas->getGrContext(), canvas, mLayer.get());
+}
+
+bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) {
// transform the matrix based on the layer
int saveCount = -1;
- if (!mLayer->getTransform().isIdentity()) {
+ if (!layer->getTransform().isIdentity()) {
saveCount = canvas->save();
SkMatrix transform;
- mLayer->getTransform().copyTo(transform);
+ layer->getTransform().copyTo(transform);
canvas->concat(transform);
}
GrGLTextureInfo externalTexture;
- externalTexture.fTarget = mLayer->getRenderTarget();
- externalTexture.fID = mLayer->getTextureId();
- GrContext* context = canvas->getGrContext();
+ externalTexture.fTarget = layer->getRenderTarget();
+ externalTexture.fID = layer->getTextureId();
GrBackendTextureDesc textureDescription;
- textureDescription.fWidth = mLayer->getWidth();
- textureDescription.fHeight = mLayer->getHeight();
+ textureDescription.fWidth = layer->getWidth();
+ textureDescription.fHeight = layer->getHeight();
textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
sk_sp<SkImage> layerImage = SkImage::MakeFromTexture(context, textureDescription);
if (layerImage) {
SkPaint paint;
- paint.setAlpha(mLayer->getAlpha());
- paint.setBlendMode(mLayer->getMode());
- paint.setColorFilter(sk_ref_sp(mLayer->getColorFilter()));
+ paint.setAlpha(layer->getAlpha());
+ paint.setBlendMode(layer->getMode());
+ paint.setColorFilter(sk_ref_sp(layer->getColorFilter()));
canvas->drawImage(layerImage, 0, 0, &paint);
}
// restore the original matrix
if (saveCount >= 0) {
canvas->restoreToCount(saveCount);
}
+
+ return layerImage;
}
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 91e274475b34..431989519a70 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -33,6 +33,7 @@ class LayerDrawable : public SkDrawable {
explicit LayerDrawable(Layer* layer)
: mLayer(layer) {}
+ static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer);
protected:
virtual SkRect onGetBounds() override {
return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight());
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index f046e4b93db1..7f3474a1bdf3 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -17,9 +17,9 @@
#include "SkiaOpenGLPipeline.h"
#include "DeferredLayerUpdater.h"
+#include "LayerDrawable.h"
#include "renderthread/EglManager.h"
#include "renderstate/RenderState.h"
-#include "Readback.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
#include "utils/TraceUtils.h"
@@ -121,10 +121,16 @@ bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew,
return *requireSwap;
}
-bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
- layer->apply();
- return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
- == CopyResult::Success;
+bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBitmap* bitmap) {
+ if (!mRenderThread.getGrContext()) {
+ return false;
+ }
+
+ deferredLayer->apply();
+
+ SkCanvas canvas(*bitmap);
+ Layer* layer = deferredLayer->backingLayer();
+ return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer);
}
DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
new file mode 100644
index 000000000000..a18d26471a29
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkiaOpenGLReadback.h"
+
+#include "Matrix.h"
+#include "Properties.h"
+#include <SkCanvas.h>
+#include <SkSurface.h>
+#include <gl/GrGLInterface.h>
+#include <gl/GrGLTypes.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android::uirenderer::renderthread;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) {
+
+ GLuint sourceTexId;
+ glGenTextures(1, &sourceTexId);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, eglImage);
+
+ sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
+ LOG_ALWAYS_FATAL_IF(!glInterface.get());
+ grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
+ (GrBackendContext)glInterface.get()));
+ } else {
+ grContext->resetContext();
+ }
+
+ GrGLTextureInfo externalTexture;
+ externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
+ externalTexture.fID = sourceTexId;
+
+ GrBackendTextureDesc textureDescription;
+ textureDescription.fWidth = imgWidth;
+ textureDescription.fHeight = imgHeight;
+ textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+ textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+ textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
+
+ CopyResult copyResult = CopyResult::UnknownError;
+ sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
+ if (image) {
+ SkAutoLockPixels alp(*bitmap);
+
+ // convert to Skia data structures
+ const SkRect bufferRect = SkRect::MakeIWH(imgWidth, imgHeight);
+ SkRect skiaSrcRect = srcRect.toSkRect();
+ SkMatrix textureMatrix;
+ imgTransform.copyTo(textureMatrix);
+
+ // remove the y-flip applied to the matrix so that we can scale the srcRect.
+ // This flip is not needed as we specify the origin of the texture when we
+ // wrap it as an SkImage.
+ SkMatrix yFlip = SkMatrix::MakeScale(1, -1);
+ yFlip.postTranslate(0,1);
+ textureMatrix.preConcat(yFlip);
+
+ // copy the entire src if the rect is empty
+ if (skiaSrcRect.isEmpty()) {
+ skiaSrcRect = bufferRect;
+ }
+
+ // since the y-flip has been removed we can simply scale & translate
+ // the source rectangle
+ textureMatrix.mapRect(&skiaSrcRect);
+
+ if (skiaSrcRect.intersect(bufferRect)) {
+ SkPoint srcOrigin = SkPoint::Make(skiaSrcRect.fLeft, skiaSrcRect.fTop);
+
+ // if we need to scale the result we must render to an offscreen buffer
+ if (bitmap->width() != skiaSrcRect.width()
+ || bitmap->height() != skiaSrcRect.height()) {
+ sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
+ grContext.get(), SkBudgeted::kYes, bitmap->info());
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect,
+ SkRect::MakeWH(bitmap->width(), bitmap->height()), &paint);
+ image = scaledSurface->makeImageSnapshot();
+ srcOrigin.set(0,0);
+ }
+
+ if (image->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(),
+ srcOrigin.fX, srcOrigin.fY)) {
+ copyResult = CopyResult::Success;
+ }
+ }
+ }
+
+ // make sure that we have deleted the texture (in the SkImage) before we
+ // destroy the EGLImage that it was created from
+ image.reset();
+ return copyResult;
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
new file mode 100644
index 000000000000..d914409628d0
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include "OpenGLReadback.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class SkiaOpenGLReadback : public OpenGLReadback {
+public:
+ SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
+protected:
+ virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index afeeef86d22c..177a729cbf55 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -20,7 +20,7 @@
#include "EglManager.h"
#include "ProfileRenderer.h"
#include "renderstate/RenderState.h"
-#include "Readback.h"
+#include "OpenGLReadback.h"
#include <android/native_window.h>
#include <cutils/properties.h>
@@ -117,9 +117,9 @@ bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& sc
}
bool OpenGLPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ ATRACE_CALL();
layer->apply();
- return Readback::copyTextureLayerInto(mRenderThread, *(layer->backingLayer()), bitmap)
- == CopyResult::Success;
+ return OpenGLReadbackImpl::copyLayerInto(mRenderThread, *(layer->backingLayer()), bitmap);
}
DeferredLayerUpdater* OpenGLPipeline::createTextureLayer() {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 39e5931da361..2c4824279325 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -602,8 +602,8 @@ void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observer) {
CREATE_BRIDGE4(copySurfaceInto, RenderThread* thread,
Surface* surface, Rect srcRect, SkBitmap* bitmap) {
- return (void*) Readback::copySurfaceInto(*args->thread,
- *args->surface, args->srcRect, args->bitmap);
+ return (void*)args->thread->readback().copySurfaceInto(*args->surface,
+ args->srcRect, args->bitmap);
}
int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top,
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index f3789c8d8cbb..223958a3c319 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,8 +17,10 @@
#include "RenderThread.h"
#include "../renderstate/RenderState.h"
+#include "../pipeline/skia/SkiaOpenGLReadback.h"
#include "CanvasContext.h"
#include "EglManager.h"
+#include "OpenGLReadback.h"
#include "RenderProxy.h"
#include "VulkanManager.h"
@@ -196,6 +198,30 @@ void RenderThread::initThreadLocals() {
mVkManager = new VulkanManager(*this);
}
+Readback& RenderThread::readback() {
+
+ if (!mReadback) {
+ auto renderType = Properties::getRenderPipelineType();
+ switch (renderType) {
+ case RenderPipelineType::OpenGL:
+ mReadback = new OpenGLReadbackImpl(*this);
+ break;
+ case RenderPipelineType::SkiaGL:
+ case RenderPipelineType::SkiaVulkan:
+ // It works to use the OpenGL pipeline for Vulkan but this is not
+ // ideal as it causes us to create an OpenGL context in addition
+ // to the Vulkan one.
+ mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ break;
+ }
+ }
+
+ return *mReadback;
+}
+
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 12050dd9c772..d121bcf5b084 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -37,6 +37,7 @@ class DisplayEventReceiver;
namespace uirenderer {
+class Readback;
class RenderState;
class TestUtils;
@@ -93,6 +94,7 @@ public:
RenderState& renderState() const { return *mRenderState; }
EglManager& eglManager() const { return *mEglManager; }
JankTracker& jankTracker() { return *mJankTracker; }
+ Readback& readback();
const DisplayInfo& mainDisplayInfo() { return mDisplayInfo; }
@@ -151,6 +153,7 @@ private:
EglManager* mEglManager;
JankTracker* mJankTracker = nullptr;
+ Readback* mReadback = nullptr;
sk_sp<GrContext> mGrContext;
VulkanManager* mVkManager;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d77a082188f6..bbb7184664b6 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2189,9 +2189,9 @@ public class ExifInterface {
/**
* Loads EXIF attributes from a JPEG input stream.
*
- * @param inputStream The input stream that starts with the JPEG data.
+ * @param in The input stream that starts with the JPEG data.
* @param jpegOffset The offset value in input stream for JPEG data.
- * @param imageTypes The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for
+ * @param imageType The image type from which to retrieve metadata. Use IFD_TYPE_PRIMARY for
* primary image, IFD_TYPE_PREVIEW for preview image, and
* IFD_TYPE_THUMBNAIL for thumbnail image.
* @throws IOException If the data contains invalid JPEG markers, offsets, or length values.
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index e07856e46779..7e3f67b875e5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -39,6 +39,8 @@ public final class CategoryKey {
public static final String CATEGORY_SYSTEM_INPUT = "com.android.settings.category.ia.input";
public static final String CATEGORY_SYSTEM_LANGUAGE =
"com.android.settings.category.ia.language";
+ public static final String CATEGORY_SYSTEM_DEVELOPMENT =
+ "com.android.settings.category.ia.development";
public static final Map<String, String> KEY_COMPAT_MAP;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index a0254cd94923..b209f4ec665a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -58,9 +58,10 @@ public class CategoryKeyTest {
allKeys.add(CategoryKey.CATEGORY_SYSTEM);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_INPUT);
allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
+ allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
// DO NOT REMOVE ANYTHING ABOVE
- assertThat(allKeys.size()).isEqualTo(13);
+ assertThat(allKeys.size()).isEqualTo(14);
}
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 9b4b1868cdbb..45f2ec76588a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2653,6 +2653,12 @@ message MetricsEvent {
// OS: O
ENTERPRISE_PRIVACY_SETTINGS = 628;
+ // ACTION: Longpress on a TextView.
+ // SUBTYPE: 1 is for START_SELECTION, 2 is for START_DRAG_AND_DROP, 0 is for OTHER.
+ // CATEGORY: TEXT_CONTROLS
+ // OS: O
+ TEXT_LONGPRESS = 629;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 543bba660ecc..883d2d81e19c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8699,9 +8699,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Managed user cannot have a managed profile.
return false;
}
+ boolean canRemoveProfile
+ = !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER);
final long ident = mInjector.binderClearCallingIdentity();
try {
- if (!mUserManager.canAddMoreManagedProfiles(callingUserId, true)) {
+ if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
return false;
}
} finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1202025751c7..ba23f219c106 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -52,6 +52,7 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.app.NightDisplayController;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.os.ZygoteInit;
@@ -275,7 +276,9 @@ public final class SystemServer {
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
+ int uptimeMillis = (int) SystemClock.uptimeMillis();
+ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
+ MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
@@ -364,6 +367,7 @@ public final class SystemServer {
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
+ MetricsLogger.histogram(null, "boot_system_server_ready", (int) SystemClock.uptimeMillis());
// Loop forever.
Looper.loop();
@@ -492,13 +496,16 @@ public final class SystemServer {
}
// Start the package manager.
+ MetricsLogger.histogram(null, "boot_package_manager_init_start",
+ (int) SystemClock.uptimeMillis());
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
-
+ MetricsLogger.histogram(null, "boot_package_manager_init_ready",
+ (int) SystemClock.uptimeMillis());
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 56ff6214a908..71379b8258e2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -2178,6 +2178,26 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, true);
}
+ public void testIsProvisioningAllowed_provisionManagedProfileCantRemoveUser_primaryUser()
+ throws Exception {
+ setDeviceOwner();
+
+ when(mContext.ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
+ .thenReturn(true);
+ when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+ when(mContext.userManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_USER))
+ .thenReturn(true);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ false /* we can't remove a managed profile*/)).thenReturn(false);
+ when(mContext.userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
+ true)).thenReturn(true);
+ setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
+
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ assertProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE, false);
+ }
+
public void testForceUpdateUserSetupComplete_permission() {
// GIVEN the permission MANAGE_PROFILE_AND_DEVICE_OWNERS is not granted
try {