Merge "[RenderScript] Make support lib harder to leak context."
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 383717e..ed3101b 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -45,9 +45,11 @@
int mSpanCount = DEFAULT_SPAN_COUNT;
/**
- * The size of each span
+ * Right borders for each span.
+ * <p>For <b>i-th</b> item start is {@link #mCachedBorders}[i-1] + 1
+ * and end is {@link #mCachedBorders}[i].
*/
- int mSizePerSpan;
+ int [] mCachedBorders;
/**
* Temporary array to keep views in layoutChunk method
*/
@@ -246,7 +248,29 @@
} else {
totalSpace = getHeight() - getPaddingBottom() - getPaddingTop();
}
- mSizePerSpan = totalSpace / mSpanCount;
+ calculateItemBorders(totalSpace);
+ }
+
+ private void calculateItemBorders(int totalSpace) {
+ if (mCachedBorders == null || mCachedBorders.length != mSpanCount + 1
+ || mCachedBorders[mCachedBorders.length - 1] != totalSpace) {
+ mCachedBorders = new int[mSpanCount + 1];
+ }
+ mCachedBorders[0] = 0;
+ int sizePerSpan = totalSpace / mSpanCount;
+ int sizePerSpanRemainder = totalSpace % mSpanCount;
+ int consumedPixels = 0;
+ int additionalSize = 0;
+ for (int i = 1; i <= mSpanCount; i++) {
+ int itemSize = sizePerSpan;
+ additionalSize += sizePerSpanRemainder;
+ if (additionalSize > 0 && (mSpanCount - additionalSize) < sizePerSpanRemainder) {
+ itemSize += 1;
+ additionalSize -= mSpanCount;
+ }
+ consumedPixels += itemSize;
+ mCachedBorders[i] = consumedPixels;
+ }
}
@Override
@@ -387,10 +411,11 @@
}
}
- int spanSize = getSpanSize(recycler, state, getPosition(view));
- final int spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize,
- View.MeasureSpec.EXACTLY);
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ final int spec = View.MeasureSpec.makeMeasureSpec(
+ mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
+ mCachedBorders[lp.mSpanIndex],
+ View.MeasureSpec.EXACTLY);
if (mOrientation == VERTICAL) {
measureChildWithDecorationsAndMargin(view, spec, getMainDirSpec(lp.height));
} else {
@@ -407,8 +432,10 @@
for (int i = 0; i < count; i ++) {
final View view = mSet[i];
if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
- int spanSize = getSpanSize(recycler, state, getPosition(view));
- final int spec = View.MeasureSpec.makeMeasureSpec(mSizePerSpan * spanSize,
+ final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ final int spec = View.MeasureSpec.makeMeasureSpec(
+ mCachedBorders[lp.mSpanIndex + lp.mSpanSize] -
+ mCachedBorders[lp.mSpanIndex],
View.MeasureSpec.EXACTLY);
if (mOrientation == VERTICAL) {
measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec);
@@ -442,10 +469,10 @@
View view = mSet[i];
LayoutParams params = (LayoutParams) view.getLayoutParams();
if (mOrientation == VERTICAL) {
- left = getPaddingLeft() + mSizePerSpan * params.mSpanIndex;
+ left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
} else {
- top = getPaddingTop() + mSizePerSpan * params.mSpanIndex;
+ top = getPaddingTop() + mCachedBorders[params.mSpanIndex];
bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
}
// We calculate everything with View's bounding box (which includes decor and margins)
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index c02a0f6..3788ef6 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -127,6 +127,49 @@
checkForMainThreadException();
}
+ public void testCachedBorders() throws Throwable {
+ List<Config> testConfigurations = new ArrayList<Config>(mBaseVariations);
+ testConfigurations.addAll(cachedBordersTestConfigs());
+ for (Config config : testConfigurations) {
+ gridCachedBorderstTest(config);
+ }
+ }
+
+ private void gridCachedBorderstTest(Config config) throws Throwable {
+ RecyclerView recyclerView = setupBasic(config);
+ waitForFirstLayout(recyclerView);
+ final boolean vertical = config.mOrientation == GridLayoutManager.VERTICAL;
+ final int expectedSizeSum = vertical ? recyclerView.getWidth() : recyclerView.getHeight();
+ final int lastVisible = mGlm.findLastVisibleItemPosition();
+ for (int i = 0; i < lastVisible; i += config.mSpanCount) {
+ if ((i+1)*config.mSpanCount - 1 < lastVisible) {
+ int childrenSizeSum = 0;
+ for (int j = 0; j < config.mSpanCount; j++) {
+ View child = recyclerView.getChildAt(i * config.mSpanCount + j);
+ childrenSizeSum += vertical ? child.getWidth() : child.getHeight();
+ }
+ assertEquals(expectedSizeSum, childrenSizeSum);
+ }
+ }
+ removeRecyclerView();
+ }
+
+ private List<Config> cachedBordersTestConfigs() {
+ ArrayList<Config> configs = new ArrayList<Config>();
+ final int [] spanCounts = new int[]{88, 279, 741};
+ final int [] spanPerItem = new int[]{11, 9, 13};
+ for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
+ for (boolean reverseLayout : new boolean[]{false, true}) {
+ for (int i = 0 ; i < spanCounts.length; i++) {
+ Config config = new Config(spanCounts[i], orientation, reverseLayout);
+ config.mSpanPerItem = spanPerItem[i];
+ configs.add(config);
+ }
+ }
+ }
+ return configs;
+ }
+
public void testLayoutParams() throws Throwable {
layoutParamsTest(GridLayoutManager.HORIZONTAL);
removeRecyclerView();
@@ -630,6 +673,7 @@
int mSpanCount;
int mOrientation = GridLayoutManager.VERTICAL;
int mItemCount = 1000;
+ int mSpanPerItem = 1;
boolean mReverseLayout = false;
Config(int spanCount, int itemCount) {
@@ -662,11 +706,17 @@
class GridTestAdapter extends TestAdapter {
Set<Integer> mFullSpanItems = new HashSet<Integer>();
+ int mSpanPerItem = 1;
GridTestAdapter(int count) {
super(count);
}
+ GridTestAdapter(int count, int spanPerItem) {
+ super(count);
+ mSpanPerItem = spanPerItem;
+ }
+
void setFullSpan(int... items) {
for (int i : items) {
mFullSpanItems.add(i);
@@ -677,7 +727,7 @@
glm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
- return mFullSpanItems.contains(position) ? glm.getSpanCount() : 1;
+ return mFullSpanItems.contains(position) ? glm.getSpanCount() : mSpanPerItem;
}
});
}
diff --git a/v8/renderscript/Android.mk b/v8/renderscript/Android.mk
index 58f7219..a7755aa 100644
--- a/v8/renderscript/Android.mk
+++ b/v8/renderscript/Android.mk
@@ -24,7 +24,7 @@
LOCAL_CFLAGS += -std=c++11
LOCAL_MODULE := android-support-v8-renderscript
-LOCAL_SDK_VERSION := 19
+LOCAL_SDK_VERSION := 21
LOCAL_SRC_FILES := $(call all-java-files-under, java/src)
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
index 5c20e5b..e97c330 100644
--- a/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
+++ b/v8/renderscript/java/src/android/support/v8/renderscript/RenderScript.java
@@ -72,7 +72,7 @@
static Object lock = new Object();
// Non-threadsafe functions.
- native boolean nLoadSO(boolean useNative);
+ native boolean nLoadSO(boolean useNative, int deviceApi);
native boolean nLoadIOSO();
native long nDeviceCreate();
native void nDeviceDestroy(long dev);
@@ -109,6 +109,13 @@
* RenderScript layer or actually using the compatibility library.
*/
static private boolean setupNative(int sdkVersion, Context ctx) {
+ // if targetSdkVersion is higher than the device api version, always use compat mode.
+ // Workaround for KK
+ if (android.os.Build.VERSION.SDK_INT < sdkVersion &&
+ android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
+ sNative = 0;
+ }
+
if (sNative == -1) {
// get the value of the debug.rs.forcecompat property
@@ -1184,7 +1191,7 @@
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
useIOlib = true;
}
- if (!rs.nLoadSO(useNative)) {
+ if (!rs.nLoadSO(useNative, android.os.Build.VERSION.SDK_INT)) {
if (useNative) {
android.util.Log.v(LOG_TAG, "Unable to load libRS.so, falling back to compat mode");
useNative = false;
@@ -1195,7 +1202,7 @@
Log.e(LOG_TAG, "Error loading RS Compat library: " + e);
throw new RSRuntimeException("Error loading RS Compat library: " + e);
}
- if (!rs.nLoadSO(false)) {
+ if (!rs.nLoadSO(false, android.os.Build.VERSION.SDK_INT)) {
throw new RSRuntimeException("Error loading libRSSupport library");
}
}
diff --git a/v8/renderscript/jni/android_renderscript_RenderScript.cpp b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
index 76f1876..38e5676 100644
--- a/v8/renderscript/jni/android_renderscript_RenderScript.cpp
+++ b/v8/renderscript/jni/android_renderscript_RenderScript.cpp
@@ -269,7 +269,7 @@
// Incremental Support lib
static dispatchTable dispatchTabInc;
-static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative) {
+static jboolean nLoadSO(JNIEnv *_env, jobject _this, jboolean useNative, jint deviceApi) {
void* handle = NULL;
if (useNative) {
handle = dlopen("libRS.so", RTLD_LAZY | RTLD_LOCAL);
@@ -281,7 +281,7 @@
return false;
}
- if (loadSymbols(handle, dispatchTab) == false) {
+ if (loadSymbols(handle, dispatchTab, deviceApi) == false) {
LOG_API("%s init failed!", filename);
return false;
}
@@ -1601,7 +1601,7 @@
static const char *classPathName = "android/support/v8/renderscript/RenderScript";
static JNINativeMethod methods[] = {
-{"nLoadSO", "(Z)Z", (bool*)nLoadSO },
+{"nLoadSO", "(ZI)Z", (bool*)nLoadSO },
{"nLoadIOSO", "()Z", (bool*)nLoadIOSO },
{"nDeviceCreate", "()J", (void*)nDeviceCreate },
{"nDeviceDestroy", "(J)V", (void*)nDeviceDestroy },