summaryrefslogtreecommitdiffstats
path: root/include/utils
diff options
context:
space:
mode:
Diffstat (limited to 'include/utils')
-rw-r--r--include/utils/BitSet.h10
-rw-r--r--include/utils/GenerationCache.h255
-rw-r--r--include/utils/ResourceTypes.h67
-rw-r--r--include/utils/Timers.h10
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