diff options
author | Xavier Ducrohet <xav@android.com> | 2012-07-10 18:38:21 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-07-10 18:38:21 -0700 |
commit | 54059cd38de24bbffc2525b56955535df73bf1eb (patch) | |
tree | 693abe2c8ae261ba276ef46f72e9c7b16cb2adf4 /tools | |
parent | 23316a1ef8868bc641ed72d42839c20b7b86fadb (diff) | |
parent | 15c15eaac51c0c375d18fb70cd1bd066d87b034e (diff) | |
download | frameworks_base-54059cd38de24bbffc2525b56955535df73bf1eb.zip frameworks_base-54059cd38de24bbffc2525b56955535df73bf1eb.tar.gz frameworks_base-54059cd38de24bbffc2525b56955535df73bf1eb.tar.bz2 |
am 15c15eaa: Merge "Replace LruCache implementation for layoutlib. do not merge." into jb-dev
* commit '15c15eaac51c0c375d18fb70cd1bd066d87b034e':
Replace LruCache implementation for layoutlib. do not merge.
Diffstat (limited to 'tools')
5 files changed, 428 insertions, 19 deletions
diff --git a/tools/layoutlib/bridge/src/android/util/LruCache.java b/tools/layoutlib/bridge/src/android/util/LruCache.java new file mode 100644 index 0000000..5208606 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/util/LruCache.java @@ -0,0 +1,391 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * BEGIN LAYOUTLIB CHANGE + * This is a custom version that doesn't use the non standard LinkedHashMap#eldest. + * END LAYOUTLIB CHANGE + * + * A cache that holds strong references to a limited number of values. Each time + * a value is accessed, it is moved to the head of a queue. When a value is + * added to a full cache, the value at the end of that queue is evicted and may + * become eligible for garbage collection. + * + * <p>If your cached values hold resources that need to be explicitly released, + * override {@link #entryRemoved}. + * + * <p>If a cache miss should be computed on demand for the corresponding keys, + * override {@link #create}. This simplifies the calling code, allowing it to + * assume a value will always be returned, even when there's a cache miss. + * + * <p>By default, the cache size is measured in the number of entries. Override + * {@link #sizeOf} to size the cache in different units. For example, this cache + * is limited to 4MiB of bitmaps: + * <pre> {@code + * int cacheSize = 4 * 1024 * 1024; // 4MiB + * LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) { + * protected int sizeOf(String key, Bitmap value) { + * return value.getByteCount(); + * } + * }}</pre> + * + * <p>This class is thread-safe. Perform multiple cache operations atomically by + * synchronizing on the cache: <pre> {@code + * synchronized (cache) { + * if (cache.get(key) == null) { + * cache.put(key, value); + * } + * }}</pre> + * + * <p>This class does not allow null to be used as a key or value. A return + * value of null from {@link #get}, {@link #put} or {@link #remove} is + * unambiguous: the key was not in the cache. + * + * <p>This class appeared in Android 3.1 (Honeycomb MR1); it's available as part + * of <a href="http://developer.android.com/sdk/compatibility-library.html">Android's + * Support Package</a> for earlier releases. + */ +public class LruCache<K, V> { + private final LinkedHashMap<K, V> map; + + /** Size of this cache in units. Not necessarily the number of elements. */ + private int size; + private int maxSize; + + private int putCount; + private int createCount; + private int evictionCount; + private int hitCount; + private int missCount; + + /** + * @param maxSize for caches that do not override {@link #sizeOf}, this is + * the maximum number of entries in the cache. For all other caches, + * this is the maximum sum of the sizes of the entries in this cache. + */ + public LruCache(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + this.maxSize = maxSize; + this.map = new LinkedHashMap<K, V>(0, 0.75f, true); + } + + /** + * Sets the size of the cache. + * @param maxSize The new maximum size. + * + * @hide + */ + public void resize(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + + synchronized (this) { + this.maxSize = maxSize; + } + trimToSize(maxSize); + } + + /** + * Returns the value for {@code key} if it exists in the cache or can be + * created by {@code #create}. If a value was returned, it is moved to the + * head of the queue. This returns null if a value is not cached and cannot + * be created. + */ + public final V get(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V mapValue; + synchronized (this) { + mapValue = map.get(key); + if (mapValue != null) { + hitCount++; + return mapValue; + } + missCount++; + } + + /* + * Attempt to create a value. This may take a long time, and the map + * may be different when create() returns. If a conflicting value was + * added to the map while create() was working, we leave that value in + * the map and release the created value. + */ + + V createdValue = create(key); + if (createdValue == null) { + return null; + } + + synchronized (this) { + createCount++; + mapValue = map.put(key, createdValue); + + if (mapValue != null) { + // There was a conflict so undo that last put + map.put(key, mapValue); + } else { + size += safeSizeOf(key, createdValue); + } + } + + if (mapValue != null) { + entryRemoved(false, key, createdValue, mapValue); + return mapValue; + } else { + trimToSize(maxSize); + return createdValue; + } + } + + /** + * Caches {@code value} for {@code key}. The value is moved to the head of + * the queue. + * + * @return the previous value mapped by {@code key}. + */ + public final V put(K key, V value) { + if (key == null || value == null) { + throw new NullPointerException("key == null || value == null"); + } + + V previous; + synchronized (this) { + putCount++; + size += safeSizeOf(key, value); + previous = map.put(key, value); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, value); + } + + trimToSize(maxSize); + return previous; + } + + /** + * @param maxSize the maximum size of the cache before returning. May be -1 + * to evict even 0-sized elements. + */ + private void trimToSize(int maxSize) { + while (true) { + K key; + V value; + synchronized (this) { + if (size < 0 || (map.isEmpty() && size != 0)) { + throw new IllegalStateException(getClass().getName() + + ".sizeOf() is reporting inconsistent results!"); + } + + if (size <= maxSize) { + break; + } + + // BEGIN LAYOUTLIB CHANGE + // get the last item in the linked list. + // This is not efficient, the goal here is to minimize the changes + // compared to the platform version. + Map.Entry<K, V> toEvict = null; + for (Map.Entry<K, V> entry : map.entrySet()) { + toEvict = entry; + } + // END LAYOUTLIB CHANGE + + if (toEvict == null) { + break; + } + + key = toEvict.getKey(); + value = toEvict.getValue(); + map.remove(key); + size -= safeSizeOf(key, value); + evictionCount++; + } + + entryRemoved(true, key, value, null); + } + } + + /** + * Removes the entry for {@code key} if it exists. + * + * @return the previous value mapped by {@code key}. + */ + public final V remove(K key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + V previous; + synchronized (this) { + previous = map.remove(key); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, null); + } + + return previous; + } + + /** + * Called for entries that have been evicted or removed. This method is + * invoked when a value is evicted to make space, removed by a call to + * {@link #remove}, or replaced by a call to {@link #put}. The default + * implementation does nothing. + * + * <p>The method is called without synchronization: other threads may + * access the cache while this method is executing. + * + * @param evicted true if the entry is being removed to make space, false + * if the removal was caused by a {@link #put} or {@link #remove}. + * @param newValue the new value for {@code key}, if it exists. If non-null, + * this removal was caused by a {@link #put}. Otherwise it was caused by + * an eviction or a {@link #remove}. + */ + protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} + + /** + * Called after a cache miss to compute a value for the corresponding key. + * Returns the computed value or null if no value can be computed. The + * default implementation returns null. + * + * <p>The method is called without synchronization: other threads may + * access the cache while this method is executing. + * + * <p>If a value for {@code key} exists in the cache when this method + * returns, the created value will be released with {@link #entryRemoved} + * and discarded. This can occur when multiple threads request the same key + * at the same time (causing multiple values to be created), or when one + * thread calls {@link #put} while another is creating a value for the same + * key. + */ + protected V create(K key) { + return null; + } + + private int safeSizeOf(K key, V value) { + int result = sizeOf(key, value); + if (result < 0) { + throw new IllegalStateException("Negative size: " + key + "=" + value); + } + return result; + } + + /** + * Returns the size of the entry for {@code key} and {@code value} in + * user-defined units. The default implementation returns 1 so that size + * is the number of entries and max size is the maximum number of entries. + * + * <p>An entry's size must not change while it is in the cache. + */ + protected int sizeOf(K key, V value) { + return 1; + } + + /** + * Clear the cache, calling {@link #entryRemoved} on each removed entry. + */ + public final void evictAll() { + trimToSize(-1); // -1 will evict 0-sized elements + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the number + * of entries in the cache. For all other caches, this returns the sum of + * the sizes of the entries in this cache. + */ + public synchronized final int size() { + return size; + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the maximum + * number of entries in the cache. For all other caches, this returns the + * maximum sum of the sizes of the entries in this cache. + */ + public synchronized final int maxSize() { + return maxSize; + } + + /** + * Returns the number of times {@link #get} returned a value that was + * already present in the cache. + */ + public synchronized final int hitCount() { + return hitCount; + } + + /** + * Returns the number of times {@link #get} returned null or required a new + * value to be created. + */ + public synchronized final int missCount() { + return missCount; + } + + /** + * Returns the number of times {@link #create(Object)} returned a value. + */ + public synchronized final int createCount() { + return createCount; + } + + /** + * Returns the number of times {@link #put} was called. + */ + public synchronized final int putCount() { + return putCount; + } + + /** + * Returns the number of values that have been evicted. + */ + public synchronized final int evictionCount() { + return evictionCount; + } + + /** + * Returns a copy of the current contents of the cache, ordered from least + * recently accessed to most recently accessed. + */ + public synchronized final Map<K, V> snapshot() { + return new LinkedHashMap<K, V>(map); + } + + @Override public synchronized final String toString() { + int accesses = hitCount + missCount; + int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; + return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", + maxSize, hitCount, missCount, hitPercent); + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index f9e48e2..3ae660d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -732,14 +732,16 @@ public final class BridgeContext extends Context { for (int i = 0 ; i < attrs.length ; i++) { Pair<String, Boolean> attribute = attributes.get(i); - // look for the value in the given style - ResourceValue resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(), - attribute.getSecond()); - - if (resValue != null) { - // resolve it to make sure there are no references left. - ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(), - mRenderResources.resolveResValue(resValue)); + if (attribute != null) { + // look for the value in the given style + ResourceValue resValue = mRenderResources.findItemInStyle(style, + attribute.getFirst(), attribute.getSecond()); + + if (resValue != null) { + // resolve it to make sure there are no references left. + ta.bridgeSetValue(i, attribute.getFirst(), attribute.getSecond(), + mRenderResources.resolveResValue(resValue)); + } } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index 1817ab5..62c886b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -233,7 +233,7 @@ abstract class CustomBar extends LinearLayout { BridgeContext bridgeContext = (BridgeContext) mContext; RenderResources res = bridgeContext.getRenderResources(); - ResourceValue value = res.findItemInTheme(themeEntryName); + ResourceValue value = res.findItemInTheme(themeEntryName, true /*isFrameworkAttr*/); value = res.resolveResValue(value); if (value instanceof StyleResourceValue == false) { @@ -243,24 +243,27 @@ abstract class CustomBar extends LinearLayout { StyleResourceValue style = (StyleResourceValue) value; // get the background - ResourceValue backgroundValue = res.findItemInStyle(style, "background"); + ResourceValue backgroundValue = res.findItemInStyle(style, "background", + true /*isFrameworkAttr*/); backgroundValue = res.resolveResValue(backgroundValue); if (backgroundValue != null) { Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext); if (d != null) { - setBackgroundDrawable(d); + setBackground(d); } } TextView textView = getStyleableTextView(); if (textView != null) { // get the text style - ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle"); + ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle", + true /*isFrameworkAttr*/); textStyleValue = res.resolveResValue(textStyleValue); if (textStyleValue instanceof StyleResourceValue) { StyleResourceValue textStyle = (StyleResourceValue) textStyleValue; - ResourceValue textSize = res.findItemInStyle(textStyle, "textSize"); + ResourceValue textSize = res.findItemInStyle(textStyle, "textSize", + true /*isFrameworkAttr*/); textSize = res.resolveResValue(textSize); if (textSize != null) { @@ -273,7 +276,8 @@ abstract class CustomBar extends LinearLayout { } - ResourceValue textColor = res.findItemInStyle(textStyle, "textColor"); + ResourceValue textColor = res.findItemInStyle(textStyle, "textColor", + true /*isFrameworkAttr*/); textColor = res.resolveResValue(textColor); if (textColor != null) { ColorStateList stateList = ResourceHelper.getColorStateList( diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 6840f46..e93b41d 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -952,7 +952,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { private void findBackground(RenderResources resources) { if (getParams().isBgColorOverridden() == false) { - mWindowBackground = resources.findItemInTheme("windowBackground"); + mWindowBackground = resources.findItemInTheme("windowBackground", + true /*isFrameworkAttr*/); if (mWindowBackground != null) { mWindowBackground = resources.resolveResValue(mWindowBackground); } @@ -1003,7 +1004,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { mActionBarSize = DEFAULT_TITLE_BAR_HEIGHT; // get value from the theme. - ResourceValue value = resources.findItemInTheme("actionBarSize"); + ResourceValue value = resources.findItemInTheme("actionBarSize", + true /*isFrameworkAttr*/); // resolve it value = resources.resolveResValue(value); @@ -1028,7 +1030,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT; // get value from the theme. - ResourceValue value = resources.findItemInTheme("windowTitleSize"); + ResourceValue value = resources.findItemInTheme("windowTitleSize", + true /*isFrameworkAttr*/); // resolve it value = resources.resolveResValue(value); @@ -1068,11 +1071,20 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { } } + /** + * Looks for a attribute in the current theme. The attribute is in the android + * namespace. + * + * @param resources the render resources + * @param name the name of the attribute + * @param defaultValue the default value. + * @return the value of the attribute or the default one if not found. + */ private boolean getBooleanThemeValue(RenderResources resources, String name, boolean defaultValue) { // get the title bar flag from the current theme. - ResourceValue value = resources.findItemInTheme(name); + ResourceValue value = resources.findItemInTheme(name, true /*isFrameworkAttr*/); // because it may reference something else, we resolve it. value = resources.resolveResValue(value); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index 79e02c8..5109810 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -116,7 +116,6 @@ public final class CreateInfo implements ICreateInfo { "android.view.View#isInEditMode", "android.view.ViewRootImpl#isInTouchMode", "android.view.inputmethod.InputMethodManager#getInstance", - "android.util.Log#println_native", "com.android.internal.util.XmlUtils#convertValueToInt", "com.android.internal.textservice.ITextServicesManager$Stub#asInterface", }; @@ -185,6 +184,7 @@ public final class CreateInfo implements ICreateInfo { private final static String[] RENAMED_CLASSES = new String[] { "android.os.ServiceManager", "android.os._Original_ServiceManager", + "android.util.LruCache", "android.util._Original_LruCache", "android.view.SurfaceView", "android.view._Original_SurfaceView", "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager", "android.webkit.WebView", "android.webkit._Original_WebView", |