diff options
| -rw-r--r-- | include/binder/IBinder.h | 2 | ||||
| -rw-r--r-- | include/ui/Input.h | 42 | ||||
| -rw-r--r-- | include/ui/KeyLayoutMap.h | 12 | ||||
| -rw-r--r-- | include/ui/Keyboard.h | 12 | ||||
| -rwxr-xr-x | include/ui/KeycodeLabels.h | 43 | ||||
| -rw-r--r-- | include/utils/RefBase.h | 285 | ||||
| -rw-r--r-- | include/utils/StrongPointer.h | 220 | ||||
| -rw-r--r-- | include/utils/TypeHelpers.h | 13 | ||||
| -rw-r--r-- | include/utils/threads.h | 3 | ||||
| -rw-r--r-- | libs/ui/Input.cpp | 56 | ||||
| -rw-r--r-- | libs/ui/InputTransport.cpp | 3 | ||||
| -rw-r--r-- | libs/ui/KeyLayoutMap.cpp | 70 | ||||
| -rw-r--r-- | libs/ui/Keyboard.cpp | 24 | ||||
| -rw-r--r-- | libs/ui/tests/InputEvent_test.cpp | 425 | ||||
| -rw-r--r-- | libs/utils/RefBase.cpp | 189 | ||||
| -rw-r--r-- | libs/utils/Threads.cpp | 27 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 48 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.h | 3 |
18 files changed, 1021 insertions, 456 deletions
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h index 749a977b83..81b56c2b2b 100644 --- a/include/binder/IBinder.h +++ b/include/binder/IBinder.h @@ -98,7 +98,7 @@ public: * Register the @a recipient for a notification if this binder * goes away. If this binder object unexpectedly goes away * (typically because its hosting process has been killed), - * then DeathRecipient::binderDied() will be called with a referene + * then DeathRecipient::binderDied() will be called with a reference * to this. * * The @a cookie is optional -- if non-NULL, it should be a diff --git a/include/ui/Input.h b/include/ui/Input.h index cb9327e121..86ce09835f 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -170,10 +170,10 @@ struct InputConfiguration { * Pointer coordinate data. */ struct PointerCoords { - enum { MAX_AXES = 15 }; // 15 so that sizeof(PointerCoords) == 16 * 4 == 64 + enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64 // Bitfield of axes that are present in this structure. - uint32_t bits; // 32bits are enough for now, can raise to 64bit when needed + uint64_t bits; // Values of axes that are stored in this structure packed in order by axis id // for each axis that is present in the structure according to 'bits'. @@ -183,41 +183,9 @@ struct PointerCoords { bits = 0; } - inline float getAxisValue(int32_t axis) const { - uint32_t axisBit = 1 << axis; - if (!(bits & axisBit)) { - return 0; - } - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - return values[index]; - } - - inline status_t setAxisValue(int32_t axis, float value) { - uint32_t axisBit = 1 << axis; - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - if (!(bits & axisBit)) { - uint32_t count = __builtin_popcount(bits); - if (count >= MAX_AXES) { - tooManyAxes(axis); - return NO_MEMORY; - } - bits |= axisBit; - for (uint32_t i = count; i > index; i--) { - values[i] = values[i - 1]; - } - } - values[index] = value; - return OK; - } - - inline float* editAxisValue(int32_t axis) { - uint32_t axisBit = 1 << axis; - if (!(bits & axisBit)) { - return NULL; - } - uint32_t index = __builtin_popcount(bits & (axisBit - 1)); - return &values[index]; - } + float getAxisValue(int32_t axis) const; + status_t setAxisValue(int32_t axis, float value); + float* editAxisValue(int32_t axis); #ifdef HAVE_ANDROID_OS status_t readFromParcel(Parcel* parcel); diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h index f0a6d001f2..904c8f305f 100644 --- a/include/ui/KeyLayoutMap.h +++ b/include/ui/KeyLayoutMap.h @@ -25,7 +25,7 @@ namespace android { /** - * Describes a mapping from keyboard scan codes to Android key codes. + * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. */ class KeyLayoutMap { public: @@ -33,8 +33,10 @@ public: static status_t load(const String8& filename, KeyLayoutMap** outMap); - status_t map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const; - status_t findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const; + status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const; + status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const; + + status_t mapAxis(int32_t scanCode, int32_t* axis) const; private: struct Key { @@ -42,7 +44,8 @@ private: uint32_t flags; }; - KeyedVector<int32_t,Key> mKeys; + KeyedVector<int32_t, Key> mKeys; + KeyedVector<int32_t, int32_t> mAxes; KeyLayoutMap(); @@ -57,6 +60,7 @@ private: private: status_t parseKey(); + status_t parseAxis(); }; }; diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h index 50296e29ba..54bc968e3c 100644 --- a/include/ui/Keyboard.h +++ b/include/ui/Keyboard.h @@ -111,6 +111,18 @@ extern int32_t getKeyCodeByLabel(const char* label); extern uint32_t getKeyFlagByLabel(const char* label); /** + * Gets a axis by its short form label, eg. "X". + * Returns -1 if unknown. + */ +extern int32_t getAxisByLabel(const char* label); + +/** + * Gets a axis label by its id. + * Returns NULL if unknown. + */ +extern const char* getAxisLabel(int32_t axisId); + +/** * Updates a meta state field when a key is pressed or released. */ extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index dbccf29b11..bdfbf7cace 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -250,4 +250,47 @@ static const KeycodeLabel FLAGS[] = { { NULL, 0 } }; +static const KeycodeLabel AXES[] = { + { "X", 0 }, + { "Y", 1 }, + { "PRESSURE", 2 }, + { "SIZE", 3 }, + { "TOUCH_MAJOR", 4 }, + { "TOUCH_MINOR", 5 }, + { "TOOL_MAJOR", 6 }, + { "TOOL_MINOR", 7 }, + { "ORIENTATION", 8 }, + { "VSCROLL", 9 }, + { "HSCROLL", 10 }, + { "Z", 11 }, + { "RX", 12 }, + { "RY", 13 }, + { "RZ", 14 }, + { "HAT_X", 15 }, + { "HAT_Y", 16 }, + { "LTRIGGER", 17 }, + { "RTRIGGER", 18 }, + { "GENERIC_1", 32 }, + { "GENERIC_2", 33 }, + { "GENERIC_3", 34 }, + { "GENERIC_4", 35 }, + { "GENERIC_5", 36 }, + { "GENERIC_6", 37 }, + { "GENERIC_7", 38 }, + { "GENERIC_8", 39 }, + { "GENERIC_9", 40 }, + { "GENERIC_10", 41 }, + { "GENERIC_11", 42 }, + { "GENERIC_12", 43 }, + { "GENERIC_13", 44 }, + { "GENERIC_14", 45 }, + { "GENERIC_15", 46 }, + { "GENERIC_16", 47 }, + + // NOTE: If you add a new axis here you must also add it to several other files. + // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. + + { NULL, -1 } +}; + #endif // _UI_KEYCODE_LABELS_H diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index c24c0dbcb2..f355087713 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -18,16 +18,19 @@ #define ANDROID_REF_BASE_H #include <cutils/atomic.h> -#include <utils/TextOutput.h> #include <stdint.h> #include <sys/types.h> #include <stdlib.h> +#include <string.h> + +#include <utils/StrongPointer.h> // --------------------------------------------------------------------------- namespace android { -template<typename T> class wp; +class TextOutput; +TextOutput& printWeakPointer(TextOutput& to, const void* val); // --------------------------------------------------------------------------- @@ -47,15 +50,15 @@ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ } -#define COMPARE(_op_) \ -COMPARE_WEAK(_op_) \ -inline bool operator _op_ (const wp<T>& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} \ -template<typename U> \ -inline bool operator _op_ (const wp<U>& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} +// --------------------------------------------------------------------------- + +class ReferenceMover; +class ReferenceConverterBase { +public: + virtual size_t getReferenceTypeSize() const = 0; + virtual void* getReferenceBase(void const*) const = 0; + inline virtual ~ReferenceConverterBase() { } +}; // --------------------------------------------------------------------------- @@ -112,6 +115,8 @@ public: getWeakRefs()->trackMe(enable, retain); } + typedef RefBase basetype; + protected: RefBase(); virtual ~RefBase(); @@ -135,6 +140,11 @@ protected: virtual void onLastWeakRef(const void* id); private: + friend class ReferenceMover; + static void moveReferences(void* d, void const* s, size_t n, + const ReferenceConverterBase& caster); + +private: friend class weakref_type; class weakref_impl; @@ -163,74 +173,21 @@ public: inline int32_t getStrongCount() const { return mCount; } - -protected: - inline ~LightRefBase() { } - -private: - mutable volatile int32_t mCount; -}; - -// --------------------------------------------------------------------------- - -template <typename T> -class sp -{ -public: - typedef typename RefBase::weakref_type weakref_type; - - inline sp() : m_ptr(0) { } - sp(T* other); - sp(const sp<T>& other); - template<typename U> sp(U* other); - template<typename U> sp(const sp<U>& other); - - ~sp(); - - // Assignment - - sp& operator = (T* other); - sp& operator = (const sp<T>& other); - - template<typename U> sp& operator = (const sp<U>& other); - template<typename U> sp& operator = (U* other); - - //! Special optimization for use by ProcessState (and nobody else). - void force_set(T* other); - - // Reset - - void clear(); - - // Accessors + typedef LightRefBase<T> basetype; - inline T& operator* () const { return *m_ptr; } - inline T* operator-> () const { return m_ptr; } - inline T* get() const { return m_ptr; } +protected: + inline ~LightRefBase() { } - // Operators - - COMPARE(==) - COMPARE(!=) - COMPARE(>) - COMPARE(<) - COMPARE(<=) - COMPARE(>=) - -private: - template<typename Y> friend class sp; - template<typename Y> friend class wp; +private: + friend class ReferenceMover; + inline static void moveReferences(void* d, void const* s, size_t n, + const ReferenceConverterBase& caster) { } - // Optimization for wp::promote(). - sp(T* p, weakref_type* refs); - - T* m_ptr; +private: + mutable volatile int32_t mCount; }; -template <typename T> -TextOutput& operator<<(TextOutput& to, const sp<T>& val); - // --------------------------------------------------------------------------- template <typename T> @@ -326,114 +283,12 @@ private: template <typename T> TextOutput& operator<<(TextOutput& to, const wp<T>& val); -#undef COMPARE #undef COMPARE_WEAK // --------------------------------------------------------------------------- // No user serviceable parts below here. template<typename T> -sp<T>::sp(T* other) - : m_ptr(other) -{ - if (other) other->incStrong(this); -} - -template<typename T> -sp<T>::sp(const sp<T>& other) - : m_ptr(other.m_ptr) -{ - if (m_ptr) m_ptr->incStrong(this); -} - -template<typename T> template<typename U> -sp<T>::sp(U* other) : m_ptr(other) -{ - if (other) other->incStrong(this); -} - -template<typename T> template<typename U> -sp<T>::sp(const sp<U>& other) - : m_ptr(other.m_ptr) -{ - if (m_ptr) m_ptr->incStrong(this); -} - -template<typename T> -sp<T>::~sp() -{ - if (m_ptr) m_ptr->decStrong(this); -} - -template<typename T> -sp<T>& sp<T>::operator = (const sp<T>& other) { - T* otherPtr(other.m_ptr); - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - m_ptr = otherPtr; - return *this; -} - -template<typename T> -sp<T>& sp<T>::operator = (T* other) -{ - if (other) other->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - m_ptr = other; - return *this; -} - -template<typename T> template<typename U> -sp<T>& sp<T>::operator = (const sp<U>& other) -{ - U* otherPtr(other.m_ptr); - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - m_ptr = otherPtr; - return *this; -} - -template<typename T> template<typename U> -sp<T>& sp<T>::operator = (U* other) -{ - if (other) other->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - m_ptr = other; - return *this; -} - -template<typename T> -void sp<T>::force_set(T* other) -{ - other->forceIncStrong(this); - m_ptr = other; -} - -template<typename T> -void sp<T>::clear() -{ - if (m_ptr) { - m_ptr->decStrong(this); - m_ptr = 0; - } -} - -template<typename T> -sp<T>::sp(T* p, weakref_type* refs) - : m_ptr((p && refs->attemptIncStrong(this)) ? p : 0) -{ -} - -template <typename T> -inline TextOutput& operator<<(TextOutput& to, const sp<T>& val) -{ - to << "sp<>(" << val.get() << ")"; - return to; -} - -// --------------------------------------------------------------------------- - -template<typename T> wp<T>::wp(T* other) : m_ptr(other) { @@ -570,7 +425,11 @@ void wp<T>::set_object_and_refs(T* other, weakref_type* refs) template<typename T> sp<T> wp<T>::promote() const { - return sp<T>(m_ptr, m_refs); + sp<T> result; + if (m_ptr && m_refs->attemptIncStrong(&result)) { + result.set_pointer(m_ptr); + } + return result; } template<typename T> @@ -585,10 +444,80 @@ void wp<T>::clear() template <typename T> inline TextOutput& operator<<(TextOutput& to, const wp<T>& val) { - to << "wp<>(" << val.unsafe_get() << ")"; - return to; + return printWeakPointer(to, val.unsafe_get()); } +// --------------------------------------------------------------------------- + +// this class just serves as a namespace so TYPE::moveReferences can stay +// private. + +class ReferenceMover { + // StrongReferenceCast and WeakReferenceCast do the impedance matching + // between the generic (void*) implementation in Refbase and the strongly typed + // template specializations below. + + template <typename TYPE> + struct StrongReferenceCast : public ReferenceConverterBase { + virtual size_t getReferenceTypeSize() const { return sizeof( sp<TYPE> ); } + virtual void* getReferenceBase(void const* p) const { + sp<TYPE> const* sptr(reinterpret_cast<sp<TYPE> const*>(p)); + return static_cast<typename TYPE::basetype *>(sptr->get()); + } + }; + + template <typename TYPE> + struct WeakReferenceCast : public ReferenceConverterBase { + virtual size_t getReferenceTypeSize() const { return sizeof( wp<TYPE> ); } + virtual void* getReferenceBase(void const* p) const { + wp<TYPE> const* sptr(reinterpret_cast<wp<TYPE> const*>(p)); + return static_cast<typename TYPE::basetype *>(sptr->unsafe_get()); + } + }; + +public: + template<typename TYPE> static inline + void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) { + memmove(d, s, n*sizeof(sp<TYPE>)); + StrongReferenceCast<TYPE> caster; + TYPE::moveReferences(d, s, n, caster); + } + template<typename TYPE> static inline + void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) { + memmove(d, s, n*sizeof(wp<TYPE>)); + WeakReferenceCast<TYPE> caster; + TYPE::moveReferences(d, s, n, caster); + } +}; + +// specialization for moving sp<> and wp<> types. +// these are used by the [Sorted|Keyed]Vector<> implementations +// sp<> and wp<> need to be handled specially, because they do not +// have trivial copy operation in the general case (see RefBase.cpp +// when DEBUG ops are enabled), but can be implemented very +// efficiently in most cases. + +template<typename TYPE> inline +void move_forward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template<typename TYPE> inline +void move_backward_type(sp<TYPE>* d, sp<TYPE> const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template<typename TYPE> inline +void move_forward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + +template<typename TYPE> inline +void move_backward_type(wp<TYPE>* d, wp<TYPE> const* s, size_t n) { + ReferenceMover::move_references(d, s, n); +} + + }; // namespace android // --------------------------------------------------------------------------- diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h new file mode 100644 index 0000000000..a8c989749b --- /dev/null +++ b/include/utils/StrongPointer.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2005 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_STRONG_POINTER_H +#define ANDROID_STRONG_POINTER_H + +#include <cutils/atomic.h> + +#include <stdint.h> +#include <sys/types.h> +#include <stdlib.h> + +// --------------------------------------------------------------------------- +namespace android { + +class TextOutput; +TextOutput& printStrongPointer(TextOutput& to, const void* val); + +template<typename T> class wp; + +// --------------------------------------------------------------------------- + +#define COMPARE(_op_) \ +inline bool operator _op_ (const sp<T>& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +inline bool operator _op_ (const T* o) const { \ + return m_ptr _op_ o; \ +} \ +template<typename U> \ +inline bool operator _op_ (const sp<U>& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +template<typename U> \ +inline bool operator _op_ (const U* o) const { \ + return m_ptr _op_ o; \ +} \ +inline bool operator _op_ (const wp<T>& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +template<typename U> \ +inline bool operator _op_ (const wp<U>& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} + +// --------------------------------------------------------------------------- + +template <typename T> +class sp +{ +public: + inline sp() : m_ptr(0) { } + + sp(T* other); + sp(const sp<T>& other); + template<typename U> sp(U* other); + template<typename U> sp(const sp<U>& other); + + ~sp(); + + // Assignment + + sp& operator = (T* other); + sp& operator = (const sp<T>& other); + + template<typename U> sp& operator = (const sp<U>& other); + template<typename U> sp& operator = (U* other); + + //! Special optimization for use by ProcessState (and nobody else). + void force_set(T* other); + + // Reset + + void clear(); + + // Accessors + + inline T& operator* () const { return *m_ptr; } + inline T* operator-> () const { return m_ptr; } + inline T* get() const { return m_ptr; } + + // Operators + + COMPARE(==) + COMPARE(!=) + COMPARE(>) + COMPARE(<) + COMPARE(<=) + COMPARE(>=) + +private: + template<typename Y> friend class sp; + template<typename Y> friend class wp; + void set_pointer(T* ptr); + T* m_ptr; +}; + +#undef COMPARE + +template <typename T> +TextOutput& operator<<(TextOutput& to, const sp<T>& val); + +// --------------------------------------------------------------------------- +// No user serviceable parts below here. + +template<typename T> +sp<T>::sp(T* other) +: m_ptr(other) + { + if (other) other->incStrong(this); + } + +template<typename T> +sp<T>::sp(const sp<T>& other) +: m_ptr(other.m_ptr) + { + if (m_ptr) m_ptr->incStrong(this); + } + +template<typename T> template<typename U> +sp<T>::sp(U* other) : m_ptr(other) +{ + if (other) other->incStrong(this); +} + +template<typename T> template<typename U> +sp<T>::sp(const sp<U>& other) +: m_ptr(other.m_ptr) + { + if (m_ptr) m_ptr->incStrong(this); + } + +template<typename T> +sp<T>::~sp() +{ + if (m_ptr) m_ptr->decStrong(this); +} + +template<typename T> +sp<T>& sp<T>::operator = (const sp<T>& other) { + T* otherPtr(other.m_ptr); + if (otherPtr) otherPtr->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + m_ptr = otherPtr; + return *this; +} + +template<typename T> +sp<T>& sp<T>::operator = (T* other) +{ + if (other) other->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + m_ptr = other; + return *this; +} + +template<typename T> template<typename U> +sp<T>& sp<T>::operator = (const sp<U>& other) +{ + U* otherPtr(other.m_ptr); + if (otherPtr) otherPtr->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + m_ptr = otherPtr; + return *this; +} + +template<typename T> template<typename U> +sp<T>& sp<T>::operator = (U* other) +{ + if (other) other->incStrong(this); + if (m_ptr) m_ptr->decStrong(this); + m_ptr = other; + return *this; +} + +template<typename T> +void sp<T>::force_set(T* other) +{ + other->forceIncStrong(this); + m_ptr = other; +} + +template<typename T> +void sp<T>::clear() +{ + if (m_ptr) { + m_ptr->decStrong(this); + m_ptr = 0; + } +} + +template<typename T> +void sp<T>::set_pointer(T* ptr) { + m_ptr = ptr; +} + +template <typename T> +inline TextOutput& operator<<(TextOutput& to, const sp<T>& val) +{ + return printStrongPointer(to, val.get()); +} + +}; // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_STRONG_POINTER_H diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h index 2ff2749ba3..a1663f30e5 100644 --- a/include/utils/TypeHelpers.h +++ b/include/utils/TypeHelpers.h @@ -37,18 +37,6 @@ template <typename T> struct trait_trivial_move { enum { value = false }; }; template <typename T> struct trait_pointer { enum { value = false }; }; template <typename T> struct trait_pointer<T*> { enum { value = true }; }; -// sp<> can be trivially moved -template <typename T> class sp; -template <typename T> struct trait_trivial_move< sp<T> >{ - enum { value = true }; -}; - -// wp<> can be trivially moved -template <typename T> class wp; -template <typename T> struct trait_trivial_move< wp<T> >{ - enum { value = true }; -}; - template <typename TYPE> struct traits { enum { @@ -217,7 +205,6 @@ void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) { } } - // --------------------------------------------------------------------------- /* diff --git a/include/utils/threads.h b/include/utils/threads.h index 1bcfaede67..41e5766a04 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -527,9 +527,10 @@ private: static int _threadLoop(void* user); const bool mCanCallJava; thread_id_t mThread; - Mutex mLock; + mutable Mutex mLock; Condition mThreadExitedCondition; status_t mStatus; + // note that all accesses of mExitPending and mRunning need to hold mLock volatile bool mExitPending; volatile bool mRunning; sp<Thread> mHoldSelf; diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index e3107d50fd..a80320e475 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -250,11 +250,59 @@ void KeyEvent::initialize(const KeyEvent& from) { // --- PointerCoords --- +float PointerCoords::getAxisValue(int32_t axis) const { + if (axis < 0 || axis > 63) { + return 0; + } + + uint64_t axisBit = 1LL << axis; + if (!(bits & axisBit)) { + return 0; + } + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + return values[index]; +} + +status_t PointerCoords::setAxisValue(int32_t axis, float value) { + if (axis < 0 || axis > 63) { + return NAME_NOT_FOUND; + } + + uint64_t axisBit = 1LL << axis; + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + if (!(bits & axisBit)) { + uint32_t count = __builtin_popcountll(bits); + if (count >= MAX_AXES) { + tooManyAxes(axis); + return NO_MEMORY; + } + bits |= axisBit; + for (uint32_t i = count; i > index; i--) { + values[i] = values[i - 1]; + } + } + values[index] = value; + return OK; +} + +float* PointerCoords::editAxisValue(int32_t axis) { + if (axis < 0 || axis > 63) { + return NULL; + } + + uint64_t axisBit = 1LL << axis; + if (!(bits & axisBit)) { + return NULL; + } + uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); + return &values[index]; +} + #ifdef HAVE_ANDROID_OS status_t PointerCoords::readFromParcel(Parcel* parcel) { - bits = parcel->readInt32(); + bits = parcel->readInt64(); - uint32_t count = __builtin_popcount(bits); + uint32_t count = __builtin_popcountll(bits); if (count > MAX_AXES) { return BAD_VALUE; } @@ -266,9 +314,9 @@ status_t PointerCoords::readFromParcel(Parcel* parcel) { } status_t PointerCoords::writeToParcel(Parcel* parcel) const { - parcel->writeInt32(bits); + parcel->writeInt64(bits); - uint32_t count = __builtin_popcount(bits); + uint32_t count = __builtin_popcountll(bits); for (uint32_t i = 0; i < count; i++) { parcel->writeInt32(values[i]); } diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index 83d955682a..5c57a76f40 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -412,7 +412,8 @@ status_t InputPublisher::publishMotionEvent( // Cache essential information about the motion event to ensure that a malicious consumer // cannot confuse the publisher by modifying the contents of the shared memory buffer while // it is being updated. - if (action == AMOTION_EVENT_ACTION_MOVE) { + if (action == AMOTION_EVENT_ACTION_MOVE + || action == AMOTION_EVENT_ACTION_HOVER_MOVE) { mMotionEventPointerCount = pointerCount; mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount); mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement( diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp index 56bc26fd6d..2ed0e66e1c 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -82,11 +82,11 @@ status_t KeyLayoutMap::load(const String8& filename, KeyLayoutMap** outMap) { return status; } -status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const { +status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const { ssize_t index = mKeys.indexOfKey(scanCode); if (index < 0) { #if DEBUG_MAPPING - LOGD("map: scanCode=%d ~ Failed.", scanCode); + LOGD("mapKey: scanCode=%d ~ Failed.", scanCode); #endif *keyCode = AKEYCODE_UNKNOWN; *flags = 0; @@ -98,12 +98,12 @@ status_t KeyLayoutMap::map(int32_t scanCode, int32_t* keyCode, uint32_t* flags) *flags = k.flags; #if DEBUG_MAPPING - LOGD("map: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags); + LOGD("mapKey: scanCode=%d ~ Result keyCode=%d, flags=0x%08x.", scanCode, *keyCode, *flags); #endif return NO_ERROR; } -status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCodes) const { +status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { const size_t N = mKeys.size(); for (size_t i=0; i<N; i++) { if (mKeys.valueAt(i).keyCode == keyCode) { @@ -113,6 +113,25 @@ status_t KeyLayoutMap::findScanCodes(int32_t keyCode, Vector<int32_t>* outScanCo return NO_ERROR; } +status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) 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); + +#if DEBUG_MAPPING + LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis); +#endif + return NO_ERROR; +} + + // --- KeyLayoutMap::Parser --- KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : @@ -137,6 +156,10 @@ status_t KeyLayoutMap::Parser::parse() { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; + } else if (keywordToken == "axis") { + mTokenizer->skipDelimiters(WHITESPACE); + status_t status = parseAxis(); + if (status) return status; } else { LOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), keywordToken.string()); @@ -162,12 +185,12 @@ status_t KeyLayoutMap::Parser::parseKey() { char* end; int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); if (*end) { - LOGE("%s: Expected scan code number, got '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(scanCode) >= 0) { - LOGE("%s: Duplicate entry for scan code '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(), scanCodeToken.string()); return BAD_VALUE; } @@ -189,12 +212,12 @@ status_t KeyLayoutMap::Parser::parseKey() { String8 flagToken = mTokenizer->nextToken(WHITESPACE); uint32_t flag = getKeyFlagByLabel(flagToken.string()); if (!flag) { - LOGE("%s: Expected flag label, got '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } if (flags & flag) { - LOGE("%s: Duplicate flag '%s'.", mTokenizer->getLocation().string(), + LOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), flagToken.string()); return BAD_VALUE; } @@ -211,4 +234,35 @@ status_t KeyLayoutMap::Parser::parseKey() { return NO_ERROR; } +status_t KeyLayoutMap::Parser::parseAxis() { + String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); + char* end; + int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); + if (*end) { + LOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), + scanCodeToken.string()); + return BAD_VALUE; + } + if (mMap->mAxes.indexOfKey(scanCode) >= 0) { + LOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), + scanCodeToken.string()); + return BAD_VALUE; + } + + 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; + } + +#if DEBUG_PARSER + LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis); +#endif + mMap->mAxes.add(scanCode, axis); + return NO_ERROR; +} + }; diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index 6faa600e6e..8b6300a1ee 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -217,7 +217,7 @@ status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFil return NAME_NOT_FOUND; } -static int lookupLabel(const char* literal, const KeycodeLabel *list) { +static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { while (list->literal) { if (strcmp(literal, list->literal) == 0) { return list->value; @@ -227,12 +227,30 @@ static int lookupLabel(const char* literal, const KeycodeLabel *list) { return list->value; } +static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { + while (list->literal) { + if (list->value == value) { + return list->literal; + } + list++; + } + return NULL; +} + int32_t getKeyCodeByLabel(const char* label) { - return int32_t(lookupLabel(label, KEYCODES)); + return int32_t(lookupValueByLabel(label, KEYCODES)); } uint32_t getKeyFlagByLabel(const char* label) { - return uint32_t(lookupLabel(label, FLAGS)); + return uint32_t(lookupValueByLabel(label, FLAGS)); +} + +int32_t getAxisByLabel(const char* label) { + return int32_t(lookupValueByLabel(label, AXES)); +} + +const char* getAxisLabel(int32_t axisId) { + return lookupLabelByValue(axisId, AXES); } static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp index 7b15c381e6..b77489e158 100644 --- a/libs/ui/tests/InputEvent_test.cpp +++ b/libs/ui/tests/InputEvent_test.cpp @@ -18,6 +18,9 @@ #include <gtest/gtest.h> #include <binder/Parcel.h> +#include <math.h> +#include <SkMatrix.h> + namespace android { class BaseTest : public testing::Test { @@ -35,7 +38,7 @@ TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { PointerCoords coords; coords.clear(); - ASSERT_EQ(0U, coords.bits); + ASSERT_EQ(0ULL, coords.bits); } TEST_F(PointerCoordsTest, AxisValues) { @@ -54,7 +57,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set first axis. ASSERT_EQ(OK, coords.setAxisValue(1, 5)); - ASSERT_EQ(0x00000002U, coords.bits); + ASSERT_EQ(0x00000002ULL, coords.bits); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(0, coords.getAxisValue(0)) @@ -64,7 +67,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with a higher id than all others. (appending value at the end) ASSERT_EQ(OK, coords.setAxisValue(3, 2)); - ASSERT_EQ(0x0000000aU, coords.bits); + ASSERT_EQ(0x0000000aULL, coords.bits); ASSERT_EQ(5, coords.values[0]); ASSERT_EQ(2, coords.values[1]); @@ -79,7 +82,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with an id lower than all others. (prepending value at beginning) ASSERT_EQ(OK, coords.setAxisValue(0, 4)); - ASSERT_EQ(0x0000000bU, coords.bits); + ASSERT_EQ(0x0000000bULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(5, coords.values[1]); ASSERT_EQ(2, coords.values[2]); @@ -104,7 +107,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an axis with an id between the others. (inserting value in the middle) ASSERT_EQ(OK, coords.setAxisValue(2, 1)); - ASSERT_EQ(0x0000000fU, coords.bits); + ASSERT_EQ(0x0000000fULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(7, coords.values[1]); ASSERT_EQ(1, coords.values[2]); @@ -121,7 +124,7 @@ TEST_F(PointerCoordsTest, AxisValues) { // Set an existing axis value in place. ASSERT_EQ(OK, coords.setAxisValue(1, 6)); - ASSERT_EQ(0x0000000fU, coords.bits); + ASSERT_EQ(0x0000000fULL, coords.bits); ASSERT_EQ(4, coords.values[0]); ASSERT_EQ(6, coords.values[1]); ASSERT_EQ(1, coords.values[2]); @@ -140,15 +143,15 @@ TEST_F(PointerCoordsTest, AxisValues) { for (size_t axis = 4; axis < PointerCoords::MAX_AXES; axis++) { ASSERT_EQ(OK, coords.setAxisValue(axis, axis)); } - ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcount(coords.bits)); + ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); // Try to set one more axis beyond maximum number. // Ensure bits are unchanged. ASSERT_EQ(NO_MEMORY, coords.setAxisValue(PointerCoords::MAX_AXES, 100)); - ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcount(coords.bits)); + ASSERT_EQ(PointerCoords::MAX_AXES, __builtin_popcountll(coords.bits)); } -TEST_F(PointerCoordsTest, ReadAndWriteParcel) { +TEST_F(PointerCoordsTest, Parcel) { Parcel parcel; PointerCoords inCoords; @@ -160,7 +163,7 @@ TEST_F(PointerCoordsTest, ReadAndWriteParcel) { parcel.setDataPosition(0); outCoords.readFromParcel(&parcel); - ASSERT_EQ(0U, outCoords.bits); + ASSERT_EQ(0ULL, outCoords.bits); // Round trip with some values. parcel.freeData(); @@ -213,16 +216,22 @@ TEST_F(KeyEventTest, Properties) { // --- MotionEventTest --- class MotionEventTest : public BaseTest { +protected: + static const nsecs_t ARBITRARY_DOWN_TIME; + static const nsecs_t ARBITRARY_EVENT_TIME; + static const float X_OFFSET; + static const float Y_OFFSET; + + void initializeEventWithHistory(MotionEvent* event); + void assertEqualsEventWithHistory(const MotionEvent* event); }; -TEST_F(MotionEventTest, Properties) { - MotionEvent event; +const nsecs_t MotionEventTest::ARBITRARY_DOWN_TIME = 1; +const nsecs_t MotionEventTest::ARBITRARY_EVENT_TIME = 2; +const float MotionEventTest::X_OFFSET = 1.0f; +const float MotionEventTest::Y_OFFSET = 1.1f; - // Initialize, add samples and get properties. - const nsecs_t ARBITRARY_DOWN_TIME = 1; - const nsecs_t ARBITRARY_EVENT_TIME = 2; - const float X_OFFSET = 1.0f; - const float Y_OFFSET = 1.1f; +void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { int32_t pointerIds[] = { 1, 2 }; PointerCoords pointerCoords[2]; pointerCoords[0].clear(); @@ -245,7 +254,7 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); - event.initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, + event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, @@ -270,7 +279,7 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 126); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 127); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 128); - event.addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); + event->addSample(ARBITRARY_EVENT_TIME + 1, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 210); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 211); @@ -290,128 +299,284 @@ TEST_F(MotionEventTest, Properties) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 226); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 227); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 228); - event.addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); - - ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event.getType()); - ASSERT_EQ(2, event.getDeviceId()); - ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event.getSource()); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event.getAction()); - ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event.getFlags()); - ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event.getEdgeFlags()); - ASSERT_EQ(AMETA_ALT_ON, event.getMetaState()); - ASSERT_EQ(X_OFFSET, event.getXOffset()); - ASSERT_EQ(Y_OFFSET, event.getYOffset()); - ASSERT_EQ(2.0f, event.getXPrecision()); - ASSERT_EQ(2.1f, event.getYPrecision()); - ASSERT_EQ(ARBITRARY_DOWN_TIME, event.getDownTime()); - - ASSERT_EQ(2U, event.getPointerCount()); - ASSERT_EQ(1, event.getPointerId(0)); - ASSERT_EQ(2, event.getPointerId(1)); - - ASSERT_EQ(2U, event.getHistorySize()); - - // Get data. - ASSERT_EQ(ARBITRARY_EVENT_TIME, event.getHistoricalEventTime(0)); - ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event.getHistoricalEventTime(1)); - ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event.getEventTime()); + event->addSample(ARBITRARY_EVENT_TIME + 2, pointerCoords); +} - ASSERT_EQ(11, event.getHistoricalRawPointerCoords(0, 0)-> +void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { + // Check properties. + ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType()); + ASSERT_EQ(2, event->getDeviceId()); + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource()); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction()); + ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags()); + ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags()); + ASSERT_EQ(AMETA_ALT_ON, event->getMetaState()); + ASSERT_EQ(X_OFFSET, event->getXOffset()); + ASSERT_EQ(Y_OFFSET, event->getYOffset()); + ASSERT_EQ(2.0f, event->getXPrecision()); + ASSERT_EQ(2.1f, event->getYPrecision()); + ASSERT_EQ(ARBITRARY_DOWN_TIME, event->getDownTime()); + + ASSERT_EQ(2U, event->getPointerCount()); + ASSERT_EQ(1, event->getPointerId(0)); + ASSERT_EQ(2, event->getPointerId(1)); + + ASSERT_EQ(2U, event->getHistorySize()); + + // Check data. + ASSERT_EQ(ARBITRARY_EVENT_TIME, event->getHistoricalEventTime(0)); + ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1)); + ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime()); + + ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(21, event.getHistoricalRawPointerCoords(1, 0)-> + ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(111, event.getHistoricalRawPointerCoords(0, 1)-> + ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(121, event.getHistoricalRawPointerCoords(1, 1)-> + ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(211, event.getRawPointerCoords(0)-> + ASSERT_EQ(211, event->getRawPointerCoords(0)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(221, event.getRawPointerCoords(1)-> + ASSERT_EQ(221, event->getRawPointerCoords(1)-> getAxisValue(AMOTION_EVENT_AXIS_Y)); - ASSERT_EQ(11, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); - ASSERT_EQ(21, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); - ASSERT_EQ(111, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); - ASSERT_EQ(121, event.getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); - ASSERT_EQ(211, event.getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); - ASSERT_EQ(221, event.getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); - - ASSERT_EQ(10, event.getHistoricalRawX(0, 0)); - ASSERT_EQ(20, event.getHistoricalRawX(1, 0)); - ASSERT_EQ(110, event.getHistoricalRawX(0, 1)); - ASSERT_EQ(120, event.getHistoricalRawX(1, 1)); - ASSERT_EQ(210, event.getRawX(0)); - ASSERT_EQ(220, event.getRawX(1)); - - ASSERT_EQ(11, event.getHistoricalRawY(0, 0)); - ASSERT_EQ(21, event.getHistoricalRawY(1, 0)); - ASSERT_EQ(111, event.getHistoricalRawY(0, 1)); - ASSERT_EQ(121, event.getHistoricalRawY(1, 1)); - ASSERT_EQ(211, event.getRawY(0)); - ASSERT_EQ(221, event.getRawY(1)); - - ASSERT_EQ(X_OFFSET + 10, event.getHistoricalX(0, 0)); - ASSERT_EQ(X_OFFSET + 20, event.getHistoricalX(1, 0)); - ASSERT_EQ(X_OFFSET + 110, event.getHistoricalX(0, 1)); - ASSERT_EQ(X_OFFSET + 120, event.getHistoricalX(1, 1)); - ASSERT_EQ(X_OFFSET + 210, event.getX(0)); - ASSERT_EQ(X_OFFSET + 220, event.getX(1)); - - ASSERT_EQ(Y_OFFSET + 11, event.getHistoricalY(0, 0)); - ASSERT_EQ(Y_OFFSET + 21, event.getHistoricalY(1, 0)); - ASSERT_EQ(Y_OFFSET + 111, event.getHistoricalY(0, 1)); - ASSERT_EQ(Y_OFFSET + 121, event.getHistoricalY(1, 1)); - ASSERT_EQ(Y_OFFSET + 211, event.getY(0)); - ASSERT_EQ(Y_OFFSET + 221, event.getY(1)); - - ASSERT_EQ(12, event.getHistoricalPressure(0, 0)); - ASSERT_EQ(22, event.getHistoricalPressure(1, 0)); - ASSERT_EQ(112, event.getHistoricalPressure(0, 1)); - ASSERT_EQ(122, event.getHistoricalPressure(1, 1)); - ASSERT_EQ(212, event.getPressure(0)); - ASSERT_EQ(222, event.getPressure(1)); + ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0)); + ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0)); + ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1)); + ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1)); + ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0)); + ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1)); + + ASSERT_EQ(10, event->getHistoricalRawX(0, 0)); + ASSERT_EQ(20, event->getHistoricalRawX(1, 0)); + ASSERT_EQ(110, event->getHistoricalRawX(0, 1)); + ASSERT_EQ(120, event->getHistoricalRawX(1, 1)); + ASSERT_EQ(210, event->getRawX(0)); + ASSERT_EQ(220, event->getRawX(1)); + + ASSERT_EQ(11, event->getHistoricalRawY(0, 0)); + ASSERT_EQ(21, event->getHistoricalRawY(1, 0)); + ASSERT_EQ(111, event->getHistoricalRawY(0, 1)); + ASSERT_EQ(121, event->getHistoricalRawY(1, 1)); + ASSERT_EQ(211, event->getRawY(0)); + ASSERT_EQ(221, event->getRawY(1)); + + ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0)); + ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0)); + ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1)); + ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1)); + ASSERT_EQ(X_OFFSET + 210, event->getX(0)); + ASSERT_EQ(X_OFFSET + 220, event->getX(1)); + + ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0)); + ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0)); + ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1)); + ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1)); + ASSERT_EQ(Y_OFFSET + 211, event->getY(0)); + ASSERT_EQ(Y_OFFSET + 221, event->getY(1)); + + ASSERT_EQ(12, event->getHistoricalPressure(0, 0)); + ASSERT_EQ(22, event->getHistoricalPressure(1, 0)); + ASSERT_EQ(112, event->getHistoricalPressure(0, 1)); + ASSERT_EQ(122, event->getHistoricalPressure(1, 1)); + ASSERT_EQ(212, event->getPressure(0)); + ASSERT_EQ(222, event->getPressure(1)); + + ASSERT_EQ(13, event->getHistoricalSize(0, 0)); + ASSERT_EQ(23, event->getHistoricalSize(1, 0)); + ASSERT_EQ(113, event->getHistoricalSize(0, 1)); + ASSERT_EQ(123, event->getHistoricalSize(1, 1)); + ASSERT_EQ(213, event->getSize(0)); + ASSERT_EQ(223, event->getSize(1)); + + ASSERT_EQ(14, event->getHistoricalTouchMajor(0, 0)); + ASSERT_EQ(24, event->getHistoricalTouchMajor(1, 0)); + ASSERT_EQ(114, event->getHistoricalTouchMajor(0, 1)); + ASSERT_EQ(124, event->getHistoricalTouchMajor(1, 1)); + ASSERT_EQ(214, event->getTouchMajor(0)); + ASSERT_EQ(224, event->getTouchMajor(1)); + + ASSERT_EQ(15, event->getHistoricalTouchMinor(0, 0)); + ASSERT_EQ(25, event->getHistoricalTouchMinor(1, 0)); + ASSERT_EQ(115, event->getHistoricalTouchMinor(0, 1)); + ASSERT_EQ(125, event->getHistoricalTouchMinor(1, 1)); + ASSERT_EQ(215, event->getTouchMinor(0)); + ASSERT_EQ(225, event->getTouchMinor(1)); + + ASSERT_EQ(16, event->getHistoricalToolMajor(0, 0)); + ASSERT_EQ(26, event->getHistoricalToolMajor(1, 0)); + ASSERT_EQ(116, event->getHistoricalToolMajor(0, 1)); + ASSERT_EQ(126, event->getHistoricalToolMajor(1, 1)); + ASSERT_EQ(216, event->getToolMajor(0)); + ASSERT_EQ(226, event->getToolMajor(1)); + + ASSERT_EQ(17, event->getHistoricalToolMinor(0, 0)); + ASSERT_EQ(27, event->getHistoricalToolMinor(1, 0)); + ASSERT_EQ(117, event->getHistoricalToolMinor(0, 1)); + ASSERT_EQ(127, event->getHistoricalToolMinor(1, 1)); + ASSERT_EQ(217, event->getToolMinor(0)); + ASSERT_EQ(227, event->getToolMinor(1)); + + ASSERT_EQ(18, event->getHistoricalOrientation(0, 0)); + ASSERT_EQ(28, event->getHistoricalOrientation(1, 0)); + ASSERT_EQ(118, event->getHistoricalOrientation(0, 1)); + ASSERT_EQ(128, event->getHistoricalOrientation(1, 1)); + ASSERT_EQ(218, event->getOrientation(0)); + ASSERT_EQ(228, event->getOrientation(1)); +} + +TEST_F(MotionEventTest, Properties) { + MotionEvent event; + + // Initialize, add samples and check properties. + initializeEventWithHistory(&event); + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); + + // Set source. + event.setSource(AINPUT_SOURCE_JOYSTICK); + ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource()); + + // Set action. + event.setAction(AMOTION_EVENT_ACTION_CANCEL); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction()); + + // Set meta state. + event.setMetaState(AMETA_CTRL_ON); + ASSERT_EQ(AMETA_CTRL_ON, event.getMetaState()); +} + +TEST_F(MotionEventTest, CopyFrom_KeepHistory) { + MotionEvent event; + initializeEventWithHistory(&event); + + MotionEvent copy; + copy.copyFrom(&event, true /*keepHistory*/); + + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&event)); +} + +TEST_F(MotionEventTest, CopyFrom_DoNotKeepHistory) { + MotionEvent event; + initializeEventWithHistory(&event); + + MotionEvent copy; + copy.copyFrom(&event, false /*keepHistory*/); + + ASSERT_EQ(event.getPointerCount(), copy.getPointerCount()); + ASSERT_EQ(0U, copy.getHistorySize()); + + ASSERT_EQ(event.getPointerId(0), copy.getPointerId(0)); + ASSERT_EQ(event.getPointerId(1), copy.getPointerId(1)); + + ASSERT_EQ(event.getEventTime(), copy.getEventTime()); + + ASSERT_EQ(event.getX(0), copy.getX(0)); +} + +TEST_F(MotionEventTest, OffsetLocation) { + MotionEvent event; + initializeEventWithHistory(&event); + + event.offsetLocation(5.0f, -2.0f); + + ASSERT_EQ(X_OFFSET + 5.0f, event.getXOffset()); + ASSERT_EQ(Y_OFFSET - 2.0f, event.getYOffset()); +} + +TEST_F(MotionEventTest, Scale) { + MotionEvent event; + initializeEventWithHistory(&event); - ASSERT_EQ(13, event.getHistoricalSize(0, 0)); - ASSERT_EQ(23, event.getHistoricalSize(1, 0)); - ASSERT_EQ(113, event.getHistoricalSize(0, 1)); - ASSERT_EQ(123, event.getHistoricalSize(1, 1)); + event.scale(2.0f); + + ASSERT_EQ(X_OFFSET * 2, event.getXOffset()); + ASSERT_EQ(Y_OFFSET * 2, event.getYOffset()); + + ASSERT_EQ(210 * 2, event.getRawX(0)); + ASSERT_EQ(211 * 2, event.getRawY(0)); + ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0)); + ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0)); + ASSERT_EQ(212, event.getPressure(0)); ASSERT_EQ(213, event.getSize(0)); - ASSERT_EQ(223, event.getSize(1)); - - ASSERT_EQ(14, event.getHistoricalTouchMajor(0, 0)); - ASSERT_EQ(24, event.getHistoricalTouchMajor(1, 0)); - ASSERT_EQ(114, event.getHistoricalTouchMajor(0, 1)); - ASSERT_EQ(124, event.getHistoricalTouchMajor(1, 1)); - ASSERT_EQ(214, event.getTouchMajor(0)); - ASSERT_EQ(224, event.getTouchMajor(1)); - - ASSERT_EQ(15, event.getHistoricalTouchMinor(0, 0)); - ASSERT_EQ(25, event.getHistoricalTouchMinor(1, 0)); - ASSERT_EQ(115, event.getHistoricalTouchMinor(0, 1)); - ASSERT_EQ(125, event.getHistoricalTouchMinor(1, 1)); - ASSERT_EQ(215, event.getTouchMinor(0)); - ASSERT_EQ(225, event.getTouchMinor(1)); - - ASSERT_EQ(16, event.getHistoricalToolMajor(0, 0)); - ASSERT_EQ(26, event.getHistoricalToolMajor(1, 0)); - ASSERT_EQ(116, event.getHistoricalToolMajor(0, 1)); - ASSERT_EQ(126, event.getHistoricalToolMajor(1, 1)); - ASSERT_EQ(216, event.getToolMajor(0)); - ASSERT_EQ(226, event.getToolMajor(1)); - - ASSERT_EQ(17, event.getHistoricalToolMinor(0, 0)); - ASSERT_EQ(27, event.getHistoricalToolMinor(1, 0)); - ASSERT_EQ(117, event.getHistoricalToolMinor(0, 1)); - ASSERT_EQ(127, event.getHistoricalToolMinor(1, 1)); - ASSERT_EQ(217, event.getToolMinor(0)); - ASSERT_EQ(227, event.getToolMinor(1)); - - ASSERT_EQ(18, event.getHistoricalOrientation(0, 0)); - ASSERT_EQ(28, event.getHistoricalOrientation(1, 0)); - ASSERT_EQ(118, event.getHistoricalOrientation(0, 1)); - ASSERT_EQ(128, event.getHistoricalOrientation(1, 1)); + ASSERT_EQ(214 * 2, event.getTouchMajor(0)); + ASSERT_EQ(215 * 2, event.getTouchMinor(0)); + ASSERT_EQ(216 * 2, event.getToolMajor(0)); + ASSERT_EQ(217 * 2, event.getToolMinor(0)); ASSERT_EQ(218, event.getOrientation(0)); - ASSERT_EQ(228, event.getOrientation(1)); +} + +TEST_F(MotionEventTest, Parcel) { + Parcel parcel; + + MotionEvent inEvent; + initializeEventWithHistory(&inEvent); + MotionEvent outEvent; + + // Round trip. + inEvent.writeToParcel(&parcel); + parcel.setDataPosition(0); + outEvent.readFromParcel(&parcel); + + ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent)); +} + +TEST_F(MotionEventTest, Transform) { + // Generate some points on a circle. + // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle + // of ARC * i degrees clockwise relative to the Y axis. + // The geometrical representation is irrelevant to the test, it's just easy to generate + // and check rotation. We set the orientation to the same angle. + // Coordinate system: down is increasing Y, right is increasing X. + const float PI_180 = float(M_PI / 180); + const float RADIUS = 10; + const float ARC = 36; + const float ROTATION = ARC * 2; + + const size_t pointerCount = 11; + int pointerIds[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + float angle = float(i * ARC * PI_180); + pointerIds[i] = i; + pointerCoords[i].clear(); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle); + } + MotionEvent event; + event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, + 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords); + float originalRawX = 0 + 3; + float originalRawY = -RADIUS + 2; + + // Check original raw X and Y assumption. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); + + // Now translate the motion event so the circle's origin is at (0,0). + event.offsetLocation(-3, -2); + + // Offsetting the location should preserve the raw X and Y of the first point. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); + + // Apply a rotation about the origin by ROTATION degrees clockwise. + SkMatrix matrix; + matrix.setRotate(ROTATION); + event.transform(&matrix); + + // Check the points. + for (size_t i = 0; i < pointerCount; i++) { + float angle = float((i * ARC + ROTATION) * PI_180); + ASSERT_NEAR(sinf(angle) * RADIUS, event.getX(i), 0.001); + ASSERT_NEAR(-cosf(angle) * RADIUS, event.getY(i), 0.001); + ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); + } + + // Applying the transformation should preserve the raw X and Y of the first point. + ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); + ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); } } // namespace android diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index 0bd1af4ebf..0fd404d66c 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -20,9 +20,9 @@ #include <utils/Atomic.h> #include <utils/CallStack.h> -#include <utils/KeyedVector.h> #include <utils/Log.h> #include <utils/threads.h> +#include <utils/TextOutput.h> #include <stdlib.h> #include <stdio.h> @@ -34,6 +34,7 @@ // compile with refcounting debugging enabled #define DEBUG_REFS 0 +#define DEBUG_REFS_FATAL_SANITY_CHECKS 0 #define DEBUG_REFS_ENABLED_BY_DEFAULT 1 #define DEBUG_REFS_CALLSTACK_ENABLED 1 @@ -69,8 +70,10 @@ public: void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } + void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } + void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { } void printRefs() const { } void trackMe(bool, bool) { } @@ -86,39 +89,73 @@ public: , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { - //LOGI("NEW weakref_impl %p for RefBase %p", this, base); } ~weakref_impl() { - LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!"); - LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!"); + bool dumpStack = false; + if (!mRetain && mStrongRefs != NULL) { + dumpStack = true; +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("Strong references remain!"); +#else + LOGE("Strong references remain!"); +#endif + } + + if (!mRetain && mWeakRefs != NULL) { + dumpStack = true; +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("Weak references remain!"); +#else + LOGE("Weak references remain!"); +#endif + } + + if (dumpStack) { + CallStack stack; + stack.update(); + stack.dump(); + } } - void addStrongRef(const void* id) - { + void addStrongRef(const void* id) { + //LOGD_IF(mTrackEnabled, + // "addStrongRef: RefBase=%p, id=%p", mBase, id); addRef(&mStrongRefs, id, mStrong); } - void removeStrongRef(const void* id) - { - if (!mRetain) + void removeStrongRef(const void* id) { + //LOGD_IF(mTrackEnabled, + // "removeStrongRef: RefBase=%p, id=%p", mBase, id); + if (!mRetain) { removeRef(&mStrongRefs, id); - else + } else { addRef(&mStrongRefs, id, -mStrong); + } } - void addWeakRef(const void* id) - { + void renameStrongRefId(const void* old_id, const void* new_id) { + //LOGD_IF(mTrackEnabled, + // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p", + // mBase, old_id, new_id); + renameRefsId(mStrongRefs, old_id, new_id); + } + + void addWeakRef(const void* id) { addRef(&mWeakRefs, id, mWeak); } - void removeWeakRef(const void* id) - { - if (!mRetain) + void removeWeakRef(const void* id) { + if (!mRetain) { removeRef(&mWeakRefs, id); - else + } else { addRef(&mWeakRefs, id, -mWeak); + } + } + + void renameWeakRefId(const void* old_id, const void* new_id) { + renameRefsId(mWeakRefs, old_id, new_id); } void trackMe(bool track, bool retain) @@ -132,8 +169,7 @@ public: String8 text; { - AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex); - + Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex); char buf[128]; sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); @@ -172,6 +208,7 @@ private: { if (mTrackEnabled) { AutoMutex _l(mMutex); + ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the // update. Positive value means we increment, negative--we @@ -181,7 +218,6 @@ private: #if DEBUG_REFS_CALLSTACK_ENABLED ref->stack.update(2); #endif - ref->next = *refs; *refs = ref; } @@ -199,13 +235,37 @@ private: delete ref; return; } - refs = &ref->next; ref = *refs; } - - LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!", - id, mBase, this); + +#if DEBUG_REFS_FATAL_SANITY_CHECKS + LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p" + "(weakref_type %p) that doesn't exist!", + id, mBase, this); +#endif + + LOGE("RefBase: removing id %p on RefBase %p" + "(weakref_type %p) that doesn't exist!", + id, mBase, this); + + CallStack stack; + stack.update(); + stack.dump(); + } + } + + void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) + { + if (mTrackEnabled) { + AutoMutex _l(mMutex); + ref_entry* ref = r; + while (ref != NULL) { + if (ref->id == old_id) { + ref->id = new_id; + } + ref = ref->next; + } } } @@ -235,44 +295,6 @@ private: // on removeref that match the address ones. bool mRetain; -#if 0 - void addRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - if (i >= 0) { - ++(refs->editValueAt(i)); - } else { - i = refs->add(id, 1); - } - } - - void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id) - { - AutoMutex _l(mMutex); - ssize_t i = refs->indexOfKey(id); - LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id); - if (i >= 0) { - int32_t val = --(refs->editValueAt(i)); - if (val == 0) { - refs->removeItemsAt(i); - } - } - } - - void printRefs(const KeyedVector<const void*, int32_t>& refs) - { - const size_t N=refs.size(); - for (size_t i=0; i<N; i++) { - printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i)); - } - } - - mutable Mutex mMutex; - KeyedVector<const void*, int32_t> mStrongRefs; - KeyedVector<const void*, int32_t> mWeakRefs; -#endif - #endif }; @@ -281,7 +303,6 @@ private: void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; - refs->addWeakRef(id); refs->incWeak(id); refs->addStrongRef(id); @@ -313,14 +334,12 @@ void RefBase::decStrong(const void* id) const delete this; } } - refs->removeWeakRef(id); refs->decWeak(id); } void RefBase::forceIncStrong(const void* id) const { weakref_impl* const refs = mRefs; - refs->addWeakRef(id); refs->incWeak(id); refs->addStrongRef(id); @@ -372,7 +391,7 @@ void RefBase::weakref_type::decWeak(const void* id) if (impl->mStrong == INITIAL_STRONG_VALUE) delete impl->mBase; else { -// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); + // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { @@ -432,7 +451,6 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id) } } - impl->addWeakRef(id); impl->addStrongRef(id); #if PRINT_REFS @@ -450,7 +468,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id) bool RefBase::weakref_type::attemptIncWeak(const void* id) { weakref_impl* const impl = static_cast<weakref_impl*>(this); - + int32_t curCount = impl->mWeak; LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", this); @@ -497,14 +515,11 @@ RefBase::weakref_type* RefBase::getWeakRefs() const RefBase::RefBase() : mRefs(new weakref_impl(this)) { -// LOGV("Creating refs %p with RefBase %p\n", mRefs, this); } RefBase::~RefBase() { -// LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs); if (mRefs->mWeak == 0) { -// LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this); delete mRefs; } } @@ -530,5 +545,37 @@ bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) void RefBase::onLastWeakRef(const void* /*id*/) { } - + +// --------------------------------------------------------------------------- + +void RefBase::moveReferences(void* dst, void const* src, size_t n, + const ReferenceConverterBase& caster) +{ +#if DEBUG_REFS + const size_t itemSize = caster.getReferenceTypeSize(); + for (size_t i=0 ; i<n ; i++) { + void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize); + void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize); + RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d))); + ref->mRefs->renameStrongRefId(s, d); + ref->mRefs->renameWeakRefId(s, d); + } +#endif +} + +// --------------------------------------------------------------------------- + +TextOutput& printStrongPointer(TextOutput& to, const void* val) +{ + to << "sp<>(" << val << ")"; + return to; +} + +TextOutput& printWeakPointer(TextOutput& to, const void* val) +{ + to << "wp<>(" << val << ")"; + return to; +} + + }; // namespace android diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index 35dcbcb64d..8b5da0e580 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -675,6 +675,9 @@ Thread::Thread(bool canCallJava) mLock("Thread::mLock"), mStatus(NO_ERROR), mExitPending(false), mRunning(false) +#ifdef HAVE_ANDROID_OS + , mTid(-1) +#endif { } @@ -715,6 +718,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) res = androidCreateRawThreadEtc(_threadLoop, this, name, priority, stack, &mThread); } + // The new thread wakes up at _threadLoop, but immediately blocks on mLock if (res == false) { mStatus = UNKNOWN_ERROR; // something happened! @@ -730,11 +734,19 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return NO_ERROR; + + // Exiting scope of mLock is a memory barrier and allows new thread to run } int Thread::_threadLoop(void* user) { Thread* const self = static_cast<Thread*>(user); + + // force a memory barrier before reading any fields, in particular mHoldSelf + { + Mutex::Autolock _l(self->mLock); + } + sp<Thread> strong(self->mHoldSelf); wp<Thread> weak(strong); self->mHoldSelf.clear(); @@ -753,7 +765,7 @@ int Thread::_threadLoop(void* user) self->mStatus = self->readyToRun(); result = (self->mStatus == NO_ERROR); - if (result && !self->mExitPending) { + if (result && !self->exitPending()) { // Binder threads (and maybe others) rely on threadLoop // running at least once after a successful ::readyToRun() // (unless, of course, the thread has already been asked to exit @@ -770,18 +782,21 @@ int Thread::_threadLoop(void* user) result = self->threadLoop(); } + // establish a scope for mLock + { + Mutex::Autolock _l(self->mLock); if (result == false || self->mExitPending) { self->mExitPending = true; - self->mLock.lock(); self->mRunning = false; // clear thread ID so that requestExitAndWait() does not exit if // called by a new thread using the same thread ID as this one. self->mThread = thread_id_t(-1); + // note that interested observers blocked in requestExitAndWait are + // awoken by broadcast, but blocked on mLock until break exits scope self->mThreadExitedCondition.broadcast(); - self->mThread = thread_id_t(-1); // thread id could be reused - self->mLock.unlock(); break; } + } // Release our strong reference, to let a chance to the thread // to die a peaceful death. @@ -795,6 +810,7 @@ int Thread::_threadLoop(void* user) void Thread::requestExit() { + Mutex::Autolock _l(mLock); mExitPending = true; } @@ -815,6 +831,8 @@ status_t Thread::requestExitAndWait() while (mRunning == true) { mThreadExitedCondition.wait(mLock); } + // This next line is probably not needed any more, but is being left for + // historical reference. Note that each interested party will clear flag. mExitPending = false; return mStatus; @@ -822,6 +840,7 @@ status_t Thread::requestExitAndWait() bool Thread::exitPending() const { + Mutex::Autolock _l(mLock); return mExitPending; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0f7d6392e4..57af001fab 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -341,6 +341,45 @@ void Layer::onDraw(const Region& clip) const drawWithOpenGL(clip, tex); } +// As documented in libhardware header, formats in the range +// 0x100 - 0x1FF are specific to the HAL implementation, and +// are known to have no alpha channel +// TODO: move definition for device-specific range into +// hardware.h, instead of using hard-coded values here. +#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) + +bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const +{ + // If buffers where set with eOpaque flag, all buffers are known to + // be opaque without having to check their actual format + if (mNeedsBlending && buffer != NULL) { + PixelFormat format = buffer->getPixelFormat(); + + if (HARDWARE_IS_DEVICE_FORMAT(format)) { + return false; + } + + PixelFormatInfo info; + status_t err = getPixelFormatInfo(format, &info); + if (!err && info.h_alpha <= info.l_alpha) { + return false; + } + } + + // Return opacity as determined from flags and format options + // passed to setBuffers() + return mNeedsBlending; +} + +bool Layer::needsBlending() const +{ + if (mBufferManager.hasActiveBuffer()) { + return needsBlending(mBufferManager.getActiveBuffer()); + } + + return mNeedsBlending; +} + bool Layer::needsFiltering() const { if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { @@ -588,6 +627,9 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // we retired a buffer, which becomes the new front buffer const bool noActiveBuffer = !mBufferManager.hasActiveBuffer(); + const bool activeBlending = + noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer()); + if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) { LOGE("retireAndLock() buffer index (%d) out of range", int(buf)); mPostedDirtyRegion.clear(); @@ -602,6 +644,12 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) sp<GraphicBuffer> newFrontBuffer(getBuffer(buf)); if (newFrontBuffer != NULL) { + if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) { + // new buffer has different opacity than previous active buffer, need + // to recompute visible regions accordingly + recomputeVisibleRegions = true; + } + // get the dirty region // compute the posted region const Region dirty(lcblk->getDirtyRegion(buf)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2b3841466d..bccc9004fd 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -75,7 +75,8 @@ public: virtual uint32_t doTransaction(uint32_t transactionFlags); virtual void lockPageFlip(bool& recomputeVisibleRegions); virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); - virtual bool needsBlending() const { return mNeedsBlending; } + virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const; + virtual bool needsBlending() const; virtual bool needsDithering() const { return mNeedsDithering; } virtual bool needsFiltering() const; virtual bool isSecure() const { return mSecure; } |