diff options
Diffstat (limited to 'libs')
22 files changed, 658 insertions, 311 deletions
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index 43b330c..a40fac9 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -156,6 +156,10 @@ int SurfaceTextureClient::query(int what, int* value) { case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: *value = MIN_UNDEQUEUED_BUFFERS; return NO_ERROR; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: + // SurfaceTextureClient currently never queues frames to SurfaceFlinger. + *value = 0; + return NO_ERROR; } return BAD_VALUE; } diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk new file mode 100644 index 0000000..1dd8885 --- /dev/null +++ b/libs/gui/tests/Android.mk @@ -0,0 +1,53 @@ +# Build the unit tests. +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +ifneq ($(TARGET_SIMULATOR),true) + +# Build the unit tests. +test_src_files := \ + SurfaceTextureClient_test.cpp \ + +shared_libraries := \ + libcutils \ + libutils \ + libbinder \ + libgui \ + libstlport \ + +static_libraries := \ + libgtest \ + libgtest_main \ + +c_includes := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + +module_tags := tests + +$(foreach file,$(test_src_files), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ + $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ + $(eval LOCAL_C_INCLUDES := $(c_includes)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ + $(eval include $(BUILD_EXECUTABLE)) \ +) + +# Build the manual test programs. +include $(call all-subdir-makefiles) + +endif + +# Include subdirectory makefiles +# ============================================================ + +# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework +# team really wants is to build the stuff defined by this makefile. +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp new file mode 100644 index 0000000..0f140ff --- /dev/null +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 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 <gui/SurfaceTextureClient.h> +#include <gtest/gtest.h> + +namespace android { + +class SurfaceTextureClientTest : public ::testing::Test { +protected: + virtual void SetUp() { + mST = new SurfaceTexture(123); + mSTC = new SurfaceTextureClient(mST); + } + + virtual void TearDown() { + mST.clear(); + mSTC.clear(); + } + + sp<SurfaceTexture> mST; + sp<SurfaceTextureClient> mSTC; +}; + +TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) { + sp<ANativeWindow> anw(mSTC); + int result = -123; + int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &result); + EXPECT_EQ(NO_ERROR, err); + EXPECT_EQ(0, result); +} + +} diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 38e0848..f4a0161 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -15,7 +15,6 @@ ifeq ($(USE_OPENGL_RENDERER),true) LayerCache.cpp \ LayerRenderer.cpp \ Matrix.cpp \ - OpenGLDebugRenderer.cpp \ OpenGLRenderer.cpp \ Patch.cpp \ PatchCache.cpp \ diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index d5d2ba0..737fa02 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -166,7 +166,7 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde void DisplayList::init() { } -bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { +bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) { bool needsInvalidate = false; TextContainer text; mReader.rewind(); @@ -189,7 +189,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { case DrawGLFunction: { Functor *functor = (Functor *) getInt(); DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor); - needsInvalidate |= renderer.callDrawGLFunction(functor); + needsInvalidate |= renderer.callDrawGLFunction(functor, dirty); } break; case Save: { @@ -287,7 +287,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t level) { DisplayList* displayList = getDisplayList(); DISPLAY_LIST_LOGD("%s%s %p, %d", (char*) indent, OP_NAMES[op], displayList, level + 1); - needsInvalidate |= renderer.drawDisplayList(displayList, level + 1); + needsInvalidate |= renderer.drawDisplayList(displayList, dirty, level + 1); } break; case DrawLayer: { @@ -589,7 +589,8 @@ void DisplayListRenderer::interrupt() { void DisplayListRenderer::resume() { } -bool DisplayListRenderer::callDrawGLFunction(Functor *functor) { +bool DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) { + // Ignore dirty during recording, it matters only when we replay addOp(DisplayList::DrawGLFunction); addInt((int) functor); return false; // No invalidate needed at record-time @@ -673,7 +674,9 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot return OpenGLRenderer::clipRect(left, top, right, bottom, op); } -bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { +bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) { + // dirty is an out parameter and should not be recorded, + // it matters only when replaying the display list addOp(DisplayList::DrawDisplayList); addDisplayList(displayList); return false; diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index e8f189d..f24545d 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -103,7 +103,7 @@ public: void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false); - bool replay(OpenGLRenderer& renderer, uint32_t level = 0); + bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0); private: void init(); @@ -214,7 +214,7 @@ public: void prepareDirty(float left, float top, float right, float bottom, bool opaque); void finish(); - bool callDrawGLFunction(Functor *functor); + bool callDrawGLFunction(Functor *functor, Rect& dirty); void interrupt(); void resume(); @@ -238,7 +238,7 @@ public: bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); + bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0); void drawLayer(Layer* layer, float x, float y, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp deleted file mode 100644 index 05870bb..0000000 --- a/libs/hwui/OpenGLDebugRenderer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "OpenGLRenderer" - -#include <utils/StopWatch.h> - -#include "OpenGLDebugRenderer.h" - -namespace android { -namespace uirenderer { - -void OpenGLDebugRenderer::prepareDirty(float left, float top, - float right, float bottom, bool opaque) { - mPrimitivesCount = 0; - LOGD("========= Frame start ========="); - OpenGLRenderer::prepareDirty(left, top, right, bottom, opaque); -} - -void OpenGLDebugRenderer::finish() { - LOGD("========= Frame end ========="); - LOGD("Primitives draw count = %d", mPrimitivesCount); - OpenGLRenderer::finish(); -} - -void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { - mPrimitivesCount++; - StopWatch w("composeLayer"); - return OpenGLRenderer::composeLayer(current, previous); -} - -int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom, - SkPaint* p, int flags) { - mPrimitivesCount++; - StopWatch w("saveLayer"); - return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags); -} - -bool OpenGLDebugRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { - mPrimitivesCount++; - StopWatch w("drawDisplayList"); - return OpenGLRenderer::drawDisplayList(displayList); -} - -void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawLayer"); - OpenGLRenderer::drawLayer(layer, x, y, paint); -} - -void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, - SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawBitmap"); - OpenGLRenderer::drawBitmap(bitmap, left, top, paint); -} - -void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, - SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawBitmapMatrix"); - OpenGLRenderer::drawBitmap(bitmap, matrix, paint); -} - -void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawBitmapRect"); - OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom, - dstLeft, dstTop, dstRight, dstBottom, paint); -} - -void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, - const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, - float left, float top, float right, float bottom, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawPatch"); - OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors, - left, top, right, bottom, paint); -} - -void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) { - mPrimitivesCount++; - StopWatch w("drawColor"); - OpenGLRenderer::drawColor(color, mode); -} - -void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom, - SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawRect"); - OpenGLRenderer::drawRect(left, top, right, bottom, paint); -} - -void OpenGLDebugRenderer::drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawRoundRect"); - OpenGLRenderer::drawRoundRect(left, top, right, bottom, rx, ry, paint); -} - -void OpenGLDebugRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawCircle"); - OpenGLRenderer::drawCircle(x, y, radius, paint); -} - -void OpenGLDebugRenderer::drawOval(float left, float top, float right, float bottom, - SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawOval"); - OpenGLRenderer::drawOval(left, top, right, bottom, paint); -} - -void OpenGLDebugRenderer::drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawArc"); - OpenGLRenderer::drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint); -} - -void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawPath"); - OpenGLRenderer::drawPath(path, paint); -} - -void OpenGLDebugRenderer::drawLines(float* points, int count, SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawLines"); - OpenGLRenderer::drawLines(points, count, paint); -} - -void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, - SkPaint* paint) { - mPrimitivesCount++; - StopWatch w("drawText"); - OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h deleted file mode 100644 index 1a18a67..0000000 --- a/libs/hwui/OpenGLDebugRenderer.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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_HWUI_OPENGL_DEBUG_RENDERER_H -#define ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H - -#include "OpenGLRenderer.h" - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Renderer -/////////////////////////////////////////////////////////////////////////////// - -class OpenGLDebugRenderer: public OpenGLRenderer { -public: - OpenGLDebugRenderer(): mPrimitivesCount(0) { - } - - ~OpenGLDebugRenderer() { - } - - void prepareDirty(float left, float top, float right, float bottom, bool opaque); - void finish(); - - int saveLayer(float left, float top, float right, float bottom, - SkPaint* p, int flags); - - bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); - void drawLayer(Layer* layer, float x, float y, SkPaint* paint); - void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); - void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); - void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, - float srcRight, float srcBottom, float dstLeft, float dstTop, - float dstRight, float dstBottom, SkPaint* paint); - void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, - const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, - float left, float top, float right, float bottom, SkPaint* paint); - void drawColor(int color, SkXfermode::Mode mode); - void drawRect(float left, float top, float right, float bottom, SkPaint* paint); - void drawRoundRect(float left, float top, float right, float bottom, - float rx, float ry, SkPaint* paint); - void drawCircle(float x, float y, float radius, SkPaint* paint); - void drawOval(float left, float top, float right, float bottom, SkPaint* paint); - void drawArc(float left, float top, float right, float bottom, - float startAngle, float sweepAngle, bool useCenter, SkPaint* paint); - void drawPath(SkPath* path, SkPaint* paint); - void drawLines(float* points, int count, SkPaint* paint); - void drawText(const char* text, int bytesCount, int count, float x, float y, - SkPaint* paint); - -protected: - void composeLayer(sp<Snapshot> current, sp<Snapshot> previous); - -private: - uint32_t mPrimitivesCount; - -}; // class OpenGLDebugRenderer - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_OPENGL_DEBUG_RENDERER_H diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index dfca7eb..1f65201 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -210,7 +210,7 @@ void OpenGLRenderer::resume() { glBlendEquation(GL_FUNC_ADD); } -bool OpenGLRenderer::callDrawGLFunction(Functor *functor) { +bool OpenGLRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) { interrupt(); if (mDirtyClip) { setScissorFromClip(); @@ -226,9 +226,16 @@ bool OpenGLRenderer::callDrawGLFunction(Functor *functor) { } #endif - status_t result = (*functor)(); + float bounds[4]; + status_t result = (*functor)(&bounds[0], 4); + + if (result != 0) { + Rect localDirty(bounds[0], bounds[1], bounds[2], bounds[3]); + dirty.unionWith(localDirty); + } + resume(); - return (result == 0) ? false : true; + return result != 0; } /////////////////////////////////////////////////////////////////////////////// @@ -1057,11 +1064,11 @@ void OpenGLRenderer::finishDrawTexture() { // Drawing /////////////////////////////////////////////////////////////////////////////// -bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t level) { +bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level) { // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList) { - return displayList->replay(*this, level); + return displayList->replay(*this, dirty, level); } return false; } @@ -1522,7 +1529,6 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, break; } - // TODO: Handle paint->getTextScaleX() const float oldX = x; const float oldY = y; const bool pureTranslate = mSnapshot->transform->isPureTranslate(); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 7bbf034..9d86388 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -70,7 +70,7 @@ public: virtual void interrupt(); virtual void resume(); - virtual bool callDrawGLFunction(Functor *functor); + virtual bool callDrawGLFunction(Functor *functor, Rect& dirty); int getSaveCount() const; virtual int save(int flags); @@ -96,7 +96,7 @@ public: bool quickReject(float left, float top, float right, float bottom); virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); - virtual bool drawDisplayList(DisplayList* displayList, uint32_t level = 0); + virtual bool drawDisplayList(DisplayList* displayList, Rect& dirty, uint32_t level = 0); virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index 62c4250..d46686d 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -42,6 +42,17 @@ struct ShadowText { textSize = paint->getTextSize(); typeface = paint->getTypeface(); + + flags = 0; + if (paint->isFakeBoldText()) { + flags |= Font::kFakeBold; + } + + const float skewX = paint->getTextSkewX(); + italicStyle = *(uint32_t*) &skewX; + + const float scaleXFloat = paint->getTextScaleX(); + scaleX = *(uint32_t*) &scaleXFloat; } ~ShadowText() { @@ -51,6 +62,9 @@ struct ShadowText { uint32_t len; float textSize; SkTypeface* typeface; + uint32_t flags; + uint32_t italicStyle; + uint32_t scaleX; const char16_t* text; String16 str; @@ -65,7 +79,13 @@ struct ShadowText { LTE_INT(radius) { LTE_FLOAT(textSize) { LTE_INT(typeface) { - return strncmp16(text, rhs.text, len >> 1) < 0; + LTE_INT(flags) { + LTE_INT(italicStyle) { + LTE_INT(scaleX) { + return strncmp16(text, rhs.text, len >> 1) < 0; + } + } + } } } } diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 4a5620d..f9e29f1 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -592,11 +592,11 @@ void * Context::helperThreadProc(void *vrsc) { void Context::launchThreads(WorkerCallback_t cbk, void *data) { mWorkers.mLaunchData = data; mWorkers.mLaunchCallback = cbk; - mWorkers.mRunningCount = (int)mWorkers.mCount; + android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { mWorkers.mLaunchSignals[ct].set(); } - while (mWorkers.mRunningCount) { + while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { mWorkers.mCompleteSignal.wait(); } } @@ -707,8 +707,8 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { } mWorkers.mCompleteSignal.init(); - mWorkers.mRunningCount = 0; - mWorkers.mLaunchCount = 0; + android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); + android_atomic_release_store(0, &mWorkers.mLaunchCount); for (uint32_t ct=0; ct < mWorkers.mCount; ct++) { status = pthread_create(&mWorkers.mThreadId[ct], &threadAttr, helperThreadProc, this); if (status) { @@ -717,6 +717,9 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) { break; } } + while (android_atomic_acquire_load(&mWorkers.mRunningCount) != 0) { + usleep(100); + } pthread_attr_destroy(&threadAttr); return true; } @@ -736,14 +739,14 @@ Context::~Context() { // Cleanup compute threads. mWorkers.mLaunchData = NULL; mWorkers.mLaunchCallback = NULL; - mWorkers.mRunningCount = (int)mWorkers.mCount; + android_atomic_release_store(mWorkers.mCount, &mWorkers.mRunningCount); for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { mWorkers.mLaunchSignals[ct].set(); } for (uint32_t ct = 0; ct < mWorkers.mCount; ct++) { status = pthread_join(mWorkers.mThreadId[ct], &res); } - rsAssert(!mWorkers.mRunningCount); + rsAssert(android_atomic_acquire_load(&mWorkers.mRunningCount) == 0); // Global structure cleanup. pthread_mutex_lock(&gInitMutex); diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index 01ae23f..8951c3f 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -25,9 +25,11 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <surfaceflinger/ISurfaceComposer.h> + #include <ui/DisplayInfo.h> -#include <surfaceflinger/ISurfaceComposer.h> +#include <utils/Log.h> // --------------------------------------------------------------------------- @@ -178,6 +180,40 @@ public: data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY); } + + virtual bool authenticateSurface(const sp<ISurface>& surface) const + { + Parcel data, reply; + int err = NO_ERROR; + err = data.writeInterfaceToken( + ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + LOGE("ISurfaceComposer::authenticateSurface: error writing " + "interface descriptor: %s (%d)", strerror(-err), -err); + return false; + } + err = data.writeStrongBinder(surface->asBinder()); + if (err != NO_ERROR) { + LOGE("ISurfaceComposer::authenticateSurface: error writing strong " + "binder to parcel: %s (%d)", strerror(-err), -err); + return false; + } + err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data, + &reply); + if (err != NO_ERROR) { + LOGE("ISurfaceComposer::authenticateSurface: error performing " + "transaction: %s (%d)", strerror(-err), -err); + return false; + } + int32_t result = 0; + err = reply.readInt32(&result); + if (err != NO_ERROR) { + LOGE("ISurfaceComposer::authenticateSurface: error retrieving " + "result: %s (%d)", strerror(-err), -err); + return false; + } + return result != 0; + } }; IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); @@ -273,6 +309,12 @@ status_t BnSurfaceComposer::onTransact( status_t res = turnElectronBeamOn(mode); reply->writeInt32(res); } break; + case AUTHENTICATE_SURFACE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder()); + int32_t result = authenticateSurface(surface) ? 1 : 0; + reply->writeInt32(result); + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 818114a..afabbf4 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -712,6 +712,10 @@ int Surface::query(int what, int* value) case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: *value = MIN_UNDEQUEUED_BUFFERS; return NO_ERROR; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + *value = sf->authenticateSurface(mSurface) ? 1 : 0; + return NO_ERROR; } return BAD_VALUE; } diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk index 5053e7d..212b8e7 100644 --- a/libs/surfaceflinger_client/tests/Android.mk +++ b/libs/surfaceflinger_client/tests/Android.mk @@ -1 +1,53 @@ +# Build the unit tests. +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +ifneq ($(TARGET_SIMULATOR),true) + +# Build the unit tests. +test_src_files := \ + Surface_test.cpp \ + +shared_libraries := \ + libcutils \ + libutils \ + libbinder \ + libsurfaceflinger_client \ + libstlport \ + +static_libraries := \ + libgtest \ + libgtest_main \ + +c_includes := \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + +module_tags := tests + +$(foreach file,$(test_src_files), \ + $(eval include $(CLEAR_VARS)) \ + $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ + $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ + $(eval LOCAL_C_INCLUDES := $(c_includes)) \ + $(eval LOCAL_SRC_FILES := $(file)) \ + $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ + $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ + $(eval include $(BUILD_EXECUTABLE)) \ +) + +# Build the manual test programs. include $(call all-subdir-makefiles) + +endif + +# Include subdirectory makefiles +# ============================================================ + +# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework +# team really wants is to build the stuff defined by this makefile. +ifeq (,$(ONE_SHOT_MAKEFILE)) +include $(call first-makefiles-under,$(LOCAL_PATH)) +endif diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/surfaceflinger_client/tests/Surface_test.cpp new file mode 100644 index 0000000..74ebf4e --- /dev/null +++ b/libs/surfaceflinger_client/tests/Surface_test.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2011 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 <gtest/gtest.h> + +#include <binder/IMemory.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/Surface.h> +#include <surfaceflinger/SurfaceComposerClient.h> +#include <utils/String8.h> + +namespace android { + +class SurfaceTest : public ::testing::Test { +protected: + virtual void SetUp() { + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + mSurfaceControl = mComposerClient->createSurface(getpid(), + String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0); + + ASSERT_TRUE(mSurfaceControl != NULL); + ASSERT_TRUE(mSurfaceControl->isValid()); + + ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction()); + ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000)); + ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); + ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction()); + + mSurface = mSurfaceControl->getSurface(); + ASSERT_TRUE(mSurface != NULL); + } + + virtual void TearDown() { + mComposerClient->dispose(); + } + + sp<Surface> mSurface; + sp<SurfaceComposerClient> mComposerClient; + sp<SurfaceControl> mSurfaceControl; +}; + +TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { + sp<ANativeWindow> anw(mSurface); + int result = -123; + int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &result); + EXPECT_EQ(NO_ERROR, err); + EXPECT_EQ(1, result); +} + +TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { + mSurfaceControl.clear(); + + sp<ANativeWindow> anw(mSurface); + int result = -123; + int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &result); + EXPECT_EQ(NO_ERROR, err); + EXPECT_EQ(1, result); +} + +// This test probably doesn't belong here. +TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersFail) { + sp<ANativeWindow> anw(mSurface); + + // Verify the screenshot works with no protected buffers. + sp<IMemoryHeap> heap; + uint32_t w=0, h=0; + PixelFormat fmt=0; + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, + 40000)); + ASSERT_TRUE(heap != NULL); + + // Set the PROTECTED usage bit and verify that the screenshot fails. Note + // that we need to dequeue a buffer in order for it to actually get + // allocated in SurfaceFlinger. + ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), + GRALLOC_USAGE_PROTECTED)); + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); + android_native_buffer_t* buf = 0; + for (int i = 0; i < 4; i++) { + // Loop to make sure SurfaceFlinger has retired a protected buffer. + ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); + ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf)); + ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf)); + } + heap = 0; + w = h = fmt = 0; + ASSERT_EQ(INVALID_OPERATION, sf->captureScreen(0, &heap, &w, &h, &fmt, + 64, 64, 0, 40000)); + ASSERT_TRUE(heap == NULL); + + // XXX: This should not be needed, but it seems that the new buffers don't + // correctly show up after the upcoming dequeue/lock/queue loop without it. + // We should look into this at some point. + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3)); + + // Un-set the PROTECTED usage bit and verify that the screenshot works + // again. Note that we have to change the buffers geometry to ensure that + // the buffers get reallocated, as the new usage bits are a subset of the + // old. + ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0)); + ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(anw.get(), 32, 32, 0)); + for (int i = 0; i < 4; i++) { + // Loop to make sure SurfaceFlinger has retired a protected buffer. + ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf)); + ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf)); + ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf)); + } + heap = 0; + w = h = fmt = 0; + ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0, + 40000)); + ASSERT_TRUE(heap != NULL); +} + +} diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 0ed0866..e2e698e 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -657,23 +657,30 @@ void InputDeviceInfo::initialize(int32_t id, const String8& name) { mMotionRanges.clear(); } -const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const { - ssize_t index = mMotionRanges.indexOfKey(axis); - return index >= 0 ? & mMotionRanges.valueAt(index) : NULL; +const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( + int32_t axis, uint32_t source) const { + size_t numRanges = mMotionRanges.size(); + for (size_t i = 0; i < numRanges; i++) { + const MotionRange& range = mMotionRanges.itemAt(i); + if (range.axis == axis && range.source == source) { + return ⦥ + } + } + return NULL; } void InputDeviceInfo::addSource(uint32_t source) { mSources |= source; } -void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max, +void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) { - MotionRange range = { min, max, flat, fuzz }; - addMotionRange(axis, range); + MotionRange range = { axis, source, min, max, flat, fuzz }; + mMotionRanges.add(range); } -void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) { - mMotionRanges.add(axis, range); +void InputDeviceInfo::addMotionRange(const MotionRange& range) { + mMotionRanges.add(range); } } // namespace android diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp index 2ed0e66..8626a03 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -113,20 +113,23 @@ status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* out return NO_ERROR; } -status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const { +status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { ssize_t index = mAxes.indexOfKey(scanCode); if (index < 0) { #if DEBUG_MAPPING LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); #endif - *axis = -1; return NAME_NOT_FOUND; } - *axis = mAxes.valueAt(index); + *outAxisInfo = mAxes.valueAt(index); #if DEBUG_MAPPING - LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis); + LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " + "splitValue=%d, flatOverride=%d.", + scanCode, + outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, + outAxisInfo->splitValue, outAxisInfo->flatOverride); #endif return NO_ERROR; } @@ -249,19 +252,89 @@ status_t KeyLayoutMap::Parser::parseAxis() { return BAD_VALUE; } + AxisInfo axisInfo; + mTokenizer->skipDelimiters(WHITESPACE); - String8 axisToken = mTokenizer->nextToken(WHITESPACE); - int32_t axis = getAxisByLabel(axisToken.string()); - if (axis < 0) { - LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(), - axisToken.string()); - return BAD_VALUE; + String8 token = mTokenizer->nextToken(WHITESPACE); + if (token == "invert") { + axisInfo.mode = AxisInfo::MODE_INVERT; + + mTokenizer->skipDelimiters(WHITESPACE); + String8 axisToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.axis = getAxisByLabel(axisToken.string()); + if (axisInfo.axis < 0) { + LOGE("%s: Expected inverted axis label, got '%s'.", + mTokenizer->getLocation().string(), axisToken.string()); + return BAD_VALUE; + } + } else if (token == "split") { + axisInfo.mode = AxisInfo::MODE_SPLIT; + + mTokenizer->skipDelimiters(WHITESPACE); + String8 splitToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); + if (*end) { + LOGE("%s: Expected split value, got '%s'.", + mTokenizer->getLocation().string(), splitToken.string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.axis = getAxisByLabel(lowAxisToken.string()); + if (axisInfo.axis < 0) { + LOGE("%s: Expected low axis label, got '%s'.", + mTokenizer->getLocation().string(), lowAxisToken.string()); + return BAD_VALUE; + } + + mTokenizer->skipDelimiters(WHITESPACE); + String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); + if (axisInfo.highAxis < 0) { + LOGE("%s: Expected high axis label, got '%s'.", + mTokenizer->getLocation().string(), highAxisToken.string()); + return BAD_VALUE; + } + } else { + axisInfo.axis = getAxisByLabel(token.string()); + if (axisInfo.axis < 0) { + LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", + mTokenizer->getLocation().string(), token.string()); + return BAD_VALUE; + } + } + + for (;;) { + mTokenizer->skipDelimiters(WHITESPACE); + if (mTokenizer->isEol()) { + break; + } + String8 keywordToken = mTokenizer->nextToken(WHITESPACE); + if (keywordToken == "flat") { + mTokenizer->skipDelimiters(WHITESPACE); + String8 flatToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); + if (*end) { + LOGE("%s: Expected flat value, got '%s'.", + mTokenizer->getLocation().string(), flatToken.string()); + return BAD_VALUE; + } + } else { + LOGE("%s: Expected keyword 'flat', got '%s'.", + mTokenizer->getLocation().string(), keywordToken.string()); + return BAD_VALUE; + } } #if DEBUG_PARSER - LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis); + LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " + "splitValue=%d, flatOverride=%d.", + scanCode, + axisInfo.mode, axisInfo.axis, axisInfo.highAxis, + axisInfo.splitValue, axisInfo.flatOverride); #endif - mMap->mAxes.add(scanCode, axis); + mMap->mAxes.add(scanCode, axisInfo); return NO_ERROR; } diff --git a/libs/usb/src/com/android/future/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java index cdd2b73..3d0707f 100644 --- a/libs/usb/src/com/android/future/usb/UsbAccessory.java +++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java @@ -23,14 +23,16 @@ public final class UsbAccessory { private final String mManufacturer; private final String mModel; - private final String mType; + private final String mDescription; private final String mVersion; + private final String mUri; /* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) { mManufacturer = accessory.getManufacturer(); mModel = accessory.getModel(); - mType = accessory.getType(); + mDescription = accessory.getDescription(); mVersion = accessory.getVersion(); + mUri = accessory.getUri(); } /** @@ -52,12 +54,12 @@ public final class UsbAccessory { } /** - * Returns the type of the accessory. + * Returns a user visible description of the accessory. * - * @return the accessory type + * @return the accessory description */ - public String getType() { - return mType; + public String getDescription() { + return mDescription; } /** @@ -69,6 +71,17 @@ public final class UsbAccessory { return mVersion; } + /** + * Returns the URI for the accessory. + * This is an optional URI that might show information about the accessory + * or provide the option to download an application for the accessory + * + * @return the accessory URI + */ + public String getUri() { + return mUri; + } + private static boolean compare(String s1, String s2) { if (s1 == null) return (s2 == null); return s1.equals(s2); @@ -80,17 +93,28 @@ public final class UsbAccessory { UsbAccessory accessory = (UsbAccessory)obj; return (compare(mManufacturer, accessory.getManufacturer()) && compare(mModel, accessory.getModel()) && - compare(mType, accessory.getType()) && - compare(mVersion, accessory.getVersion())); + compare(mDescription, accessory.getDescription()) && + compare(mVersion, accessory.getVersion()) && + compare(mUri, accessory.getUri())); } return false; } @Override + public int hashCode() { + return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^ + (mModel == null ? 0 : mModel.hashCode()) ^ + (mDescription == null ? 0 : mDescription.hashCode()) ^ + (mVersion == null ? 0 : mVersion.hashCode()) ^ + (mUri == null ? 0 : mUri.hashCode())); + } + + @Override public String toString() { return "UsbAccessory[mManufacturer=" + mManufacturer + ", mModel=" + mModel + - ", mType=" + mType + - ", mVersion=" + mVersion + "]"; + ", mDescription=" + mDescription + + ", mVersion=" + mVersion + + ", mUri=" + mUri + "]"; } } diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java index f74b291..840e1e3 100644 --- a/libs/usb/src/com/android/future/usb/UsbManager.java +++ b/libs/usb/src/com/android/future/usb/UsbManager.java @@ -17,6 +17,7 @@ package com.android.future.usb; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.hardware.usb.IUsbManager; @@ -55,28 +56,39 @@ public class UsbManager { public static final String ACTION_USB_ACCESSORY_DETACHED = "android.hardware.usb.action.USB_ACCESSORY_DETACHED"; + /** + * Name of extra added to the {@link android.app.PendingIntent} + * passed into {#requestPermission} or {#requestPermission} + * containing a boolean value indicating whether the user granted permission or not. + */ + public static final String EXTRA_PERMISSION_GRANTED = "permission"; + + private final Context mContext; private final IUsbManager mService; - private UsbManager(IUsbManager service) { + private UsbManager(Context context, IUsbManager service) { + mContext = context; mService = service; } /** * Returns a new instance of this class. * + * @param context the caller's {@link android.content.Context} * @return UsbManager instance. */ - public static UsbManager getInstance() { + public static UsbManager getInstance(Context context) { IBinder b = ServiceManager.getService(Context.USB_SERVICE); - return new UsbManager(IUsbManager.Stub.asInterface(b)); + return new UsbManager(context, IUsbManager.Stub.asInterface(b)); } /** * Returns the {@link com.google.android.usb.UsbAccessory} for * a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED} - * broadcast Intent + * broadcast Intent. This can also be used to retrieve the accessory from the result + * of a call to {#requestPermission}. * - * @return UsbAccessory for the broadcast. + * @return UsbAccessory for the intent. */ public static UsbAccessory getAccessory(Intent intent) { android.hardware.usb.UsbAccessory accessory = @@ -118,10 +130,54 @@ public class UsbManager { try { return mService.openAccessory(new android.hardware.usb.UsbAccessory( accessory.getManufacturer(),accessory.getModel(), - accessory.getType(), accessory.getVersion())); + accessory.getDescription(), accessory.getVersion(), accessory.getUri())); } catch (RemoteException e) { Log.e(TAG, "RemoteException in openAccessory" , e); return null; } } + + /** + * Returns true if the caller has permission to access the accessory. + * Permission might have been granted temporarily via + * {@link #requestPermission(android.hardware.usb.UsbAccessory} or + * by the user choosing the caller as the default application for the accessory. + * + * @param accessory to check permissions for + * @return true if caller has permission + */ + public boolean hasPermission(UsbAccessory accessory) { + try { + return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory( + accessory.getManufacturer(),accessory.getModel(), + accessory.getDescription(), accessory.getVersion(), accessory.getUri())); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in hasPermission", e); + return false; + } + } + + /** + * Requests temporary permission for the given package to access the accessory. + * This may result in a system dialog being displayed to the user + * if permission had not already been granted. + * Success or failure is returned via the {@link android.app.PendingIntent} pi. + * The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the + * PendingIntent to indicate success or failure. + * If successful, this grants the caller permission to access the device only + * until the device is disconnected. + * + * @param accessory to request permissions for + * @param pi PendingIntent for returning result + */ + public void requestPermission(UsbAccessory accessory, PendingIntent pi) { + try { + mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory( + accessory.getManufacturer(),accessory.getModel(), + accessory.getDescription(), accessory.getVersion(), accessory.getUri()), + mContext.getPackageName(), pi); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in requestPermission", e); + } + } } diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c index 94cc0ce..3c0de69 100644 --- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c +++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c @@ -133,10 +133,19 @@ static int usb_device_added(const char *devname, void* client_data) { } else { printf("Found possible android device - attempting to switch to accessory mode\n"); + uint16_t protocol; + ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR, + ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0); + if (ret == 2) + printf("device supports protocol version %d\n", protocol); + else + fprintf(stderr, "failed to read protocol version\n"); + send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc."); send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat"); - send_string(device, ACCESSORY_STRING_TYPE, "Sample Program"); + send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program"); send_string(device, ACCESSORY_STRING_VERSION, "1.0"); + send_string(device, ACCESSORY_STRING_URI, "http://www.android.com"); ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR, ACCESSORY_START, 0, 0, 0, 0, 0); diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java index 5cf02c7..f9a5bf4 100644 --- a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java +++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java @@ -17,9 +17,11 @@ package com.android.accessorychat; import android.app.Activity; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -42,18 +44,47 @@ import java.io.IOException; public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener { private static final String TAG = "AccessoryChat"; - TextView mLog; - EditText mEditText; - ParcelFileDescriptor mFileDescriptor; - FileInputStream mInputStream; - FileOutputStream mOutputStream; + + private static final String ACTION_USB_PERMISSION = + "com.android.accessorychat.action.USB_PERMISSION"; + + private TextView mLog; + private EditText mEditText; + private ParcelFileDescriptor mFileDescriptor; + private FileInputStream mInputStream; + private FileOutputStream mOutputStream; + private UsbManager mUsbManager; + private PendingIntent mPermissionIntent; + private boolean mPermissionRequestPending; private static final int MESSAGE_LOG = 1; + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_USB_PERMISSION.equals(intent.getAction())) { + synchronized (this) { + UsbAccessory accessory = UsbManager.getAccessory(intent); + if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { + openAccessory(accessory); + } else { + Log.d(TAG, "permission denied for accessory " + accessory); + } + mPermissionRequestPending = false; + } + } + } + }; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mUsbManager = UsbManager.getInstance(this); + mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); + IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); + registerReceiver(mUsbReceiver, filter); + setContentView(R.layout.accessory_chat); mLog = (TextView)findViewById(R.id.log); mEditText = (EditText)findViewById(R.id.message); @@ -66,21 +97,20 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit Intent intent = getIntent(); Log.d(TAG, "intent: " + intent); - UsbManager manager = UsbManager.getInstance(); - UsbAccessory[] accessories = manager.getAccessoryList(); + UsbAccessory[] accessories = mUsbManager.getAccessoryList(); UsbAccessory accessory = (accessories == null ? null : accessories[0]); if (accessory != null) { - mFileDescriptor = manager.openAccessory(accessory); - if (mFileDescriptor != null) { - FileDescriptor fd = mFileDescriptor.getFileDescriptor(); - mInputStream = new FileInputStream(fd); - mOutputStream = new FileOutputStream(fd); - Thread thread = new Thread(null, this, "AccessoryChat"); - thread.start(); + if (mUsbManager.hasPermission(accessory)) { + openAccessory(accessory); } else { - Log.d(TAG, "openAccessory fail"); + synchronized (mUsbReceiver) { + if (!mPermissionRequestPending) { + mUsbManager.requestPermission(accessory, mPermissionIntent); + mPermissionRequestPending = true; + } + } } - } else { + } else { Log.d(TAG, "mAccessory is null"); } } @@ -100,9 +130,24 @@ public class AccessoryChat extends Activity implements Runnable, TextView.OnEdit @Override public void onDestroy() { + unregisterReceiver(mUsbReceiver); super.onDestroy(); } + private void openAccessory(UsbAccessory accessory) { + mFileDescriptor = mUsbManager.openAccessory(accessory); + if (mFileDescriptor != null) { + FileDescriptor fd = mFileDescriptor.getFileDescriptor(); + mInputStream = new FileInputStream(fd); + mOutputStream = new FileOutputStream(fd); + Thread thread = new Thread(null, this, "AccessoryChat"); + thread.start(); + Log.d(TAG, "openAccessory succeeded"); + } else { + Log.d(TAG, "openAccessory fail"); + } + } + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) { try { |
