diff options
Diffstat (limited to 'include/utils')
-rw-r--r-- | include/utils/BitSet.h | 10 | ||||
-rw-r--r-- | include/utils/GenerationCache.h | 255 | ||||
-rw-r--r-- | include/utils/ResourceTypes.h | 67 | ||||
-rw-r--r-- | include/utils/Timers.h | 10 |
4 files changed, 340 insertions, 2 deletions
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h index f5dbcd9..de748b5 100644 --- a/include/utils/BitSet.h +++ b/include/utils/BitSet.h @@ -61,6 +61,16 @@ struct BitSet32 { // Result is undefined if all bits are marked. inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); } + // Finds the last marked bit in the set. + // Result is undefined if all bits are unmarked. + inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); } + + // Gets the index of the specified bit in the set, which is the number of + // marked bits that appear before the specified bit. + inline uint32_t getIndexOfBit(uint32_t n) const { + return __builtin_popcount(value & ~(0xffffffffUL >> n)); + } + inline bool operator== (const BitSet32& other) const { return value == other.value; } inline bool operator!= (const BitSet32& other) const { return value != other.value; } }; diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h new file mode 100644 index 0000000..bb9ddd6 --- /dev/null +++ b/include/utils/GenerationCache.h @@ -0,0 +1,255 @@ +/* + * 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_UTILS_GENERATION_CACHE_H +#define ANDROID_UTILS_GENERATION_CACHE_H + +#include <utils/KeyedVector.h> +#include <utils/RefBase.h> + +namespace android { + +/** + * GenerationCache callback used when an item is removed + */ +template<typename EntryKey, typename EntryValue> +class OnEntryRemoved { +public: + virtual ~OnEntryRemoved() { }; + virtual void operator()(EntryKey& key, EntryValue& value) = 0; +}; // class OnEntryRemoved + +template<typename EntryKey, typename EntryValue> +struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { + Entry() { } + Entry(const Entry<EntryKey, EntryValue>& e): + key(e.key), value(e.value), parent(e.parent), child(e.child) { } + Entry(sp<Entry<EntryKey, EntryValue> > e): + key(e->key), value(e->value), parent(e->parent), child(e->child) { } + + EntryKey key; + EntryValue value; + + sp<Entry<EntryKey, EntryValue> > parent; + sp<Entry<EntryKey, EntryValue> > child; +}; // struct Entry + +/** + * A LRU type cache + */ +template<typename K, typename V> +class GenerationCache { +public: + GenerationCache(uint32_t maxCapacity); + virtual ~GenerationCache(); + + enum Capacity { + kUnlimitedCapacity, + }; + + void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); + + void clear(); + + bool contains(K key) const; + V get(K key); + K getKeyAt(uint32_t index) const; + bool put(K key, V value); + V remove(K key); + V removeOldest(); + V getValueAt(uint32_t index) const; + + uint32_t size() const; + + void addToCache(sp<Entry<K, V> > entry, K key, V value); + void attachToCache(sp<Entry<K, V> > entry); + void detachFromCache(sp<Entry<K, V> > entry); + + V removeAt(ssize_t index); + +private: + KeyedVector<K, sp<Entry<K, V> > > mCache; + uint32_t mMaxCapacity; + + OnEntryRemoved<K, V>* mListener; + + sp<Entry<K, V> > mOldest; + sp<Entry<K, V> > mYoungest; +}; // class GenerationCache + +template<typename K, typename V> +GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), + mListener(NULL) { +}; + +template<typename K, typename V> +GenerationCache<K, V>::~GenerationCache() { + clear(); +}; + +template<typename K, typename V> +uint32_t GenerationCache<K, V>::size() const { + return mCache.size(); +} + +/** + * Should be set by the user of the Cache so that the callback is called whenever an item is + * removed from the cache + */ +template<typename K, typename V> +void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) { + mListener = listener; +} + +template<typename K, typename V> +void GenerationCache<K, V>::clear() { + if (mListener) { + for (uint32_t i = 0; i < mCache.size(); i++) { + sp<Entry<K, V> > entry = mCache.valueAt(i); + if (mListener) { + (*mListener)(entry->key, entry->value); + } + } + } + mCache.clear(); + mYoungest.clear(); + mOldest.clear(); +} + +template<typename K, typename V> +bool GenerationCache<K, V>::contains(K key) const { + return mCache.indexOfKey(key) >= 0; +} + +template<typename K, typename V> +K GenerationCache<K, V>::getKeyAt(uint32_t index) const { + return mCache.keyAt(index); +} + +template<typename K, typename V> +V GenerationCache<K, V>::getValueAt(uint32_t index) const { + return mCache.valueAt(index)->value; +} + +template<typename K, typename V> +V GenerationCache<K, V>::get(K key) { + ssize_t index = mCache.indexOfKey(key); + if (index >= 0) { + sp<Entry<K, V> > entry = mCache.valueAt(index); + if (entry.get()) { + detachFromCache(entry); + attachToCache(entry); + return entry->value; + } + } + + return NULL; +} + +template<typename K, typename V> +bool GenerationCache<K, V>::put(K key, V value) { + if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { + removeOldest(); + } + + ssize_t index = mCache.indexOfKey(key); + if (index < 0) { + sp<Entry<K, V> > entry = new Entry<K, V>; + addToCache(entry, key, value); + return true; + } + + return false; +} + +template<typename K, typename V> +void GenerationCache<K, V>::addToCache(sp<Entry<K, V> > entry, K key, V value) { + entry->key = key; + entry->value = value; + mCache.add(key, entry); + attachToCache(entry); +} + +template<typename K, typename V> +V GenerationCache<K, V>::remove(K key) { + ssize_t index = mCache.indexOfKey(key); + if (index >= 0) { + return removeAt(index); + } + + return NULL; +} + +template<typename K, typename V> +V GenerationCache<K, V>::removeAt(ssize_t index) { + sp<Entry<K, V> > entry = mCache.valueAt(index); + if (mListener) { + (*mListener)(entry->key, entry->value); + } + mCache.removeItemsAt(index, 1); + detachFromCache(entry); + + return entry->value; +} + +template<typename K, typename V> +V GenerationCache<K, V>::removeOldest() { + if (mOldest.get()) { + ssize_t index = mCache.indexOfKey(mOldest->key); + if (index >= 0) { + return removeAt(index); + } + } + + return NULL; +} + +template<typename K, typename V> +void GenerationCache<K, V>::attachToCache(sp<Entry<K, V> > entry) { + if (!mYoungest.get()) { + mYoungest = mOldest = entry; + } else { + entry->parent = mYoungest; + mYoungest->child = entry; + mYoungest = entry; + } +} + +template<typename K, typename V> +void GenerationCache<K, V>::detachFromCache(sp<Entry<K, V> > entry) { + if (entry->parent.get()) { + entry->parent->child = entry->child; + } + + if (entry->child.get()) { + entry->child->parent = entry->parent; + } + + if (mOldest == entry) { + mOldest = entry->child; + } + + if (mYoungest == entry) { + mYoungest = entry->parent; + } + + entry->parent.clear(); + entry->child.clear(); +} + +}; // namespace android + +#endif // ANDROID_UTILS_GENERATION_CACHE_H diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 24e72e9..173412e 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -972,6 +972,14 @@ struct ResTable_config uint32_t screenConfig; }; + union { + struct { + uint16_t screenWidthDp; + uint16_t screenHeightDp; + }; + uint32_t screenSizeDp; + }; + inline void copyFromDeviceNoSwap(const ResTable_config& o) { const size_t size = dtohl(o.size); if (size >= sizeof(ResTable_config)) { @@ -992,6 +1000,8 @@ struct ResTable_config screenHeight = dtohs(screenHeight); sdkVersion = dtohs(sdkVersion); minorVersion = dtohs(minorVersion); + screenWidthDp = dtohs(screenWidthDp); + screenHeightDp = dtohs(screenHeightDp); } inline void swapHtoD() { @@ -1003,6 +1013,8 @@ struct ResTable_config screenHeight = htods(screenHeight); sdkVersion = htods(sdkVersion); minorVersion = htods(minorVersion); + screenWidthDp = htods(screenWidthDp); + screenHeightDp = htods(screenHeightDp); } inline int compare(const ResTable_config& o) const { @@ -1021,6 +1033,8 @@ struct ResTable_config diff = (int32_t)(screenLayout - o.screenLayout); if (diff != 0) return diff; diff = (int32_t)(uiMode - o.uiMode); + if (diff != 0) return diff; + diff = (int32_t)(screenSizeDp - o.screenSizeDp); return (int)diff; } @@ -1061,6 +1075,7 @@ struct ResTable_config if (version != o.version) diffs |= CONFIG_VERSION; if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT; if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; + if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE; return diffs; } @@ -1105,6 +1120,18 @@ struct ResTable_config } } + if (screenSizeDp || o.screenSizeDp) { + if (screenWidthDp != o.screenWidthDp) { + if (!screenWidthDp) return false; + if (!o.screenWidthDp) return true; + } + + if (screenHeightDp != o.screenHeightDp) { + if (!screenHeightDp) return false; + if (!o.screenHeightDp) return true; + } + } + if (orientation != o.orientation) { if (!orientation) return false; if (!o.orientation) return true; @@ -1243,6 +1270,30 @@ struct ResTable_config } } + if (screenSizeDp || o.screenSizeDp) { + // Better is based on the sum of the difference between both + // width and height from the requested dimensions. We are + // assuming the invalid configs (with smaller dimens) have + // already been filtered. Note that if a particular dimension + // is unspecified, we will end up with a large value (the + // difference between 0 and the requested dimension), which is + // good since we will prefer a config that has specified a + // dimension value. + int myDelta = 0, otherDelta = 0; + if (requested->screenWidthDp) { + myDelta += requested->screenWidthDp - screenWidthDp; + otherDelta += requested->screenWidthDp - o.screenWidthDp; + } + if (requested->screenHeightDp) { + myDelta += requested->screenHeightDp - screenHeightDp; + otherDelta += requested->screenHeightDp - o.screenHeightDp; + } + //LOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d", + // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp, + // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta); + return (myDelta <= otherDelta); + } + if ((orientation != o.orientation) && requested->orientation) { return (orientation); } @@ -1426,6 +1477,18 @@ struct ResTable_config return false; } } + if (screenSizeDp != 0) { + if (settings.screenWidthDp != 0 && screenWidthDp != 0 + && screenWidthDp > settings.screenWidthDp) { + //LOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp); + return false; + } + if (settings.screenHeightDp != 0 && screenHeightDp != 0 + && screenHeightDp > settings.screenHeightDp) { + //LOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp); + return false; + } + } if (screenType != 0) { if (settings.orientation != 0 && orientation != 0 && orientation != settings.orientation) { @@ -1505,13 +1568,13 @@ struct ResTable_config String8 toString() const { char buf[200]; sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d " - "kbd=%d nav=%d input=%d scrnW=%d scrnH=%d sz=%d long=%d " + "kbd=%d nav=%d input=%d ssz=%dx%d %ddp x %ddp sz=%d long=%d " "ui=%d night=%d vers=%d.%d", mcc, mnc, language[0] ? language[0] : '-', language[1] ? language[1] : '-', country[0] ? country[0] : '-', country[1] ? country[1] : '-', orientation, touchscreen, density, keyboard, navigation, inputFlags, - screenWidth, screenHeight, + screenWidth, screenHeight, screenWidthDp, screenHeightDp, screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG, uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT, sdkVersion, minorVersion); diff --git a/include/utils/Timers.h b/include/utils/Timers.h index 9a9e07c..8b4d322 100644 --- a/include/utils/Timers.h +++ b/include/utils/Timers.h @@ -88,6 +88,16 @@ nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC); nsecs_t systemTime(int clock); #endif // def __cplusplus +/** + * Returns the number of milliseconds to wait between the reference time and the timeout time. + * If the timeout is in the past relative to the reference time, returns 0. + * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time, + * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay. + * Otherwise, returns the difference between the reference time and timeout time + * rounded up to the next millisecond. + */ +int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime); + #ifdef __cplusplus } // extern "C" #endif |