summaryrefslogtreecommitdiffstats
path: root/tests/src/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/com/android')
-rw-r--r--tests/src/com/android/gallery3d/anim/AnimationTest.java80
-rw-r--r--tests/src/com/android/gallery3d/common/BlobCacheTest.java738
-rw-r--r--tests/src/com/android/gallery3d/common/UtilsTest.java244
-rw-r--r--tests/src/com/android/gallery3d/data/GalleryAppMock.java50
-rw-r--r--tests/src/com/android/gallery3d/data/GalleryAppStub.java47
-rw-r--r--tests/src/com/android/gallery3d/data/LocalDataTest.java461
-rw-r--r--tests/src/com/android/gallery3d/data/MediaSetTest.java63
-rw-r--r--tests/src/com/android/gallery3d/data/MockItem.java43
-rw-r--r--tests/src/com/android/gallery3d/data/MockSet.java88
-rw-r--r--tests/src/com/android/gallery3d/data/MockSource.java48
-rw-r--r--tests/src/com/android/gallery3d/data/PathTest.java82
-rw-r--r--tests/src/com/android/gallery3d/data/RealDataTest.java110
-rw-r--r--tests/src/com/android/gallery3d/ui/GLCanvasMock.java68
-rw-r--r--tests/src/com/android/gallery3d/ui/GLCanvasStub.java79
-rw-r--r--tests/src/com/android/gallery3d/ui/GLCanvasTest.java778
-rw-r--r--tests/src/com/android/gallery3d/ui/GLMock.java195
-rw-r--r--tests/src/com/android/gallery3d/ui/GLRootMock.java37
-rw-r--r--tests/src/com/android/gallery3d/ui/GLRootStub.java30
-rw-r--r--tests/src/com/android/gallery3d/ui/GLStub.java1490
-rw-r--r--tests/src/com/android/gallery3d/ui/GLViewMock.java85
-rw-r--r--tests/src/com/android/gallery3d/ui/GLViewTest.java424
-rw-r--r--tests/src/com/android/gallery3d/ui/PointerInfo.java222
-rw-r--r--tests/src/com/android/gallery3d/ui/TextureTest.java208
-rw-r--r--tests/src/com/android/gallery3d/util/IntArrayTest.java60
24 files changed, 5730 insertions, 0 deletions
diff --git a/tests/src/com/android/gallery3d/anim/AnimationTest.java b/tests/src/com/android/gallery3d/anim/AnimationTest.java
new file mode 100644
index 000000000..c7d5daec7
--- /dev/null
+++ b/tests/src/com/android/gallery3d/anim/AnimationTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.anim;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.view.animation.Interpolator;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class AnimationTest extends TestCase {
+ private static final String TAG = "AnimationTest";
+
+ public void testFloatAnimation() {
+ FloatAnimation a = new FloatAnimation(0f, 1f, 10); // value 0 to 1.0, duration 10
+ a.start(); // start animation
+ assertTrue(a.isActive()); // should be active now
+ a.calculate(0); // set start time = 0
+ assertTrue(a.get() == 0); // start value should be 0
+ a.calculate(1); // calculate value for time 1
+ assertFloatEq(a.get(), 0.1f);
+ a.calculate(5); // calculate value for time 5
+ assertTrue(a.get() == 0.5);//
+ a.calculate(9); // calculate value for time 9
+ assertFloatEq(a.get(), 0.9f);
+ a.calculate(10); // calculate value for time 10
+ assertTrue(!a.isActive()); // should be inactive now
+ assertTrue(a.get() == 1.0);//
+ a.start(); // restart
+ assertTrue(a.isActive()); // should be active now
+ a.calculate(5); // set start time = 5
+ assertTrue(a.get() == 0); // start value should be 0
+ a.calculate(5+9); // calculate for time 5+9
+ assertFloatEq(a.get(), 0.9f);
+ }
+
+ private static class MyInterpolator implements Interpolator {
+ public float getInterpolation(float input) {
+ return 4f * (input - 0.5f); // maps [0,1] to [-2,2]
+ }
+ }
+
+ public void testInterpolator() {
+ FloatAnimation a = new FloatAnimation(0f, 1f, 10); // value 0 to 1.0, duration 10
+ a.setInterpolator(new MyInterpolator());
+ a.start(); // start animation
+ a.calculate(0); // set start time = 0
+ assertTrue(a.get() == -2); // start value should be -2
+ a.calculate(1); // calculate value for time 1
+ assertFloatEq(a.get(), -1.6f);
+ a.calculate(5); // calculate value for time 5
+ assertTrue(a.get() == 0); //
+ a.calculate(9); // calculate value for time 9
+ assertFloatEq(a.get(), 1.6f);
+ a.calculate(10); // calculate value for time 10
+ assertTrue(a.get() == 2); //
+ }
+
+ public static void assertFloatEq(float expected, float actual) {
+ if (Math.abs(actual - expected) > 1e-6) {
+ Log.v(TAG, "expected: " + expected + ", actual: " + actual);
+ fail();
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/common/BlobCacheTest.java b/tests/src/com/android/gallery3d/common/BlobCacheTest.java
new file mode 100644
index 000000000..2a911c45b
--- /dev/null
+++ b/tests/src/com/android/gallery3d/common/BlobCacheTest.java
@@ -0,0 +1,738 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.common;
+
+import com.android.gallery3d.common.BlobCache;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Random;
+
+public class BlobCacheTest extends AndroidTestCase {
+ private static final String TAG = "BlobCacheTest";
+
+ @SmallTest
+ public void testReadIntLong() {
+ byte[] buf = new byte[9];
+ assertEquals(0, BlobCache.readInt(buf, 0));
+ assertEquals(0, BlobCache.readLong(buf, 0));
+ buf[0] = 1;
+ assertEquals(1, BlobCache.readInt(buf, 0));
+ assertEquals(1, BlobCache.readLong(buf, 0));
+ buf[3] = 0x7f;
+ assertEquals(0x7f000001, BlobCache.readInt(buf, 0));
+ assertEquals(0x7f000001, BlobCache.readLong(buf, 0));
+ assertEquals(0x007f0000, BlobCache.readInt(buf, 1));
+ assertEquals(0x007f0000, BlobCache.readLong(buf, 1));
+ buf[3] = (byte) 0x80;
+ buf[7] = (byte) 0xA0;
+ buf[0] = 0;
+ assertEquals(0x80000000, BlobCache.readInt(buf, 0));
+ assertEquals(0xA000000080000000L, BlobCache.readLong(buf, 0));
+ for (int i = 0; i < 8; i++) {
+ buf[i] = (byte) (0x11 * (i+8));
+ }
+ assertEquals(0xbbaa9988, BlobCache.readInt(buf, 0));
+ assertEquals(0xffeeddccbbaa9988L, BlobCache.readLong(buf, 0));
+ buf[8] = 0x33;
+ assertEquals(0x33ffeeddccbbaa99L, BlobCache.readLong(buf, 1));
+ }
+
+ @SmallTest
+ public void testWriteIntLong() {
+ byte[] buf = new byte[8];
+ BlobCache.writeInt(buf, 0, 0x12345678);
+ assertEquals(0x78, buf[0]);
+ assertEquals(0x56, buf[1]);
+ assertEquals(0x34, buf[2]);
+ assertEquals(0x12, buf[3]);
+ assertEquals(0x00, buf[4]);
+ BlobCache.writeLong(buf, 0, 0xffeeddccbbaa9988L);
+ for (int i = 0; i < 8; i++) {
+ assertEquals((byte) (0x11 * (i+8)), buf[i]);
+ }
+ }
+
+ @MediumTest
+ public void testChecksum() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+ byte[] buf = new byte[0];
+ assertEquals(0x1, bc.checkSum(buf));
+ buf = new byte[1];
+ assertEquals(0x10001, bc.checkSum(buf));
+ buf[0] = 0x47;
+ assertEquals(0x480048, bc.checkSum(buf));
+ buf = new byte[3];
+ buf[0] = 0x10;
+ buf[1] = 0x30;
+ buf[2] = 0x01;
+ assertEquals(0x940042, bc.checkSum(buf));
+ assertEquals(0x310031, bc.checkSum(buf, 1, 1));
+ assertEquals(0x1, bc.checkSum(buf, 1, 0));
+ assertEquals(0x630032, bc.checkSum(buf, 1, 2));
+ buf = new byte[1024];
+ for (int i = 0; i < buf.length; i++) {
+ buf[i] = (byte)(i*i);
+ }
+ assertEquals(0x3574a610, bc.checkSum(buf));
+ bc.close();
+ }
+
+ private static final int HEADER_SIZE = 32;
+ private static final int DATA_HEADER_SIZE = 4;
+ private static final int BLOB_HEADER_SIZE = 20;
+
+ private static final String TEST_FILE_NAME = "/sdcard/btest";
+ private static final int MAX_ENTRIES = 100;
+ private static final int MAX_BYTES = 1000;
+ private static final int INDEX_SIZE = HEADER_SIZE + MAX_ENTRIES * 12 * 2;
+ private static final long KEY_0 = 0x1122334455667788L;
+ private static final long KEY_1 = 0x1122334455667789L;
+ private static final long KEY_2 = 0x112233445566778AL;
+ private static byte[] DATA_0 = new byte[10];
+ private static byte[] DATA_1 = new byte[10];
+
+ @MediumTest
+ public void testBasic() throws IOException {
+ String name = TEST_FILE_NAME;
+ BlobCache bc;
+ File idxFile = new File(name + ".idx");
+ File data0File = new File(name + ".0");
+ File data1File = new File(name + ".1");
+
+ // Create a brand new cache.
+ bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, true);
+ bc.close();
+
+ // Make sure the initial state is correct.
+ assertTrue(idxFile.exists());
+ assertTrue(data0File.exists());
+ assertTrue(data1File.exists());
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE, data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+ assertEquals(0, bc.getActiveCount());
+
+ // Re-open it.
+ bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false);
+ assertNull(bc.lookup(KEY_0));
+
+ // insert one blob
+ genData(DATA_0, 1);
+ bc.insert(KEY_0, DATA_0);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+ assertEquals(1, bc.getActiveCount());
+ bc.close();
+
+ // Make sure the file size is right.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + BLOB_HEADER_SIZE + DATA_0.length,
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+
+ // Re-open it and make sure we can get the old data
+ bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+
+ // insert with the same key (but using a different blob)
+ genData(DATA_0, 2);
+ bc.insert(KEY_0, DATA_0);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+ assertEquals(1, bc.getActiveCount());
+ bc.close();
+
+ // Make sure the file size is right.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + 2 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+
+ // Re-open it and make sure we can get the old data
+ bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, false);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+
+ // insert another key and make sure we can get both key.
+ assertNull(bc.lookup(KEY_1));
+ genData(DATA_1, 3);
+ bc.insert(KEY_1, DATA_1);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+ assertSameData(DATA_1, bc.lookup(KEY_1));
+ assertEquals(2, bc.getActiveCount());
+ bc.close();
+
+ // Make sure the file size is right.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + 3 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+
+ // Re-open it and make sure we can get the old data
+ bc = new BlobCache(name, 100, 1000, false);
+ assertSameData(DATA_0, bc.lookup(KEY_0));
+ assertSameData(DATA_1, bc.lookup(KEY_1));
+ assertEquals(2, bc.getActiveCount());
+ bc.close();
+ }
+
+ @MediumTest
+ public void testNegativeKey() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+
+ // insert one blob
+ genData(DATA_0, 1);
+ bc.insert(-123, DATA_0);
+ assertSameData(DATA_0, bc.lookup(-123));
+ bc.close();
+ }
+
+ @MediumTest
+ public void testEmptyBlob() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+
+ byte[] data = new byte[0];
+ bc.insert(123, data);
+ assertSameData(data, bc.lookup(123));
+ bc.close();
+ }
+
+ @MediumTest
+ public void testLookupRequest() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+
+ // insert one blob
+ genData(DATA_0, 1);
+ bc.insert(1, DATA_0);
+ assertSameData(DATA_0, bc.lookup(1));
+
+ // the same size buffer
+ byte[] buf = new byte[DATA_0.length];
+ BlobCache.LookupRequest req = new BlobCache.LookupRequest();
+ req.key = 1;
+ req.buffer = buf;
+ assertTrue(bc.lookup(req));
+ assertEquals(1, req.key);
+ assertSame(buf, req.buffer);
+ assertEquals(DATA_0.length, req.length);
+
+ // larger buffer
+ buf = new byte[DATA_0.length + 22];
+ req = new BlobCache.LookupRequest();
+ req.key = 1;
+ req.buffer = buf;
+ assertTrue(bc.lookup(req));
+ assertEquals(1, req.key);
+ assertSame(buf, req.buffer);
+ assertEquals(DATA_0.length, req.length);
+
+ // smaller buffer
+ buf = new byte[DATA_0.length - 1];
+ req = new BlobCache.LookupRequest();
+ req.key = 1;
+ req.buffer = buf;
+ assertTrue(bc.lookup(req));
+ assertEquals(1, req.key);
+ assertNotSame(buf, req.buffer);
+ assertEquals(DATA_0.length, req.length);
+ assertSameData(DATA_0, req.buffer, DATA_0.length);
+
+ // null buffer
+ req = new BlobCache.LookupRequest();
+ req.key = 1;
+ req.buffer = null;
+ assertTrue(bc.lookup(req));
+ assertEquals(1, req.key);
+ assertNotNull(req.buffer);
+ assertEquals(DATA_0.length, req.length);
+ assertSameData(DATA_0, req.buffer, DATA_0.length);
+
+ bc.close();
+ }
+
+ @MediumTest
+ public void testKeyCollision() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+
+ for (int i = 0; i < MAX_ENTRIES / 2; i++) {
+ genData(DATA_0, i);
+ long key = KEY_1 + i * MAX_ENTRIES;
+ bc.insert(key, DATA_0);
+ }
+
+ for (int i = 0; i < MAX_ENTRIES / 2; i++) {
+ genData(DATA_0, i);
+ long key = KEY_1 + i * MAX_ENTRIES;
+ assertSameData(DATA_0, bc.lookup(key));
+ }
+ bc.close();
+ }
+
+ @MediumTest
+ public void testRegionFlip() throws IOException {
+ String name = TEST_FILE_NAME;
+ BlobCache bc;
+ File idxFile = new File(name + ".idx");
+ File data0File = new File(name + ".0");
+ File data1File = new File(name + ".1");
+
+ // Create a brand new cache.
+ bc = new BlobCache(name, MAX_ENTRIES, MAX_BYTES, true);
+
+ // This is the number of blobs fits into a region.
+ int maxFit = (MAX_BYTES - DATA_HEADER_SIZE) /
+ (BLOB_HEADER_SIZE + DATA_0.length);
+
+ for (int k = 0; k < maxFit; k++) {
+ genData(DATA_0, k);
+ bc.insert(k, DATA_0);
+ }
+ assertEquals(maxFit, bc.getActiveCount());
+
+ // Make sure the file size is right.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+
+ // Now insert another one and let it flip.
+ genData(DATA_0, 777);
+ bc.insert(KEY_1, DATA_0);
+ assertEquals(1, bc.getActiveCount());
+
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+
+ // Make sure we can find the new data
+ assertSameData(DATA_0, bc.lookup(KEY_1));
+
+ // Now find an old blob
+ int old = maxFit / 2;
+ genData(DATA_0, old);
+ assertSameData(DATA_0, bc.lookup(old));
+ assertEquals(2, bc.getActiveCount());
+
+ // Observed data is copied.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + 2 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+
+ // Now copy everything over (except we should have no space for the last one)
+ assertTrue(old < maxFit - 1);
+ for (int k = 0; k < maxFit; k++) {
+ genData(DATA_0, k);
+ assertSameData(DATA_0, bc.lookup(k));
+ }
+ assertEquals(maxFit, bc.getActiveCount());
+
+ // Now both file should be full.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+
+ // Now insert one to make it flip.
+ genData(DATA_0, 888);
+ bc.insert(KEY_2, DATA_0);
+ assertEquals(1, bc.getActiveCount());
+
+ // Check the size after the second flip.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+
+ // Now the last key should be gone.
+ assertNull(bc.lookup(maxFit - 1));
+
+ // But others should remain
+ for (int k = 0; k < maxFit - 1; k++) {
+ genData(DATA_0, k);
+ assertSameData(DATA_0, bc.lookup(k));
+ }
+
+ assertEquals(maxFit, bc.getActiveCount());
+ genData(DATA_0, 777);
+ assertSameData(DATA_0, bc.lookup(KEY_1));
+ genData(DATA_0, 888);
+ assertSameData(DATA_0, bc.lookup(KEY_2));
+ assertEquals(maxFit, bc.getActiveCount());
+
+ // Now two files should be full.
+ assertEquals(INDEX_SIZE, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+
+ bc.close();
+ }
+
+ @MediumTest
+ public void testEntryLimit() throws IOException {
+ String name = TEST_FILE_NAME;
+ BlobCache bc;
+ File idxFile = new File(name + ".idx");
+ File data0File = new File(name + ".0");
+ File data1File = new File(name + ".1");
+ int maxEntries = 10;
+ int maxFit = maxEntries / 2;
+ int indexSize = HEADER_SIZE + maxEntries * 12 * 2;
+
+ // Create a brand new cache with a small entry limit.
+ bc = new BlobCache(name, maxEntries, MAX_BYTES, true);
+
+ // Fill to just before flipping
+ for (int i = 0; i < maxFit; i++) {
+ genData(DATA_0, i);
+ bc.insert(i, DATA_0);
+ }
+ assertEquals(maxFit, bc.getActiveCount());
+
+ // Check the file size.
+ assertEquals(indexSize, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE, data1File.length());
+
+ // Insert one and make it flip
+ genData(DATA_0, 777);
+ bc.insert(777, DATA_0);
+ assertEquals(1, bc.getActiveCount());
+
+ // Check the file size.
+ assertEquals(indexSize, idxFile.length());
+ assertEquals(DATA_HEADER_SIZE + maxFit * (BLOB_HEADER_SIZE + DATA_0.length),
+ data0File.length());
+ assertEquals(DATA_HEADER_SIZE + 1 * (BLOB_HEADER_SIZE + DATA_0.length),
+ data1File.length());
+ bc.close();
+ }
+
+ @LargeTest
+ public void testDataIntegrity() throws IOException {
+ String name = TEST_FILE_NAME;
+ File idxFile = new File(name + ".idx");
+ File data0File = new File(name + ".0");
+ File data1File = new File(name + ".1");
+ RandomAccessFile f;
+
+ Log.v(TAG, "It should be readable if the content is not changed.");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(1);
+ byte b = f.readByte();
+ f.seek(1);
+ f.write(b);
+ f.close();
+ assertReadable();
+
+ Log.v(TAG, "Change the data file magic field");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(1);
+ f.write(0xFF);
+ f.close();
+ assertUnreadable();
+
+ prepareNewCache();
+ f = new RandomAccessFile(data1File, "rw");
+ f.write(0xFF);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob key");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4);
+ f.write(0x00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob checksum");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 8);
+ f.write(0x00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob offset");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 12);
+ f.write(0x20);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob length: some other value");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 16);
+ f.write(0x20);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob length: -1");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 16);
+ f.writeInt(0xFFFFFFFF);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob length: big value");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 16);
+ f.writeInt(0xFFFFFF00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the blob content");
+ prepareNewCache();
+ f = new RandomAccessFile(data0File, "rw");
+ f.seek(4 + 20);
+ f.write(0x01);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the index magic");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(1);
+ f.write(0x00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the active region");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(12);
+ f.write(0x01);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the reserved data");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(24);
+ f.write(0x01);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the checksum");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(29);
+ f.write(0x00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the key");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES));
+ f.write(0x00);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the offset");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES) + 8);
+ f.write(0x05);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Change the offset");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ f.seek(32 + 12 * (KEY_1 % MAX_ENTRIES) + 8 + 3);
+ f.write(0xFF);
+ f.close();
+ assertUnreadable();
+
+ Log.v(TAG, "Garbage index");
+ prepareNewCache();
+ f = new RandomAccessFile(idxFile, "rw");
+ int n = (int) idxFile.length();
+ f.seek(32);
+ byte[] garbage = new byte[1024];
+ for (int i = 0; i < garbage.length; i++) {
+ garbage[i] = (byte) 0x80;
+ }
+ int i = 32;
+ while (i < n) {
+ int todo = Math.min(garbage.length, n - i);
+ f.write(garbage, 0, todo);
+ i += todo;
+ }
+ f.close();
+ assertUnreadable();
+ }
+
+ // Create a brand new cache and put one entry into it.
+ private void prepareNewCache() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+ genData(DATA_0, 777);
+ bc.insert(KEY_1, DATA_0);
+ bc.close();
+ }
+
+ private void assertReadable() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, false);
+ genData(DATA_0, 777);
+ assertSameData(DATA_0, bc.lookup(KEY_1));
+ bc.close();
+ }
+
+ private void assertUnreadable() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, false);
+ genData(DATA_0, 777);
+ assertNull(bc.lookup(KEY_1));
+ bc.close();
+ }
+
+ @LargeTest
+ public void testRandomSize() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, MAX_BYTES, true);
+
+ // Random size test
+ Random rand = new Random(0);
+ for (int i = 0; i < 100; i++) {
+ byte[] data = new byte[rand.nextInt(MAX_BYTES*12/10)];
+ try {
+ bc.insert(rand.nextLong(), data);
+ if (data.length > MAX_BYTES - 4 - 20) fail();
+ } catch (RuntimeException ex) {
+ if (data.length <= MAX_BYTES - 4 - 20) fail();
+ }
+ }
+
+ bc.close();
+ }
+
+ @LargeTest
+ public void testBandwidth() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, 1000, 10000000, true);
+
+ // Write
+ int count = 0;
+ byte[] data = new byte[20000];
+ long t0 = System.nanoTime();
+ for (int i = 0; i < 1000; i++) {
+ bc.insert(i, data);
+ count += data.length;
+ }
+ bc.syncAll();
+ float delta = (System.nanoTime() - t0) * 1e-3f;
+ Log.v(TAG, "write bandwidth = " + (count / delta) + " M/s");
+
+ // Copy over
+ BlobCache.LookupRequest req = new BlobCache.LookupRequest();
+ count = 0;
+ t0 = System.nanoTime();
+ for (int i = 0; i < 1000; i++) {
+ req.key = i;
+ req.buffer = data;
+ if (bc.lookup(req)) {
+ count += req.length;
+ }
+ }
+ bc.syncAll();
+ delta = (System.nanoTime() - t0) * 1e-3f;
+ Log.v(TAG, "copy over bandwidth = " + (count / delta) + " M/s");
+
+ // Read
+ count = 0;
+ t0 = System.nanoTime();
+ for (int i = 0; i < 1000; i++) {
+ req.key = i;
+ req.buffer = data;
+ if (bc.lookup(req)) {
+ count += req.length;
+ }
+ }
+ bc.syncAll();
+ delta = (System.nanoTime() - t0) * 1e-3f;
+ Log.v(TAG, "read bandwidth = " + (count / delta) + " M/s");
+
+ bc.close();
+ }
+
+ @LargeTest
+ public void testSmallSize() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, MAX_ENTRIES, 40, true);
+
+ // Small size test
+ Random rand = new Random(0);
+ for (int i = 0; i < 100; i++) {
+ byte[] data = new byte[rand.nextInt(3)];
+ bc.insert(rand.nextLong(), data);
+ }
+
+ bc.close();
+ }
+
+ @LargeTest
+ public void testManyEntries() throws IOException {
+ BlobCache bc = new BlobCache(TEST_FILE_NAME, 1, MAX_BYTES, true);
+
+ // Many entries test
+ Random rand = new Random(0);
+ for (int i = 0; i < 100; i++) {
+ byte[] data = new byte[rand.nextInt(10)];
+ }
+
+ bc.close();
+ }
+
+ private void genData(byte[] data, int seed) {
+ for(int i = 0; i < data.length; i++) {
+ data[i] = (byte) (seed * i);
+ }
+ }
+
+ private void assertSameData(byte[] data1, byte[] data2) {
+ if (data1 == null && data2 == null) return;
+ if (data1 == null || data2 == null) fail();
+ if (data1.length != data2.length) fail();
+ for (int i = 0; i < data1.length; i++) {
+ if (data1[i] != data2[i]) fail();
+ }
+ }
+
+ private void assertSameData(byte[] data1, byte[] data2, int n) {
+ if (data1 == null || data2 == null) fail();
+ for (int i = 0; i < n; i++) {
+ if (data1[i] != data2[i]) fail();
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/common/UtilsTest.java b/tests/src/com/android/gallery3d/common/UtilsTest.java
new file mode 100644
index 000000000..b3552444b
--- /dev/null
+++ b/tests/src/com/android/gallery3d/common/UtilsTest.java
@@ -0,0 +1,244 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.common;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+public class UtilsTest extends AndroidTestCase {
+ private static final String TAG = "UtilsTest";
+
+ private static final int [] testData = new int [] {
+ /* outWidth, outHeight, minSideLength, maxNumOfPixels, sample size */
+ 1, 1, BitmapUtils.UNCONSTRAINED, BitmapUtils.UNCONSTRAINED, 1,
+ 1, 1, 1, 1, 1,
+ 100, 100, 100, 10000, 1,
+ 100, 100, 100, 2500, 2,
+ 99, 66, 33, 10000, 2,
+ 66, 99, 33, 10000, 2,
+ 99, 66, 34, 10000, 1,
+ 99, 66, 22, 10000, 4,
+ 99, 66, 16, 10000, 4,
+
+ 10000, 10000, 20000, 1000000, 16,
+
+ 100, 100, 100, 10000, 1, // 1
+ 100, 100, 50, 10000, 2, // 2
+ 100, 100, 30, 10000, 4, // 3->4
+ 100, 100, 22, 10000, 4, // 4
+ 100, 100, 20, 10000, 8, // 5->8
+ 100, 100, 11, 10000, 16, // 9->16
+ 100, 100, 5, 10000, 24, // 20->24
+ 100, 100, 2, 10000, 56, // 50->56
+
+ 100, 100, 100, 10000 - 1, 2, // a bit less than 1
+ 100, 100, 100, 10000 / (2 * 2) - 1, 4, // a bit less than 2
+ 100, 100, 100, 10000 / (3 * 3) - 1, 4, // a bit less than 3
+ 100, 100, 100, 10000 / (4 * 4) - 1, 8, // a bit less than 4
+ 100, 100, 100, 10000 / (8 * 8) - 1, 16, // a bit less than 8
+ 100, 100, 100, 10000 / (16 * 16) - 1, 24, // a bit less than 16
+ 100, 100, 100, 10000 / (24 * 24) - 1, 32, // a bit less than 24
+ 100, 100, 100, 10000 / (32 * 32) - 1, 40, // a bit less than 32
+
+ 640, 480, 480, BitmapUtils.UNCONSTRAINED, 1, // 1
+ 640, 480, 240, BitmapUtils.UNCONSTRAINED, 2, // 2
+ 640, 480, 160, BitmapUtils.UNCONSTRAINED, 4, // 3->4
+ 640, 480, 120, BitmapUtils.UNCONSTRAINED, 4, // 4
+ 640, 480, 96, BitmapUtils.UNCONSTRAINED, 8, // 5->8
+ 640, 480, 80, BitmapUtils.UNCONSTRAINED, 8, // 6->8
+ 640, 480, 60, BitmapUtils.UNCONSTRAINED, 8, // 8
+ 640, 480, 48, BitmapUtils.UNCONSTRAINED, 16, // 10->16
+ 640, 480, 40, BitmapUtils.UNCONSTRAINED, 16, // 12->16
+ 640, 480, 30, BitmapUtils.UNCONSTRAINED, 16, // 16
+ 640, 480, 24, BitmapUtils.UNCONSTRAINED, 24, // 20->24
+ 640, 480, 20, BitmapUtils.UNCONSTRAINED, 24, // 24
+ 640, 480, 16, BitmapUtils.UNCONSTRAINED, 32, // 30->32
+ 640, 480, 12, BitmapUtils.UNCONSTRAINED, 40, // 40
+ 640, 480, 10, BitmapUtils.UNCONSTRAINED, 48, // 48
+ 640, 480, 8, BitmapUtils.UNCONSTRAINED, 64, // 60->64
+ 640, 480, 6, BitmapUtils.UNCONSTRAINED, 80, // 80
+ 640, 480, 4, BitmapUtils.UNCONSTRAINED, 120, // 120
+ 640, 480, 3, BitmapUtils.UNCONSTRAINED, 160, // 160
+ 640, 480, 2, BitmapUtils.UNCONSTRAINED, 240, // 240
+ 640, 480, 1, BitmapUtils.UNCONSTRAINED, 480, // 480
+
+ 640, 480, BitmapUtils.UNCONSTRAINED, BitmapUtils.UNCONSTRAINED, 1,
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480, 1, // 1
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 - 1, 2, // a bit less than 1
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 4, 2, // 2
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 4 - 1, 4, // a bit less than 2
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 9, 4, // 3
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 9 - 1, 4, // a bit less than 3
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 16, 4, // 4
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 16 - 1, 8, // a bit less than 4
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 64, 8, // 8
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 64 - 1, 16, // a bit less than 8
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 256, 16, // 16
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / 256 - 1, 24, // a bit less than 16
+ 640, 480, BitmapUtils.UNCONSTRAINED, 640 * 480 / (24 * 24) - 1, 32, // a bit less than 24
+ };
+
+ @SmallTest
+ public void testComputeSampleSize() {
+
+ for (int i = 0; i < testData.length; i += 5) {
+ int w = testData[i];
+ int h = testData[i + 1];
+ int minSide = testData[i + 2];
+ int maxPixels = testData[i + 3];
+ int sampleSize = testData[i + 4];
+ int result = BitmapUtils.computeSampleSize(w, h, minSide, maxPixels);
+ if (result != sampleSize) {
+ Log.v(TAG, w + "x" + h + ", minSide = " + minSide + ", maxPixels = "
+ + maxPixels + ", sampleSize = " + sampleSize + ", result = "
+ + result);
+ }
+ assertTrue(sampleSize == result);
+ }
+ }
+
+ public void testAssert() {
+ // This should not throw an exception.
+ Utils.assertTrue(true);
+
+ // This should throw an exception.
+ try {
+ Utils.assertTrue(false);
+ fail();
+ } catch (AssertionError ex) {
+ // expected.
+ }
+ }
+
+ public void testCheckNotNull() {
+ // These should not throw an expection.
+ Utils.checkNotNull(new Object());
+ Utils.checkNotNull(0);
+ Utils.checkNotNull("");
+
+ // This should throw an expection.
+ try {
+ Utils.checkNotNull(null);
+ fail();
+ } catch (NullPointerException ex) {
+ // expected.
+ }
+ }
+
+ public void testEquals() {
+ Object a = new Object();
+ Object b = new Object();
+
+ assertTrue(Utils.equals(null, null));
+ assertTrue(Utils.equals(a, a));
+ assertFalse(Utils.equals(null, a));
+ assertFalse(Utils.equals(a, null));
+ assertFalse(Utils.equals(a, b));
+ }
+
+ public void testIsPowerOf2() {
+ for (int i = 0; i < 31; i++) {
+ int v = (1 << i);
+ assertTrue(Utils.isPowerOf2(v));
+ }
+
+ int[] f = new int[] {3, 5, 6, 7, 9, 10, 65535, Integer.MAX_VALUE - 1,
+ Integer.MAX_VALUE };
+ for (int v : f) {
+ assertFalse(Utils.isPowerOf2(v));
+ }
+
+ int[] e = new int[] {0, -1, -2, -4, -65536, Integer.MIN_VALUE + 1,
+ Integer.MIN_VALUE };
+ for (int v : e) {
+ try {
+ Utils.isPowerOf2(v);
+ fail();
+ } catch (IllegalArgumentException ex) {
+ // expected.
+ }
+ }
+ }
+
+ public void testNextPowerOf2() {
+ int[] q = new int[] {1, 2, 3, 4, 5, 6, 10, 65535, (1 << 30) - 1, (1 << 30)};
+ int[] a = new int[] {1, 2, 4, 4, 8, 8, 16, 65536, (1 << 30) , (1 << 30)};
+
+ for (int i = 0; i < q.length; i++) {
+ assertEquals(a[i], Utils.nextPowerOf2(q[i]));
+ }
+
+ int[] e = new int[] {0, -1, -2, -4, -65536, (1 << 30) + 1, Integer.MAX_VALUE};
+
+ for (int v : e) {
+ try {
+ Utils.nextPowerOf2(v);
+ fail();
+ } catch (IllegalArgumentException ex) {
+ // expected.
+ }
+ }
+ }
+
+ public void testDistance() {
+ assertFloatEq(0f, Utils.distance(0, 0, 0, 0));
+ assertFloatEq(1f, Utils.distance(0, 1, 0, 0));
+ assertFloatEq(1f, Utils.distance(0, 0, 0, 1));
+ assertFloatEq(2f, Utils.distance(1, 2, 3, 2));
+ assertFloatEq(5f, Utils.distance(1, 2, 1 + 3, 2 + 4));
+ assertFloatEq(5f, Utils.distance(1, 2, 1 + 3, 2 + 4));
+ assertFloatEq(Float.MAX_VALUE, Utils.distance(Float.MAX_VALUE, 0, 0, 0));
+ }
+
+ public void testClamp() {
+ assertEquals(1000, Utils.clamp(300, 1000, 2000));
+ assertEquals(1300, Utils.clamp(1300, 1000, 2000));
+ assertEquals(2000, Utils.clamp(2300, 1000, 2000));
+
+ assertEquals(0.125f, Utils.clamp(0.1f, 0.125f, 0.5f));
+ assertEquals(0.25f, Utils.clamp(0.25f, 0.125f, 0.5f));
+ assertEquals(0.5f, Utils.clamp(0.9f, 0.125f, 0.5f));
+ }
+
+ public void testIsOpaque() {
+ assertTrue(Utils.isOpaque(0xFF000000));
+ assertTrue(Utils.isOpaque(0xFFFFFFFF));
+ assertTrue(Utils.isOpaque(0xFF123456));
+
+ assertFalse(Utils.isOpaque(0xFEFFFFFF));
+ assertFalse(Utils.isOpaque(0x8FFFFFFF));
+ assertFalse(Utils.isOpaque(0x00FF0000));
+ assertFalse(Utils.isOpaque(0x5500FF00));
+ assertFalse(Utils.isOpaque(0xAA0000FF));
+ }
+
+ public static void testSwap() {
+ Integer[] a = {1, 2, 3};
+ Utils.swap(a, 0, 2);
+ assertEquals(a[0].intValue(), 3);
+ assertEquals(a[1].intValue(), 2);
+ assertEquals(a[2].intValue(), 1);
+ }
+
+ public static void assertFloatEq(float expected, float actual) {
+ if (Math.abs(actual - expected) > 1e-6) {
+ Log.v(TAG, "expected: " + expected + ", actual: " + actual);
+ fail();
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/GalleryAppMock.java b/tests/src/com/android/gallery3d/data/GalleryAppMock.java
new file mode 100644
index 000000000..bbc569238
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/GalleryAppMock.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.gallery3d.ui.GLRoot;
+import com.android.gallery3d.ui.GLRootStub;
+
+class GalleryAppMock extends GalleryAppStub {
+ GLRoot mGLRoot = new GLRootStub();
+ DataManager mDataManager = new DataManager(this);
+ ContentResolver mResolver;
+ Context mContext;
+ Looper mMainLooper;
+
+ GalleryAppMock(Context context,
+ ContentResolver resolver, Looper mainLooper) {
+ mContext = context;
+ mResolver = resolver;
+ mMainLooper = mainLooper;
+ }
+
+ @Override
+ public GLRoot getGLRoot() { return mGLRoot; }
+ @Override
+ public DataManager getDataManager() { return mDataManager; }
+ @Override
+ public Context getAndroidContext() { return mContext; }
+ @Override
+ public ContentResolver getContentResolver() { return mResolver; }
+ @Override
+ public Looper getMainLooper() { return mMainLooper; }
+}
diff --git a/tests/src/com/android/gallery3d/data/GalleryAppStub.java b/tests/src/com/android/gallery3d/data/GalleryAppStub.java
new file mode 100644
index 000000000..36075f435
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/GalleryAppStub.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import com.android.gallery3d.app.GalleryApp;
+import com.android.gallery3d.app.StateManager;
+import com.android.gallery3d.ui.GLRoot;
+import com.android.gallery3d.ui.PositionRepository;
+import com.android.gallery3d.util.ThreadPool;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Looper;
+
+class GalleryAppStub implements GalleryApp {
+ public ImageCacheService getImageCacheService() { return null; }
+ public StateManager getStateManager() { return null; }
+ public DataManager getDataManager() { return null; }
+ public DownloadUtils getDownloadService() { return null; }
+ public DecodeUtils getDecodeService() { return null; }
+
+ public GLRoot getGLRoot() { return null; }
+ public PositionRepository getPositionRepository() { return null; }
+
+ public Context getAndroidContext() { return null; }
+
+ public Looper getMainLooper() { return null; }
+ public Resources getResources() { return null; }
+ public ContentResolver getContentResolver() { return null; }
+ public ThreadPool getThreadPool() { return null; }
+ public DownloadCache getDownloadCache() { return null; }
+}
diff --git a/tests/src/com/android/gallery3d/data/LocalDataTest.java b/tests/src/com/android/gallery3d/data/LocalDataTest.java
new file mode 100644
index 000000000..8f6a46b8e
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/LocalDataTest.java
@@ -0,0 +1,461 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContentProvider;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class LocalDataTest extends AndroidTestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = "LocalDataTest";
+ private static final long DEFAULT_TIMEOUT = 1000; // one second
+
+ @MediumTest
+ public void testLocalAlbum() throws Exception {
+ new TestZeroImage().run();
+ new TestOneImage().run();
+ new TestMoreImages().run();
+ new TestZeroVideo().run();
+ new TestOneVideo().run();
+ new TestMoreVideos().run();
+ new TestDeleteOneImage().run();
+ new TestDeleteOneAlbum().run();
+ }
+
+ abstract class TestLocalAlbumBase {
+ private boolean mIsImage;
+ protected GalleryAppStub mApp;
+ protected LocalAlbumSet mAlbumSet;
+
+ TestLocalAlbumBase(boolean isImage) {
+ mIsImage = isImage;
+ }
+
+ public void run() throws Exception {
+ SQLiteDatabase db = SQLiteDatabase.create(null);
+ prepareData(db);
+ mApp = newGalleryContext(db, Looper.getMainLooper());
+ Path.clearAll();
+ Path path = Path.fromString(
+ mIsImage ? "/local/image" : "/local/video");
+ mAlbumSet = new LocalAlbumSet(path, mApp);
+ mAlbumSet.reload();
+ verifyResult();
+ }
+
+ abstract void prepareData(SQLiteDatabase db);
+ abstract void verifyResult() throws Exception;
+ }
+
+ abstract class TestLocalImageAlbum extends TestLocalAlbumBase {
+ TestLocalImageAlbum() {
+ super(true);
+ }
+ }
+
+ abstract class TestLocalVideoAlbum extends TestLocalAlbumBase {
+ TestLocalVideoAlbum() {
+ super(false);
+ }
+ }
+
+ class TestZeroImage extends TestLocalImageAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ createImageTable(db);
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(0, mAlbumSet.getSubMediaSetCount());
+ assertEquals(0, mAlbumSet.getTotalMediaItemCount());
+ }
+ }
+
+ class TestOneImage extends TestLocalImageAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ createImageTable(db);
+ insertImageData(db);
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(1, mAlbumSet.getSubMediaSetCount());
+ assertEquals(1, mAlbumSet.getTotalMediaItemCount());
+ MediaSet sub = mAlbumSet.getSubMediaSet(0);
+ assertEquals(1, sub.getMediaItemCount());
+ assertEquals(0, sub.getSubMediaSetCount());
+ LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0);
+ assertEquals(1, item.id);
+ assertEquals("IMG_0072", item.caption);
+ assertEquals("image/jpeg", item.mimeType);
+ assertEquals(12.0, item.latitude);
+ assertEquals(34.0, item.longitude);
+ assertEquals(0xD000, item.dateTakenInMs);
+ assertEquals(1280395646L, item.dateAddedInSec);
+ assertEquals(1275934796L, item.dateModifiedInSec);
+ assertEquals("/mnt/sdcard/DCIM/100CANON/IMG_0072.JPG", item.filePath);
+ }
+ }
+
+ class TestMoreImages extends TestLocalImageAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ // Albums are sorted by names, and items are sorted by
+ // dateTimeTaken (descending)
+ createImageTable(db);
+ // bucket 0xB000
+ insertImageData(db, 1000, 0xB000, "second"); // id 1
+ insertImageData(db, 2000, 0xB000, "second"); // id 2
+ // bucket 0xB001
+ insertImageData(db, 3000, 0xB001, "first"); // id 3
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(2, mAlbumSet.getSubMediaSetCount());
+ assertEquals(3, mAlbumSet.getTotalMediaItemCount());
+
+ MediaSet first = mAlbumSet.getSubMediaSet(0);
+ assertEquals(1, first.getMediaItemCount());
+ LocalMediaItem item = (LocalMediaItem) first.getMediaItem(0, 1).get(0);
+ assertEquals(3, item.id);
+ assertEquals(3000L, item.dateTakenInMs);
+
+ MediaSet second = mAlbumSet.getSubMediaSet(1);
+ assertEquals(2, second.getMediaItemCount());
+ item = (LocalMediaItem) second.getMediaItem(0, 1).get(0);
+ assertEquals(2, item.id);
+ assertEquals(2000L, item.dateTakenInMs);
+ item = (LocalMediaItem) second.getMediaItem(1, 1).get(0);
+ assertEquals(1, item.id);
+ assertEquals(1000L, item.dateTakenInMs);
+ }
+ }
+
+ class OnContentDirtyLatch implements ContentListener {
+ private CountDownLatch mLatch = new CountDownLatch(1);
+
+ public void onContentDirty() {
+ mLatch.countDown();
+ }
+
+ public boolean isOnContentDirtyBeCalled(long timeout)
+ throws InterruptedException {
+ return mLatch.await(timeout, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ class TestDeleteOneAlbum extends TestLocalImageAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ // Albums are sorted by names, and items are sorted by
+ // dateTimeTaken (descending)
+ createImageTable(db);
+ // bucket 0xB000
+ insertImageData(db, 1000, 0xB000, "second"); // id 1
+ insertImageData(db, 2000, 0xB000, "second"); // id 2
+ // bucket 0xB001
+ insertImageData(db, 3000, 0xB001, "first"); // id 3
+ }
+
+ @Override
+ public void verifyResult() throws Exception {
+ MediaSet sub = mAlbumSet.getSubMediaSet(1); // "second"
+ assertEquals(2, mAlbumSet.getSubMediaSetCount());
+ OnContentDirtyLatch latch = new OnContentDirtyLatch();
+ sub.addContentListener(latch);
+ assertTrue((sub.getSupportedOperations() & MediaSet.SUPPORT_DELETE) != 0);
+ sub.delete();
+ mAlbumSet.fakeChange();
+ latch.isOnContentDirtyBeCalled(DEFAULT_TIMEOUT);
+ mAlbumSet.reload();
+ assertEquals(1, mAlbumSet.getSubMediaSetCount());
+ }
+ }
+
+ class TestDeleteOneImage extends TestLocalImageAlbum {
+
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ createImageTable(db);
+ insertImageData(db);
+ }
+
+ @Override
+ public void verifyResult() {
+ MediaSet sub = mAlbumSet.getSubMediaSet(0);
+ LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0);
+ assertEquals(1, sub.getMediaItemCount());
+ assertTrue((sub.getSupportedOperations() & MediaSet.SUPPORT_DELETE) != 0);
+ sub.delete();
+ sub.reload();
+ assertEquals(0, sub.getMediaItemCount());
+ }
+ }
+
+ static void createImageTable(SQLiteDatabase db) {
+ // This is copied from MediaProvider
+ db.execSQL("CREATE TABLE IF NOT EXISTS images (" +
+ "_id INTEGER PRIMARY KEY," +
+ "_data TEXT," +
+ "_size INTEGER," +
+ "_display_name TEXT," +
+ "mime_type TEXT," +
+ "title TEXT," +
+ "date_added INTEGER," +
+ "date_modified INTEGER," +
+ "description TEXT," +
+ "picasa_id TEXT," +
+ "isprivate INTEGER," +
+ "latitude DOUBLE," +
+ "longitude DOUBLE," +
+ "datetaken INTEGER," +
+ "orientation INTEGER," +
+ "mini_thumb_magic INTEGER," +
+ "bucket_id TEXT," +
+ "bucket_display_name TEXT" +
+ ");");
+ }
+
+ static void insertImageData(SQLiteDatabase db) {
+ insertImageData(db, 0xD000, 0xB000, "name");
+ }
+
+ static void insertImageData(SQLiteDatabase db, long dateTaken,
+ int bucketId, String bucketName) {
+ db.execSQL("INSERT INTO images (title, mime_type, latitude, longitude, "
+ + "datetaken, date_added, date_modified, bucket_id, "
+ + "bucket_display_name, _data, orientation) "
+ + "VALUES ('IMG_0072', 'image/jpeg', 12, 34, "
+ + dateTaken + ", 1280395646, 1275934796, '" + bucketId + "', "
+ + "'" + bucketName + "', "
+ + "'/mnt/sdcard/DCIM/100CANON/IMG_0072.JPG', 0)");
+ }
+
+ class TestZeroVideo extends TestLocalVideoAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ createVideoTable(db);
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(0, mAlbumSet.getSubMediaSetCount());
+ assertEquals(0, mAlbumSet.getTotalMediaItemCount());
+ }
+ }
+
+ class TestOneVideo extends TestLocalVideoAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ createVideoTable(db);
+ insertVideoData(db);
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(1, mAlbumSet.getSubMediaSetCount());
+ assertEquals(1, mAlbumSet.getTotalMediaItemCount());
+ MediaSet sub = mAlbumSet.getSubMediaSet(0);
+ assertEquals(1, sub.getMediaItemCount());
+ assertEquals(0, sub.getSubMediaSetCount());
+ LocalMediaItem item = (LocalMediaItem) sub.getMediaItem(0, 1).get(0);
+ assertEquals(1, item.id);
+ assertEquals("VID_20100811_051413", item.caption);
+ assertEquals("video/mp4", item.mimeType);
+ assertEquals(11.0, item.latitude);
+ assertEquals(22.0, item.longitude);
+ assertEquals(0xD000, item.dateTakenInMs);
+ assertEquals(1281503663L, item.dateAddedInSec);
+ assertEquals(1281503662L, item.dateModifiedInSec);
+ assertEquals("/mnt/sdcard/DCIM/Camera/VID_20100811_051413.3gp",
+ item.filePath);
+ }
+ }
+
+ class TestMoreVideos extends TestLocalVideoAlbum {
+ @Override
+ public void prepareData(SQLiteDatabase db) {
+ // Albums are sorted by names, and items are sorted by
+ // dateTimeTaken (descending)
+ createVideoTable(db);
+ // bucket 0xB002
+ insertVideoData(db, 1000, 0xB000, "second"); // id 1
+ insertVideoData(db, 2000, 0xB000, "second"); // id 2
+ // bucket 0xB001
+ insertVideoData(db, 3000, 0xB001, "first"); // id 3
+ }
+
+ @Override
+ public void verifyResult() {
+ assertEquals(0, mAlbumSet.getMediaItemCount());
+ assertEquals(2, mAlbumSet.getSubMediaSetCount());
+ assertEquals(3, mAlbumSet.getTotalMediaItemCount());
+
+ MediaSet first = mAlbumSet.getSubMediaSet(0);
+ assertEquals(1, first.getMediaItemCount());
+ LocalMediaItem item = (LocalMediaItem) first.getMediaItem(0, 1).get(0);
+ assertEquals(3, item.id);
+ assertEquals(3000L, item.dateTakenInMs);
+
+ MediaSet second = mAlbumSet.getSubMediaSet(1);
+ assertEquals(2, second.getMediaItemCount());
+ item = (LocalMediaItem) second.getMediaItem(0, 1).get(0);
+ assertEquals(2, item.id);
+ assertEquals(2000L, item.dateTakenInMs);
+ item = (LocalMediaItem) second.getMediaItem(1, 1).get(0);
+ assertEquals(1, item.id);
+ assertEquals(1000L, item.dateTakenInMs);
+ }
+ }
+
+ static void createVideoTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS video (" +
+ "_id INTEGER PRIMARY KEY," +
+ "_data TEXT NOT NULL," +
+ "_display_name TEXT," +
+ "_size INTEGER," +
+ "mime_type TEXT," +
+ "date_added INTEGER," +
+ "date_modified INTEGER," +
+ "title TEXT," +
+ "duration INTEGER," +
+ "artist TEXT," +
+ "album TEXT," +
+ "resolution TEXT," +
+ "description TEXT," +
+ "isprivate INTEGER," + // for YouTube videos
+ "tags TEXT," + // for YouTube videos
+ "category TEXT," + // for YouTube videos
+ "language TEXT," + // for YouTube videos
+ "mini_thumb_data TEXT," +
+ "latitude DOUBLE," +
+ "longitude DOUBLE," +
+ "datetaken INTEGER," +
+ "mini_thumb_magic INTEGER" +
+ ");");
+ db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;");
+ db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT");
+ }
+
+ static void insertVideoData(SQLiteDatabase db) {
+ insertVideoData(db, 0xD000, 0xB000, "name");
+ }
+
+ static void insertVideoData(SQLiteDatabase db, long dateTaken,
+ int bucketId, String bucketName) {
+ db.execSQL("INSERT INTO video (title, mime_type, latitude, longitude, "
+ + "datetaken, date_added, date_modified, bucket_id, "
+ + "bucket_display_name, _data, duration) "
+ + "VALUES ('VID_20100811_051413', 'video/mp4', 11, 22, "
+ + dateTaken + ", 1281503663, 1281503662, '" + bucketId + "', "
+ + "'" + bucketName + "', "
+ + "'/mnt/sdcard/DCIM/Camera/VID_20100811_051413.3gp', 2964)");
+ }
+
+ static GalleryAppStub newGalleryContext(SQLiteDatabase db, Looper mainLooper) {
+ MockContentResolver cr = new MockContentResolver();
+ ContentProvider cp = new DbContentProvider(db, cr);
+ cr.addProvider("media", cp);
+ return new GalleryAppMock(null, cr, mainLooper);
+ }
+}
+
+class DbContentProvider extends MockContentProvider {
+ private static final String TAG = "DbContentProvider";
+ private SQLiteDatabase mDatabase;
+ private ContentResolver mContentResolver;
+
+ DbContentProvider(SQLiteDatabase db, ContentResolver cr) {
+ mDatabase = db;
+ mContentResolver = cr;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder) {
+ // This is a simplified version extracted from MediaProvider.
+
+ String tableName = getTableName(uri);
+ if (tableName == null) return null;
+
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+ qb.setTables(tableName);
+
+ String groupBy = null;
+ String limit = uri.getQueryParameter("limit");
+
+ if (uri.getQueryParameter("distinct") != null) {
+ qb.setDistinct(true);
+ }
+
+ Log.v(TAG, "query = " + qb.buildQuery(projection, selection,
+ selectionArgs, groupBy, null, sortOrder, limit));
+
+ if (selectionArgs != null) {
+ for (String s : selectionArgs) {
+ Log.v(TAG, " selectionArgs = " + s);
+ }
+ }
+
+ Cursor c = qb.query(mDatabase, projection, selection,
+ selectionArgs, groupBy, null, sortOrder, limit);
+
+ return c;
+ }
+
+ @Override
+ public int delete(Uri uri, String whereClause, String[] whereArgs) {
+ Log.v(TAG, "delete " + uri + "," + whereClause + "," + whereArgs[0]);
+ String tableName = getTableName(uri);
+ if (tableName == null) return 0;
+ int count = mDatabase.delete(tableName, whereClause, whereArgs);
+ mContentResolver.notifyChange(uri, null);
+ return count;
+ }
+
+ private String getTableName(Uri uri) {
+ String uriString = uri.toString();
+ if (uriString.startsWith("content://media/external/images/media")) {
+ return "images";
+ } else if (uriString.startsWith("content://media/external/video/media")) {
+ return "video";
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/MediaSetTest.java b/tests/src/com/android/gallery3d/data/MediaSetTest.java
new file mode 100644
index 000000000..33dfe96de
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/MediaSetTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import com.android.gallery3d.app.GalleryApp;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class MediaSetTest extends AndroidTestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = "MediaSetTest";
+
+ @SmallTest
+ public void testComboAlbumSet() {
+ GalleryApp app = new GalleryAppMock(null, null, null);
+ Path.clearAll();
+ DataManager dataManager = app.getDataManager();
+
+ dataManager.addSource(new ComboSource(app));
+ dataManager.addSource(new MockSource(app));
+
+ MockSet set00 = new MockSet(Path.fromString("/mock/00"), dataManager, 0, 2000);
+ MockSet set01 = new MockSet(Path.fromString("/mock/01"), dataManager, 1, 3000);
+ MockSet set10 = new MockSet(Path.fromString("/mock/10"), dataManager, 2, 4000);
+ MockSet set11 = new MockSet(Path.fromString("/mock/11"), dataManager, 3, 5000);
+ MockSet set12 = new MockSet(Path.fromString("/mock/12"), dataManager, 4, 6000);
+
+ MockSet set0 = new MockSet(Path.fromString("/mock/0"), dataManager, 7, 7000);
+ set0.addMediaSet(set00);
+ set0.addMediaSet(set01);
+
+ MockSet set1 = new MockSet(Path.fromString("/mock/1"), dataManager, 8, 8000);
+ set1.addMediaSet(set10);
+ set1.addMediaSet(set11);
+ set1.addMediaSet(set12);
+
+ MediaSet combo = dataManager.getMediaSet("/combo/{/mock/0,/mock/1}");
+ assertEquals(5, combo.getSubMediaSetCount());
+ assertEquals(0, combo.getMediaItemCount());
+ assertEquals("/mock/00", combo.getSubMediaSet(0).getPath().toString());
+ assertEquals("/mock/01", combo.getSubMediaSet(1).getPath().toString());
+ assertEquals("/mock/10", combo.getSubMediaSet(2).getPath().toString());
+ assertEquals("/mock/11", combo.getSubMediaSet(3).getPath().toString());
+ assertEquals("/mock/12", combo.getSubMediaSet(4).getPath().toString());
+
+ assertEquals(10, combo.getTotalMediaItemCount());
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/MockItem.java b/tests/src/com/android/gallery3d/data/MockItem.java
new file mode 100644
index 000000000..bd6dcd9cb
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/MockItem.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import com.android.gallery3d.util.ThreadPool.Job;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapRegionDecoder;
+
+public class MockItem extends MediaItem {
+ public MockItem(Path path) {
+ super(path, nextVersionNumber());
+ }
+
+ @Override
+ public Job<Bitmap> requestImage(int type) {
+ return null;
+ }
+
+ @Override
+ public Job<BitmapRegionDecoder> requestLargeImage() {
+ return null;
+ }
+
+ @Override
+ public String getMimeType() {
+ return null;
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/MockSet.java b/tests/src/com/android/gallery3d/data/MockSet.java
new file mode 100644
index 000000000..fa83c796f
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/MockSet.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import java.util.ArrayList;
+
+public class MockSet extends MediaSet {
+ ArrayList<MediaItem> mItems = new ArrayList<MediaItem>();
+ ArrayList<MediaSet> mSets = new ArrayList<MediaSet>();
+ Path mItemPath;
+
+ public MockSet(Path path, DataManager dataManager) {
+ super(path, nextVersionNumber());
+ mItemPath = Path.fromString("/mock/item");
+ }
+
+ public MockSet(Path path, DataManager dataManager,
+ int items, int item_id_start) {
+ this(path, dataManager);
+ for (int i = 0; i < items; i++) {
+ Path childPath = mItemPath.getChild(item_id_start + i);
+ mItems.add(new MockItem(childPath));
+ }
+ }
+
+ public void addMediaSet(MediaSet sub) {
+ mSets.add(sub);
+ }
+
+ @Override
+ public int getMediaItemCount() {
+ return mItems.size();
+ }
+
+ @Override
+ public ArrayList<MediaItem> getMediaItem(int start, int count) {
+ ArrayList<MediaItem> result = new ArrayList<MediaItem>();
+ int end = Math.min(start + count, mItems.size());
+
+ for (int i = start; i < end; i++) {
+ result.add(mItems.get(i));
+ }
+ return result;
+ }
+
+ @Override
+ public int getSubMediaSetCount() {
+ return mSets.size();
+ }
+
+ @Override
+ public MediaSet getSubMediaSet(int index) {
+ return mSets.get(index);
+ }
+
+ @Override
+ public int getTotalMediaItemCount() {
+ int result = mItems.size();
+ for (MediaSet s : mSets) {
+ result += s.getTotalMediaItemCount();
+ }
+ return result;
+ }
+
+ @Override
+ public String getName() {
+ return "Set " + mPath;
+ }
+
+ @Override
+ public long reload() {
+ return 0;
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/MockSource.java b/tests/src/com/android/gallery3d/data/MockSource.java
new file mode 100644
index 000000000..27ed4d0de
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/MockSource.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import com.android.gallery3d.app.GalleryApp;
+
+class MockSource extends MediaSource {
+ GalleryApp mApplication;
+ PathMatcher mMatcher;
+
+ private static final int MOCK_SET = 0;
+ private static final int MOCK_ITEM = 1;
+
+ public MockSource(GalleryApp context) {
+ super("mock");
+ mApplication = context;
+ mMatcher = new PathMatcher();
+ mMatcher.add("/mock/*", MOCK_SET);
+ mMatcher.add("/mock/item/*", MOCK_ITEM);
+ }
+
+ @Override
+ public MediaObject createMediaObject(Path path) {
+ MediaObject obj;
+ switch (mMatcher.match(path)) {
+ case MOCK_SET:
+ return new MockSet(path, mApplication.getDataManager());
+ case MOCK_ITEM:
+ return new MockItem(path);
+ default:
+ throw new RuntimeException("bad path: " + path);
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/PathTest.java b/tests/src/com/android/gallery3d/data/PathTest.java
new file mode 100644
index 000000000..b43d10963
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/PathTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PathTest extends AndroidTestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = "PathTest";
+
+ @SmallTest
+ public void testToString() {
+ Path p = Path.fromString("/hello/world");
+ assertEquals("/hello/world", p.toString());
+
+ p = Path.fromString("/a");
+ assertEquals("/a", p.toString());
+
+ p = Path.fromString("");
+ assertEquals("", p.toString());
+ }
+
+ @SmallTest
+ public void testSplit() {
+ Path p = Path.fromString("/hello/world");
+ String[] s = p.split();
+ assertEquals(2, s.length);
+ assertEquals("hello", s[0]);
+ assertEquals("world", s[1]);
+
+ p = Path.fromString("");
+ assertEquals(0, p.split().length);
+ }
+
+ @SmallTest
+ public void testPrefix() {
+ Path p = Path.fromString("/hello/world");
+ assertEquals("hello", p.getPrefix());
+
+ p = Path.fromString("");
+ assertEquals("", p.getPrefix());
+ }
+
+ @SmallTest
+ public void testGetChild() {
+ Path p = Path.fromString("/hello");
+ Path q = Path.fromString("/hello/world");
+ assertSame(q, p.getChild("world"));
+ Path r = q.getChild(17);
+ assertEquals("/hello/world/17", r.toString());
+ }
+
+ @SmallTest
+ public void testSplitSequence() {
+ String[] s = Path.splitSequence("{a,bb,ccc}");
+ assertEquals(3, s.length);
+ assertEquals("a", s[0]);
+ assertEquals("bb", s[1]);
+ assertEquals("ccc", s[2]);
+
+ s = Path.splitSequence("{a,{bb,ccc},d}");
+ assertEquals(3, s.length);
+ assertEquals("a", s[0]);
+ assertEquals("{bb,ccc}", s[1]);
+ assertEquals("d", s[2]);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/data/RealDataTest.java b/tests/src/com/android/gallery3d/data/RealDataTest.java
new file mode 100644
index 000000000..526cfe357
--- /dev/null
+++ b/tests/src/com/android/gallery3d/data/RealDataTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.data;
+
+import com.android.gallery3d.app.GalleryApp;
+import com.android.gallery3d.picasasource.PicasaSource;
+
+import android.os.Looper;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+// This test reads real data directly and dump information out in the log.
+public class RealDataTest extends AndroidTestCase {
+ private static final String TAG = "RealDataTest";
+
+ private HashSet<Path> mUsedId = new HashSet<Path>();
+ private GalleryApp mApplication;
+ private DataManager mDataManager;
+
+ @LargeTest
+ public void testRealData() {
+ mUsedId.clear();
+ mApplication = new GalleryAppMock(
+ mContext,
+ mContext.getContentResolver(),
+ Looper.myLooper());
+ mDataManager = mApplication.getDataManager();
+ mDataManager.addSource(new LocalSource(mApplication));
+ mDataManager.addSource(new PicasaSource(mApplication));
+ new TestLocalImage().run();
+ new TestLocalVideo().run();
+ new TestPicasa().run();
+ }
+
+ class TestLocalImage {
+ public void run() {
+ MediaSet set = mDataManager.getMediaSet("/local/image");
+ set.reload();
+ Log.v(TAG, "LocalAlbumSet (Image)");
+ dumpMediaSet(set, "");
+ }
+ }
+
+ class TestLocalVideo {
+ public void run() {
+ MediaSet set = mDataManager.getMediaSet("/local/video");
+ set.reload();
+ Log.v(TAG, "LocalAlbumSet (Video)");
+ dumpMediaSet(set, "");
+ }
+ }
+
+ class TestPicasa implements Runnable {
+ public void run() {
+ MediaSet set = mDataManager.getMediaSet("/picasa");
+ set.reload();
+ Log.v(TAG, "PicasaAlbumSet");
+ dumpMediaSet(set, "");
+ }
+ }
+
+ void dumpMediaSet(MediaSet set, String prefix) {
+ Log.v(TAG, "getName() = " + set.getName());
+ Log.v(TAG, "getPath() = " + set.getPath());
+ Log.v(TAG, "getMediaItemCount() = " + set.getMediaItemCount());
+ Log.v(TAG, "getSubMediaSetCount() = " + set.getSubMediaSetCount());
+ Log.v(TAG, "getTotalMediaItemCount() = " + set.getTotalMediaItemCount());
+ assertNewId(set.getPath());
+ for (int i = 0, n = set.getSubMediaSetCount(); i < n; i++) {
+ MediaSet sub = set.getSubMediaSet(i);
+ Log.v(TAG, prefix + "got set " + i);
+ dumpMediaSet(sub, prefix + " ");
+ }
+ for (int i = 0, n = set.getMediaItemCount(); i < n; i += 10) {
+ ArrayList<MediaItem> list = set.getMediaItem(i, 10);
+ Log.v(TAG, prefix + "got item " + i + " (+" + list.size() + ")");
+ for (MediaItem item : list) {
+ dumpMediaItem(item, prefix + "..");
+ }
+ }
+ }
+
+ void dumpMediaItem(MediaItem item, String prefix) {
+ assertNewId(item.getPath());
+ Log.v(TAG, prefix + "getPath() = " + item.getPath());
+ }
+
+ void assertNewId(Path key) {
+ assertFalse(key + " has already appeared.", mUsedId.contains(key));
+ mUsedId.add(key);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasMock.java b/tests/src/com/android/gallery3d/ui/GLCanvasMock.java
new file mode 100644
index 000000000..f8100ddf6
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLCanvasMock.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class GLCanvasMock extends GLCanvasStub {
+ // fillRect
+ int mFillRectCalled;
+ float mFillRectWidth;
+ float mFillRectHeight;
+ int mFillRectColor;
+ // drawMixed
+ int mDrawMixedCalled;
+ float mDrawMixedRatio;
+ // drawTexture;
+ int mDrawTextureCalled;
+
+ private GL11 mGL;
+
+ public GLCanvasMock(GL11 gl) {
+ mGL = gl;
+ }
+
+ public GLCanvasMock() {
+ mGL = new GLStub();
+ }
+
+ @Override
+ public GL11 getGLInstance() {
+ return mGL;
+ }
+
+ @Override
+ public void fillRect(float x, float y, float width, float height, int color) {
+ mFillRectCalled++;
+ mFillRectWidth = width;
+ mFillRectHeight = height;
+ mFillRectColor = color;
+ }
+
+ @Override
+ public void drawTexture(
+ BasicTexture texture, int x, int y, int width, int height) {
+ mDrawTextureCalled++;
+ }
+
+ @Override
+ public void drawMixed(BasicTexture from, BasicTexture to,
+ float ratio, int x, int y, int w, int h) {
+ mDrawMixedCalled++;
+ mDrawMixedRatio = ratio;
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java
new file mode 100644
index 000000000..f1663f4bd
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import android.graphics.RectF;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class GLCanvasStub implements GLCanvas {
+ public void setSize(int width, int height) {}
+ public void clearBuffer() {}
+ public void setCurrentAnimationTimeMillis(long time) {}
+ public long currentAnimationTimeMillis() {
+ throw new UnsupportedOperationException();
+ }
+ public void setAlpha(float alpha) {}
+ public float getAlpha() {
+ throw new UnsupportedOperationException();
+ }
+ public void multiplyAlpha(float alpha) {}
+ public void translate(float x, float y, float z) {}
+ public void scale(float sx, float sy, float sz) {}
+ public void rotate(float angle, float x, float y, float z) {}
+ public boolean clipRect(int left, int top, int right, int bottom) {
+ throw new UnsupportedOperationException();
+ }
+ public int save() {
+ throw new UnsupportedOperationException();
+ }
+ public int save(int saveFlags) {
+ throw new UnsupportedOperationException();
+ }
+ public void setBlendEnabled(boolean enabled) {}
+ public void restore() {}
+ public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint) {}
+ public void drawRect(float x1, float y1, float x2, float y2, GLPaint paint) {}
+ public void fillRect(float x, float y, float width, float height, int color) {}
+ public void drawTexture(
+ BasicTexture texture, int x, int y, int width, int height) {}
+ public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
+ int uvBuffer, int indexBuffer, int indexCount) {}
+ public void drawTexture(BasicTexture texture,
+ int x, int y, int width, int height, float alpha) {}
+ public void drawTexture(BasicTexture texture, RectF source, RectF target) {}
+ public void drawMixed(BasicTexture from, BasicTexture to,
+ float ratio, int x, int y, int w, int h) {}
+ public void drawMixed(BasicTexture from, int to,
+ float ratio, int x, int y, int w, int h) {}
+ public void drawMixed(BasicTexture from, BasicTexture to,
+ float ratio, int x, int y, int width, int height, float alpha) {}
+ public BasicTexture copyTexture(int x, int y, int width, int height) {
+ throw new UnsupportedOperationException();
+ }
+ public GL11 getGLInstance() {
+ throw new UnsupportedOperationException();
+ }
+ public boolean unloadTexture(BasicTexture texture) {
+ throw new UnsupportedOperationException();
+ }
+ public void deleteBuffer(int bufferId) {
+ throw new UnsupportedOperationException();
+ }
+ public void deleteRecycledResources() {}
+ public void multiplyMatrix(float[] mMatrix, int offset) {}
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasTest.java b/tests/src/com/android/gallery3d/ui/GLCanvasTest.java
new file mode 100644
index 000000000..528b04f67
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLCanvasTest.java
@@ -0,0 +1,778 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+
+@SmallTest
+public class GLCanvasTest extends TestCase {
+ private static final String TAG = "GLCanvasTest";
+
+ private static GLPaint newColorPaint(int color) {
+ GLPaint paint = new GLPaint();
+ paint.setColor(color);
+ return paint;
+ }
+
+ @SmallTest
+ public void testSetSize() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+ canvas.setSize(100, 200);
+ canvas.setSize(1000, 100);
+ try {
+ canvas.setSize(-1, 100);
+ fail();
+ } catch (Throwable ex) {
+ // expected.
+ }
+ }
+
+ @SmallTest
+ public void testClearBuffer() {
+ new ClearBufferTest().run();
+ }
+
+ private static class ClearBufferTest extends GLMock {
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ assertEquals(0, mGLClearCalled);
+ canvas.clearBuffer();
+ assertEquals(GL10.GL_COLOR_BUFFER_BIT, mGLClearMask);
+ assertEquals(1, mGLClearCalled);
+ }
+ }
+
+ @SmallTest
+ public void testAnimationTime() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+
+ long[] testData = {0, 1, 2, 1000, 10000, Long.MAX_VALUE};
+
+ for (long v : testData) {
+ canvas.setCurrentAnimationTimeMillis(v);
+ assertEquals(v, canvas.currentAnimationTimeMillis());
+ }
+
+ try {
+ canvas.setCurrentAnimationTimeMillis(-1);
+ fail();
+ } catch (Throwable ex) {
+ // expected.
+ }
+ }
+
+ @SmallTest
+ public void testSetColor() {
+ new SetColorTest().run();
+ }
+
+ // This test assumes we use pre-multipled alpha blending and should
+ // set the blending function and color correctly.
+ private static class SetColorTest extends GLMock {
+ void run() {
+ int[] testColors = new int[] {
+ 0, 0xFFFFFFFF, 0xFF000000, 0x00FFFFFF, 0x80FF8001,
+ 0x7F010101, 0xFEFEFDFC, 0x017F8081, 0x027F8081, 0x2ADE4C4D
+ };
+
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+ // Test one color to make sure blend function is set.
+ assertEquals(0, mGLColorCalled);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(0x7F804020));
+ assertEquals(1, mGLColorCalled);
+ assertEquals(0x7F402010, mGLColor);
+ assertPremultipliedBlending(this);
+
+ // Test other colors to make sure premultiplication is right
+ for (int c : testColors) {
+ float a = (c >>> 24) / 255f;
+ float r = ((c >> 16) & 0xff) / 255f;
+ float g = ((c >> 8) & 0xff) / 255f;
+ float b = (c & 0xff) / 255f;
+ int pre = makeColor4f(a * r, a * g, a * b, a);
+
+ mGLColorCalled = 0;
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(c));
+ assertEquals(1, mGLColorCalled);
+ assertEquals(pre, mGLColor);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testSetGetMultiplyAlpha() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+
+ canvas.setAlpha(1f);
+ assertEquals(1f, canvas.getAlpha());
+
+ canvas.setAlpha(0f);
+ assertEquals(0f, canvas.getAlpha());
+
+ canvas.setAlpha(0.5f);
+ assertEquals(0.5f, canvas.getAlpha());
+
+ canvas.multiplyAlpha(0.5f);
+ assertEquals(0.25f, canvas.getAlpha());
+
+ canvas.multiplyAlpha(0f);
+ assertEquals(0f, canvas.getAlpha());
+
+ try {
+ canvas.setAlpha(-0.01f);
+ fail();
+ } catch (Throwable ex) {
+ // expected.
+ }
+
+ try {
+ canvas.setAlpha(1.01f);
+ fail();
+ } catch (Throwable ex) {
+ // expected.
+ }
+ }
+
+ @SmallTest
+ public void testAlpha() {
+ new AlphaTest().run();
+ }
+
+ private static class AlphaTest extends GLMock {
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+
+ assertEquals(0, mGLColorCalled);
+ canvas.setAlpha(0.48f);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(0xFF804020));
+ assertPremultipliedBlending(this);
+ assertEquals(1, mGLColorCalled);
+ assertEquals(0x7A3D1F0F, mGLColor);
+ }
+ }
+
+ @SmallTest
+ public void testDrawLine() {
+ new DrawLineTest().run();
+ }
+
+ // This test assumes the drawLine() function use glDrawArrays() with
+ // GL_LINE_STRIP mode to draw the line and the input coordinates are used
+ // directly.
+ private static class DrawLineTest extends GLMock {
+ private int mDrawArrayCalled = 0;
+ private final int[] mResult = new int[4];
+
+ @Override
+ public void glDrawArrays(int mode, int first, int count) {
+ assertNotNull(mGLVertexPointer);
+ assertEquals(GL10.GL_LINE_STRIP, mode);
+ assertEquals(2, count);
+ mGLVertexPointer.bindByteBuffer();
+
+ double[] coord = new double[4];
+ mGLVertexPointer.getArrayElement(first, coord);
+ mResult[0] = (int) coord[0];
+ mResult[1] = (int) coord[1];
+ mGLVertexPointer.getArrayElement(first + 1, coord);
+ mResult[2] = (int) coord[0];
+ mResult[3] = (int) coord[1];
+ mDrawArrayCalled++;
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+ canvas.drawLine(2, 7, 1, 8, newColorPaint(0) /* color */);
+ assertTrue(mGLVertexArrayEnabled);
+ assertEquals(1, mDrawArrayCalled);
+
+ Log.v(TAG, "result = " + Arrays.toString(mResult));
+ int[] answer = new int[] {2, 7, 1, 8};
+ for (int i = 0; i < answer.length; i++) {
+ assertEquals(answer[i], mResult[i]);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testFillRect() {
+ new FillRectTest().run();
+ }
+
+ // This test assumes the drawLine() function use glDrawArrays() with
+ // GL_TRIANGLE_STRIP mode to draw the line and the input coordinates
+ // are used directly.
+ private static class FillRectTest extends GLMock {
+ private int mDrawArrayCalled = 0;
+ private final int[] mResult = new int[8];
+
+ @Override
+ public void glDrawArrays(int mode, int first, int count) {
+ assertNotNull(mGLVertexPointer);
+ assertEquals(GL10.GL_TRIANGLE_STRIP, mode);
+ assertEquals(4, count);
+ mGLVertexPointer.bindByteBuffer();
+
+ double[] coord = new double[4];
+ for (int i = 0; i < 4; i++) {
+ mGLVertexPointer.getArrayElement(first + i, coord);
+ mResult[i * 2 + 0] = (int) coord[0];
+ mResult[i * 2 + 1] = (int) coord[1];
+ }
+
+ mDrawArrayCalled++;
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+ canvas.fillRect(2, 7, 1, 8, 0 /* color */);
+ assertTrue(mGLVertexArrayEnabled);
+ assertEquals(1, mDrawArrayCalled);
+ Log.v(TAG, "result = " + Arrays.toString(mResult));
+
+ // These are the four vertics that should be used.
+ int[] answer = new int[] {
+ 2, 7,
+ 3, 7,
+ 3, 15,
+ 2, 15};
+ int count[] = new int[4];
+
+ // Count the number of appearances for each vertex.
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (answer[i * 2] == mResult[j * 2] &&
+ answer[i * 2 + 1] == mResult[j * 2 + 1]) {
+ count[i]++;
+ }
+ }
+ }
+
+ // Each vertex should appear exactly once.
+ for (int i = 0; i < 4; i++) {
+ assertEquals(1, count[i]);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testTransform() {
+ new TransformTest().run();
+ }
+
+ // This test assumes glLoadMatrixf is used to load the model view matrix,
+ // and glOrthof is used to load the projection matrix.
+ //
+ // The projection matrix is set to an orthogonal projection which is the
+ // inverse of viewport transform. So the model view matrix maps input
+ // directly to screen coordinates (default no scaling, and the y-axis is
+ // reversed).
+ //
+ // The matrix here are all listed in column major order.
+ //
+ private static class TransformTest extends GLMock {
+ private final float[] mModelViewMatrixUsed = new float[16];
+ private final float[] mProjectionMatrixUsed = new float[16];
+
+ @Override
+ public void glDrawArrays(int mode, int first, int count) {
+ copy(mModelViewMatrixUsed, mGLModelViewMatrix);
+ copy(mProjectionMatrixUsed, mGLProjectionMatrix);
+ }
+
+ private void copy(float[] dest, float[] src) {
+ System.arraycopy(src, 0, dest, 0, 16);
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(40, 50);
+ int color = 0;
+
+ // Initial matrix
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(color));
+ assertMatrixEq(new float[] {
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 50, 0, 1
+ }, mModelViewMatrixUsed);
+
+ assertMatrixEq(new float[] {
+ 2f / 40, 0, 0, 0,
+ 0, 2f / 50, 0, 0,
+ 0, 0, -1, 0,
+ -1, -1, 0, 1
+ }, mProjectionMatrixUsed);
+
+ // Translation
+ canvas.translate(3, 4, 5);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(color));
+ assertMatrixEq(new float[] {
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 3, 46, 5, 1
+ }, mModelViewMatrixUsed);
+ canvas.save();
+
+ // Scaling
+ canvas.scale(0.7f, 0.6f, 0.5f);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(color));
+ assertMatrixEq(new float[] {
+ 0.7f, 0, 0, 0,
+ 0, -0.6f, 0, 0,
+ 0, 0, 0.5f, 0,
+ 3, 46, 5, 1
+ }, mModelViewMatrixUsed);
+
+ // Rotation
+ canvas.rotate(90, 0, 0, 1);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(color));
+ assertMatrixEq(new float[] {
+ 0, -0.6f, 0, 0,
+ -0.7f, 0, 0, 0,
+ 0, 0, 0.5f, 0,
+ 3, 46, 5, 1
+ }, mModelViewMatrixUsed);
+ canvas.restore();
+
+ // After restoring to the point just after translation,
+ // do rotation again.
+ canvas.rotate(180, 1, 0, 0);
+ canvas.drawLine(0, 0, 1, 1, newColorPaint(color));
+ assertMatrixEq(new float[] {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, -1, 0,
+ 3, 46, 5, 1
+ }, mModelViewMatrixUsed);
+ }
+ }
+
+ @SmallTest
+ public void testClipRect() {
+ // The test is currently broken, waiting for the fix
+ // new ClipRectTest().run();
+ }
+
+ private static class ClipRectTest extends GLStub {
+ int mX, mY, mWidth, mHeight;
+
+ @Override
+ public void glScissor(int x, int y, int width, int height) {
+ mX = x;
+ mY = 100 - y - height; // flip in Y direction
+ mWidth = width;
+ mHeight = height;
+ }
+
+ private void assertClipRect(int x, int y, int width, int height) {
+ assertEquals(x, mX);
+ assertEquals(y, mY);
+ assertEquals(width, mWidth);
+ assertEquals(height, mHeight);
+ }
+
+ private void assertEmptyClipRect() {
+ assertEquals(0, mWidth);
+ assertEquals(0, mHeight);
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(100, 100);
+ canvas.save();
+ assertClipRect(0, 0, 100, 100);
+
+ assertTrue(canvas.clipRect(10, 10, 70, 70));
+ canvas.save();
+ assertClipRect(10, 10, 60, 60);
+
+ assertTrue(canvas.clipRect(30, 30, 90, 90));
+ canvas.save();
+ assertClipRect(30, 30, 40, 40);
+
+ assertTrue(canvas.clipRect(40, 40, 60, 90));
+ assertClipRect(40, 40, 20, 30);
+
+ assertFalse(canvas.clipRect(30, 30, 70, 40));
+ assertEmptyClipRect();
+ assertFalse(canvas.clipRect(0, 0, 100, 100));
+ assertEmptyClipRect();
+
+ canvas.restore();
+ assertClipRect(30, 30, 40, 40);
+
+ canvas.restore();
+ assertClipRect(10, 10, 60, 60);
+
+ canvas.restore();
+ assertClipRect(0, 0, 100, 100);
+
+ canvas.translate(10, 20, 30);
+ assertTrue(canvas.clipRect(10, 10, 70, 70));
+ canvas.save();
+ assertClipRect(20, 30, 60, 60);
+ }
+ }
+
+ @SmallTest
+ public void testSaveRestore() {
+ new SaveRestoreTest().run();
+ }
+
+ private static class SaveRestoreTest extends GLStub {
+ int mX, mY, mWidth, mHeight;
+
+ @Override
+ public void glScissor(int x, int y, int width, int height) {
+ mX = x;
+ mY = 100 - y - height; // flip in Y direction
+ mWidth = width;
+ mHeight = height;
+ }
+
+ private void assertClipRect(int x, int y, int width, int height) {
+ assertEquals(x, mX);
+ assertEquals(y, mY);
+ assertEquals(width, mWidth);
+ assertEquals(height, mHeight);
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(100, 100);
+
+ canvas.setAlpha(0.7f);
+ assertTrue(canvas.clipRect(10, 10, 70, 70));
+
+ canvas.save(canvas.SAVE_FLAG_CLIP);
+ canvas.setAlpha(0.6f);
+ assertTrue(canvas.clipRect(30, 30, 90, 90));
+
+ canvas.save(canvas.SAVE_FLAG_CLIP | canvas.SAVE_FLAG_ALPHA);
+ canvas.setAlpha(0.5f);
+ assertTrue(canvas.clipRect(40, 40, 60, 90));
+
+ assertEquals(0.5f, canvas.getAlpha());
+ assertClipRect(40, 40, 20, 30);
+
+ canvas.restore(); // now both clipping rect and alpha are restored.
+ assertEquals(0.6f, canvas.getAlpha());
+ assertClipRect(30, 30, 40, 40);
+
+ canvas.restore(); // now only clipping rect is restored.
+
+ canvas.save(0);
+ canvas.save(0);
+ canvas.restore();
+ canvas.restore();
+
+ assertEquals(0.6f, canvas.getAlpha());
+ assertTrue(canvas.clipRect(10, 10, 60, 60));
+ }
+ }
+
+ @SmallTest
+ public void testDrawTexture() {
+ new DrawTextureTest().run();
+ new DrawTextureMixedTest().run();
+ }
+
+ private static class MyTexture extends BasicTexture {
+ boolean mIsOpaque;
+ int mBindCalled;
+
+ MyTexture(GLCanvas canvas, int id, boolean isOpaque) {
+ super(canvas, id, STATE_LOADED);
+ setSize(1, 1);
+ mIsOpaque = isOpaque;
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ mBindCalled++;
+ return true;
+ }
+
+ public boolean isOpaque() {
+ return mIsOpaque;
+ }
+ }
+
+ private static class DrawTextureTest extends GLMock {
+ int mDrawTexiOESCalled;
+ int mDrawArrayCalled;
+ int[] mResult = new int[4];
+
+ @Override
+ public void glDrawTexiOES(int x, int y, int z,
+ int width, int height) {
+ mDrawTexiOESCalled++;
+ }
+
+ @Override
+ public void glDrawArrays(int mode, int first, int count) {
+ assertNotNull(mGLVertexPointer);
+ assertEquals(GL10.GL_TRIANGLE_STRIP, mode);
+ assertEquals(4, count);
+ mGLVertexPointer.bindByteBuffer();
+
+ double[] coord = new double[4];
+ mGLVertexPointer.getArrayElement(first, coord);
+ mResult[0] = (int) coord[0];
+ mResult[1] = (int) coord[1];
+ mGLVertexPointer.getArrayElement(first + 1, coord);
+ mResult[2] = (int) coord[0];
+ mResult[3] = (int) coord[1];
+ mDrawArrayCalled++;
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+ MyTexture texture = new MyTexture(canvas, 42, false); // non-opaque
+ MyTexture texture_o = new MyTexture(canvas, 47, true); // opaque
+
+ // Draw a non-opaque texture
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(42, mGLBindTextureId);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertPremultipliedBlending(this);
+ assertFalse(mGLStencilEnabled);
+
+ // Draw an opaque texture
+ canvas.drawTexture(texture_o, 100, 200, 300, 400);
+ assertEquals(47, mGLBindTextureId);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertFalse(mGLBlendEnabled);
+
+ // Draw a non-opaque texture with alpha = 0.5
+ canvas.setAlpha(0.5f);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(42, mGLBindTextureId);
+ assertEquals(0x80808080, mGLColor);
+ assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertPremultipliedBlending(this);
+ assertFalse(mGLStencilEnabled);
+
+ // Draw an non-opaque texture with overriden alpha = 1
+ canvas.drawTexture(texture, 100, 200, 300, 400, 1f);
+ assertEquals(42, mGLBindTextureId);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertPremultipliedBlending(this);
+
+ // Draw an opaque texture with overriden alpha = 1
+ canvas.drawTexture(texture_o, 100, 200, 300, 400, 1f);
+ assertEquals(47, mGLBindTextureId);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertFalse(mGLBlendEnabled);
+
+ // Draw an opaque texture with overridden alpha = 0.25
+ canvas.drawTexture(texture_o, 100, 200, 300, 400, 0.25f);
+ assertEquals(47, mGLBindTextureId);
+ assertEquals(0x40404040, mGLColor);
+ assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertPremultipliedBlending(this);
+
+ // Draw an opaque texture with overridden alpha = 0.125
+ // but with some rotation so it will use DrawArray.
+ canvas.save();
+ canvas.rotate(30, 0, 0, 1);
+ canvas.drawTexture(texture_o, 100, 200, 300, 400, 0.125f);
+ canvas.restore();
+ assertEquals(47, mGLBindTextureId);
+ assertEquals(0x20202020, mGLColor);
+ assertEquals(GL_MODULATE, getTexEnvi(GL_TEXTURE_ENV_MODE));
+ assertPremultipliedBlending(this);
+
+ // We have drawn seven textures above.
+ assertEquals(1, mDrawArrayCalled);
+ assertEquals(6, mDrawTexiOESCalled);
+
+ // translate and scale does not affect whether we
+ // can use glDrawTexiOES, but rotate may.
+ canvas.translate(10, 20, 30);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(7, mDrawTexiOESCalled);
+
+ canvas.scale(10, 20, 30);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(8, mDrawTexiOESCalled);
+
+ canvas.rotate(90, 1, 2, 3);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(8, mDrawTexiOESCalled);
+
+ canvas.rotate(-90, 1, 2, 3);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(9, mDrawTexiOESCalled);
+
+ canvas.rotate(180, 0, 0, 1);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(9, mDrawTexiOESCalled);
+
+ canvas.rotate(180, 0, 0, 1);
+ canvas.drawTexture(texture, 100, 200, 300, 400);
+ assertEquals(10, mDrawTexiOESCalled);
+
+ assertEquals(3, mDrawArrayCalled);
+
+ assertTrue(texture.isLoaded(canvas));
+ texture.recycle();
+ assertFalse(texture.isLoaded(canvas));
+ canvas.deleteRecycledResources();
+
+ assertTrue(texture_o.isLoaded(canvas));
+ texture_o.recycle();
+ assertFalse(texture_o.isLoaded(canvas));
+ }
+ }
+
+ private static class DrawTextureMixedTest extends GLMock {
+
+ boolean mTexture2DEnabled0, mTexture2DEnabled1;
+ int mBindTexture0;
+ int mBindTexture1;
+
+ @Override
+ public void glEnable(int cap) {
+ if (cap == GL_TEXTURE_2D) {
+ texture2DEnable(true);
+ }
+ }
+
+ @Override
+ public void glDisable(int cap) {
+ if (cap == GL_TEXTURE_2D) {
+ texture2DEnable(false);
+ }
+ }
+
+ private void texture2DEnable(boolean enable) {
+ if (mGLActiveTexture == GL_TEXTURE0) {
+ mTexture2DEnabled0 = enable;
+ } else if (mGLActiveTexture == GL_TEXTURE1) {
+ mTexture2DEnabled1 = enable;
+ } else {
+ fail();
+ }
+ }
+
+ @Override
+ public void glTexEnvfv(int target, int pname, float[] params, int offset) {
+ if (target == GL_TEXTURE_ENV && pname == GL_TEXTURE_ENV_COLOR) {
+ assertEquals(0.5f, params[offset + 3]);
+ }
+ }
+
+ @Override
+ public void glBindTexture(int target, int texture) {
+ if (target == GL_TEXTURE_2D) {
+ if (mGLActiveTexture == GL_TEXTURE0) {
+ mBindTexture0 = texture;
+ } else if (mGLActiveTexture == GL_TEXTURE1) {
+ mBindTexture1 = texture;
+ } else {
+ fail();
+ }
+ }
+ }
+
+ void run() {
+ GLCanvas canvas = new GLCanvasImpl(this);
+ canvas.setSize(400, 300);
+ MyTexture from = new MyTexture(canvas, 42, false); // non-opaque
+ MyTexture to = new MyTexture(canvas, 47, true); // opaque
+
+ canvas.drawMixed(from, to, 0.5f, 100, 200, 300, 400);
+ assertEquals(42, mBindTexture0);
+ assertEquals(47, mBindTexture1);
+ assertTrue(mTexture2DEnabled0);
+ assertFalse(mTexture2DEnabled1);
+
+ assertEquals(GL_COMBINE, getTexEnvi(GL_TEXTURE1, GL_TEXTURE_ENV_MODE));
+ assertEquals(GL_INTERPOLATE, getTexEnvi(GL_TEXTURE1, GL_COMBINE_RGB));
+ assertEquals(GL_INTERPOLATE, getTexEnvi(GL_TEXTURE1, GL_COMBINE_ALPHA));
+ assertEquals(GL_CONSTANT, getTexEnvi(GL_TEXTURE1, GL_SRC2_RGB));
+ assertEquals(GL_CONSTANT, getTexEnvi(GL_TEXTURE1, GL_SRC2_ALPHA));
+ assertEquals(GL_SRC_ALPHA, getTexEnvi(GL_TEXTURE1, GL_OPERAND2_RGB));
+ assertEquals(GL_SRC_ALPHA, getTexEnvi(GL_TEXTURE1, GL_OPERAND2_ALPHA));
+
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE));
+
+ assertFalse(mGLBlendEnabled);
+
+ canvas.drawMixed(from, to, 0, 100, 200, 300, 400);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE));
+ assertEquals(42, mBindTexture0);
+
+ canvas.drawMixed(from, to, 1, 100, 200, 300, 400);
+ assertEquals(GL_REPLACE, getTexEnvi(GL_TEXTURE0, GL_TEXTURE_ENV_MODE));
+ assertEquals(47, mBindTexture0);
+ }
+ }
+
+ @SmallTest
+ public void testGetGLInstance() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+ assertSame(glStub, canvas.getGLInstance());
+ }
+
+ private static void assertPremultipliedBlending(GLMock mock) {
+ assertTrue(mock.mGLBlendFuncCalled > 0);
+ assertTrue(mock.mGLBlendEnabled);
+ assertEquals(GL11.GL_ONE, mock.mGLBlendFuncSFactor);
+ assertEquals(GL11.GL_ONE_MINUS_SRC_ALPHA, mock.mGLBlendFuncDFactor);
+ }
+
+ private static void assertMatrixEq(float[] expected, float[] actual) {
+ try {
+ for (int i = 0; i < 16; i++) {
+ assertFloatEq(expected[i], actual[i]);
+ }
+ } catch (Throwable t) {
+ Log.v(TAG, "expected = " + Arrays.toString(expected) +
+ ", actual = " + Arrays.toString(actual));
+ fail();
+ }
+ }
+
+ public static void assertFloatEq(float expected, float actual) {
+ if (Math.abs(actual - expected) > 1e-6) {
+ Log.v(TAG, "expected: " + expected + ", actual: " + actual);
+ fail();
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLMock.java b/tests/src/com/android/gallery3d/ui/GLMock.java
new file mode 100644
index 000000000..c1fe53c62
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLMock.java
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import java.nio.Buffer;
+import java.util.HashMap;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL11;
+
+public class GLMock extends GLStub {
+ @SuppressWarnings("unused")
+ private static final String TAG = "GLMock";
+
+ // glClear
+ int mGLClearCalled;
+ int mGLClearMask;
+ // glBlendFunc
+ int mGLBlendFuncCalled;
+ int mGLBlendFuncSFactor;
+ int mGLBlendFuncDFactor;
+ // glColor4[fx]
+ int mGLColorCalled;
+ int mGLColor;
+ // glEnable, glDisable
+ boolean mGLBlendEnabled;
+ boolean mGLStencilEnabled;
+ // glEnableClientState
+ boolean mGLVertexArrayEnabled;
+ // glVertexPointer
+ PointerInfo mGLVertexPointer;
+ // glMatrixMode
+ int mGLMatrixMode = GL10.GL_MODELVIEW;
+ // glLoadMatrixf
+ float[] mGLModelViewMatrix = new float[16];
+ float[] mGLProjectionMatrix = new float[16];
+ // glBindTexture
+ int mGLBindTextureId;
+ // glTexEnvf
+ HashMap<Integer, Float> mGLTexEnv0 = new HashMap<Integer, Float>();
+ HashMap<Integer, Float> mGLTexEnv1 = new HashMap<Integer, Float>();
+ // glActiveTexture
+ int mGLActiveTexture = GL11.GL_TEXTURE0;
+
+ @Override
+ public void glClear(int mask) {
+ mGLClearCalled++;
+ mGLClearMask = mask;
+ }
+
+ @Override
+ public void glBlendFunc(int sfactor, int dfactor) {
+ mGLBlendFuncSFactor = sfactor;
+ mGLBlendFuncDFactor = dfactor;
+ mGLBlendFuncCalled++;
+ }
+
+ @Override
+ public void glColor4f(float red, float green, float blue,
+ float alpha) {
+ mGLColorCalled++;
+ mGLColor = makeColor4f(red, green, blue, alpha);
+ }
+
+ @Override
+ public void glColor4x(int red, int green, int blue, int alpha) {
+ mGLColorCalled++;
+ mGLColor = makeColor4x(red, green, blue, alpha);
+ }
+
+ @Override
+ public void glEnable(int cap) {
+ if (cap == GL11.GL_BLEND) {
+ mGLBlendEnabled = true;
+ } else if (cap == GL11.GL_STENCIL_TEST) {
+ mGLStencilEnabled = true;
+ }
+ }
+
+ @Override
+ public void glDisable(int cap) {
+ if (cap == GL11.GL_BLEND) {
+ mGLBlendEnabled = false;
+ } else if (cap == GL11.GL_STENCIL_TEST) {
+ mGLStencilEnabled = false;
+ }
+ }
+
+ @Override
+ public void glEnableClientState(int array) {
+ if (array == GL10.GL_VERTEX_ARRAY) {
+ mGLVertexArrayEnabled = true;
+ }
+ }
+
+ @Override
+ public void glVertexPointer(int size, int type, int stride, Buffer pointer) {
+ mGLVertexPointer = new PointerInfo(size, type, stride, pointer);
+ }
+
+ @Override
+ public void glMatrixMode(int mode) {
+ mGLMatrixMode = mode;
+ }
+
+ @Override
+ public void glLoadMatrixf(float[] m, int offset) {
+ if (mGLMatrixMode == GL10.GL_MODELVIEW) {
+ System.arraycopy(m, offset, mGLModelViewMatrix, 0, 16);
+ } else if (mGLMatrixMode == GL10.GL_PROJECTION) {
+ System.arraycopy(m, offset, mGLProjectionMatrix, 0, 16);
+ }
+ }
+
+ @Override
+ public void glOrthof(
+ float left, float right, float bottom, float top,
+ float zNear, float zFar) {
+ float tx = -(right + left) / (right - left);
+ float ty = -(top + bottom) / (top - bottom);
+ float tz = - (zFar + zNear) / (zFar - zNear);
+ float[] m = new float[] {
+ 2 / (right - left), 0, 0, 0,
+ 0, 2 / (top - bottom), 0, 0,
+ 0, 0, -2 / (zFar - zNear), 0,
+ tx, ty, tz, 1
+ };
+ glLoadMatrixf(m, 0);
+ }
+
+ @Override
+ public void glBindTexture(int target, int texture) {
+ if (target == GL11.GL_TEXTURE_2D) {
+ mGLBindTextureId = texture;
+ }
+ }
+
+ @Override
+ public void glTexEnvf(int target, int pname, float param) {
+ if (target == GL11.GL_TEXTURE_ENV) {
+ if (mGLActiveTexture == GL11.GL_TEXTURE0) {
+ mGLTexEnv0.put(pname, param);
+ } else if (mGLActiveTexture == GL11.GL_TEXTURE1) {
+ mGLTexEnv1.put(pname, param);
+ } else {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ public int getTexEnvi(int pname) {
+ return getTexEnvi(mGLActiveTexture, pname);
+ }
+
+ public int getTexEnvi(int activeTexture, int pname) {
+ if (activeTexture == GL11.GL_TEXTURE0) {
+ return (int) mGLTexEnv0.get(pname).floatValue();
+ } else if (activeTexture == GL11.GL_TEXTURE1) {
+ return (int) mGLTexEnv1.get(pname).floatValue();
+ } else {
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public void glActiveTexture(int texture) {
+ mGLActiveTexture = texture;
+ }
+
+ public static int makeColor4f(float red, float green, float blue,
+ float alpha) {
+ return (Math.round(alpha * 255) << 24) |
+ (Math.round(red * 255) << 16) |
+ (Math.round(green * 255) << 8) |
+ Math.round(blue * 255);
+ }
+
+ public static int makeColor4x(int red, int green, int blue, int alpha) {
+ final float X = 65536f;
+ return makeColor4f(red / X, green / X, blue / X, alpha / X);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLRootMock.java b/tests/src/com/android/gallery3d/ui/GLRootMock.java
new file mode 100644
index 000000000..c83e94342
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLRootMock.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import com.android.gallery3d.anim.CanvasAnimation;
+
+public class GLRootMock implements GLRoot {
+ int mRequestRenderCalled;
+ int mRequestLayoutContentPaneCalled;
+
+ public void addOnGLIdleListener(OnGLIdleListener listener) {}
+ public void registerLaunchedAnimation(CanvasAnimation animation) {}
+ public void requestRender() {
+ mRequestRenderCalled++;
+ }
+ public void requestLayoutContentPane() {
+ mRequestLayoutContentPaneCalled++;
+ }
+ public boolean hasStencil() { return true; }
+ public void lockRenderThread() {}
+ public void unlockRenderThread() {}
+ public void setContentPane(GLView content) {}
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLRootStub.java b/tests/src/com/android/gallery3d/ui/GLRootStub.java
new file mode 100644
index 000000000..d6bc678d4
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLRootStub.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import com.android.gallery3d.anim.CanvasAnimation;
+
+public class GLRootStub implements GLRoot {
+ public void addOnGLIdleListener(OnGLIdleListener listener) {}
+ public void registerLaunchedAnimation(CanvasAnimation animation) {}
+ public void requestRender() {}
+ public void requestLayoutContentPane() {}
+ public boolean hasStencil() { return true; }
+ public void lockRenderThread() {}
+ public void unlockRenderThread() {}
+ public void setContentPane(GLView content) {}
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLStub.java b/tests/src/com/android/gallery3d/ui/GLStub.java
new file mode 100644
index 000000000..2af73f905
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLStub.java
@@ -0,0 +1,1490 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.opengles.GL10Ext;
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11Ext;
+
+public class GLStub implements GL, GL10, GL10Ext, GL11, GL11Ext {
+ @SuppressWarnings("unused")
+ private static final String TAG = "GLStub";
+
+ public void glActiveTexture(
+ int texture
+ ){}
+
+ public void glAlphaFunc(
+ int func,
+ float ref
+ ){}
+
+ public void glAlphaFuncx(
+ int func,
+ int ref
+ ){}
+
+ public void glBindTexture(
+ int target,
+ int texture
+ ){}
+
+ public void glBlendFunc(
+ int sfactor,
+ int dfactor
+ ){}
+
+ public void glClear(
+ int mask
+ ){}
+
+ public void glClearColor(
+ float red,
+ float green,
+ float blue,
+ float alpha
+ ){}
+
+ public void glClearColorx(
+ int red,
+ int green,
+ int blue,
+ int alpha
+ ){}
+
+ public void glClearDepthf(
+ float depth
+ ){}
+
+ public void glClearDepthx(
+ int depth
+ ){}
+
+ public void glClearStencil(
+ int s
+ ){}
+
+ public void glClientActiveTexture(
+ int texture
+ ){}
+
+ public void glColor4f(
+ float red,
+ float green,
+ float blue,
+ float alpha
+ ){}
+
+ public void glColor4x(
+ int red,
+ int green,
+ int blue,
+ int alpha
+ ){}
+
+ public void glColorMask(
+ boolean red,
+ boolean green,
+ boolean blue,
+ boolean alpha
+ ){}
+
+ public void glColorPointer(
+ int size,
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glCompressedTexImage2D(
+ int target,
+ int level,
+ int internalformat,
+ int width,
+ int height,
+ int border,
+ int imageSize,
+ java.nio.Buffer data
+ ){}
+
+ public void glCompressedTexSubImage2D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int width,
+ int height,
+ int format,
+ int imageSize,
+ java.nio.Buffer data
+ ){}
+
+ public void glCopyTexImage2D(
+ int target,
+ int level,
+ int internalformat,
+ int x,
+ int y,
+ int width,
+ int height,
+ int border
+ ){}
+
+ public void glCopyTexSubImage2D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int x,
+ int y,
+ int width,
+ int height
+ ){}
+
+ public void glCullFace(
+ int mode
+ ){}
+
+ public void glDeleteTextures(
+ int n,
+ int[] textures,
+ int offset
+ ){}
+
+ public void glDeleteTextures(
+ int n,
+ java.nio.IntBuffer textures
+ ){}
+
+ public void glDepthFunc(
+ int func
+ ){}
+
+ public void glDepthMask(
+ boolean flag
+ ){}
+
+ public void glDepthRangef(
+ float zNear,
+ float zFar
+ ){}
+
+ public void glDepthRangex(
+ int zNear,
+ int zFar
+ ){}
+
+ public void glDisable(
+ int cap
+ ){}
+
+ public void glDisableClientState(
+ int array
+ ){}
+
+ public void glDrawArrays(
+ int mode,
+ int first,
+ int count
+ ){}
+
+ public void glDrawElements(
+ int mode,
+ int count,
+ int type,
+ java.nio.Buffer indices
+ ){}
+
+ public void glEnable(
+ int cap
+ ){}
+
+ public void glEnableClientState(
+ int array
+ ){}
+
+ public void glFinish(
+ ){}
+
+ public void glFlush(
+ ){}
+
+ public void glFogf(
+ int pname,
+ float param
+ ){}
+
+ public void glFogfv(
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glFogfv(
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glFogx(
+ int pname,
+ int param
+ ){}
+
+ public void glFogxv(
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glFogxv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glFrontFace(
+ int mode
+ ){}
+
+ public void glFrustumf(
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float zNear,
+ float zFar
+ ){}
+
+ public void glFrustumx(
+ int left,
+ int right,
+ int bottom,
+ int top,
+ int zNear,
+ int zFar
+ ){}
+
+ public void glGenTextures(
+ int n,
+ int[] textures,
+ int offset
+ ){}
+
+ public void glGenTextures(
+ int n,
+ java.nio.IntBuffer textures
+ ){}
+
+ public int glGetError(
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glGetIntegerv(
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetIntegerv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public String glGetString(
+ int name
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glHint(
+ int target,
+ int mode
+ ){}
+
+ public void glLightModelf(
+ int pname,
+ float param
+ ){}
+
+ public void glLightModelfv(
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glLightModelfv(
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glLightModelx(
+ int pname,
+ int param
+ ){}
+
+ public void glLightModelxv(
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glLightModelxv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glLightf(
+ int light,
+ int pname,
+ float param
+ ){}
+
+ public void glLightfv(
+ int light,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glLightfv(
+ int light,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glLightx(
+ int light,
+ int pname,
+ int param
+ ){}
+
+ public void glLightxv(
+ int light,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glLightxv(
+ int light,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glLineWidth(
+ float width
+ ){}
+
+ public void glLineWidthx(
+ int width
+ ){}
+
+ public void glLoadIdentity(
+ ){}
+
+ public void glLoadMatrixf(
+ float[] m,
+ int offset
+ ){}
+
+ public void glLoadMatrixf(
+ java.nio.FloatBuffer m
+ ){}
+
+ public void glLoadMatrixx(
+ int[] m,
+ int offset
+ ){}
+
+ public void glLoadMatrixx(
+ java.nio.IntBuffer m
+ ){}
+
+ public void glLogicOp(
+ int opcode
+ ){}
+
+ public void glMaterialf(
+ int face,
+ int pname,
+ float param
+ ){}
+
+ public void glMaterialfv(
+ int face,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glMaterialfv(
+ int face,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glMaterialx(
+ int face,
+ int pname,
+ int param
+ ){}
+
+ public void glMaterialxv(
+ int face,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glMaterialxv(
+ int face,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glMatrixMode(
+ int mode
+ ){}
+
+ public void glMultMatrixf(
+ float[] m,
+ int offset
+ ){}
+
+ public void glMultMatrixf(
+ java.nio.FloatBuffer m
+ ){}
+
+ public void glMultMatrixx(
+ int[] m,
+ int offset
+ ){}
+
+ public void glMultMatrixx(
+ java.nio.IntBuffer m
+ ){}
+
+ public void glMultiTexCoord4f(
+ int target,
+ float s,
+ float t,
+ float r,
+ float q
+ ){}
+
+ public void glMultiTexCoord4x(
+ int target,
+ int s,
+ int t,
+ int r,
+ int q
+ ){}
+
+ public void glNormal3f(
+ float nx,
+ float ny,
+ float nz
+ ){}
+
+ public void glNormal3x(
+ int nx,
+ int ny,
+ int nz
+ ){}
+
+ public void glNormalPointer(
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glOrthof(
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float zNear,
+ float zFar
+ ){}
+
+ public void glOrthox(
+ int left,
+ int right,
+ int bottom,
+ int top,
+ int zNear,
+ int zFar
+ ){}
+
+ public void glPixelStorei(
+ int pname,
+ int param
+ ){}
+
+ public void glPointSize(
+ float size
+ ){}
+
+ public void glPointSizex(
+ int size
+ ){}
+
+ public void glPolygonOffset(
+ float factor,
+ float units
+ ){}
+
+ public void glPolygonOffsetx(
+ int factor,
+ int units
+ ){}
+
+ public void glPopMatrix(
+ ){}
+
+ public void glPushMatrix(
+ ){}
+
+ public void glReadPixels(
+ int x,
+ int y,
+ int width,
+ int height,
+ int format,
+ int type,
+ java.nio.Buffer pixels
+ ){}
+
+ public void glRotatef(
+ float angle,
+ float x,
+ float y,
+ float z
+ ){}
+
+ public void glRotatex(
+ int angle,
+ int x,
+ int y,
+ int z
+ ){}
+
+ public void glSampleCoverage(
+ float value,
+ boolean invert
+ ){}
+
+ public void glSampleCoveragex(
+ int value,
+ boolean invert
+ ){}
+
+ public void glScalef(
+ float x,
+ float y,
+ float z
+ ){}
+
+ public void glScalex(
+ int x,
+ int y,
+ int z
+ ){}
+
+ public void glScissor(
+ int x,
+ int y,
+ int width,
+ int height
+ ){}
+
+ public void glShadeModel(
+ int mode
+ ){}
+
+ public void glStencilFunc(
+ int func,
+ int ref,
+ int mask
+ ){}
+
+ public void glStencilMask(
+ int mask
+ ){}
+
+ public void glStencilOp(
+ int fail,
+ int zfail,
+ int zpass
+ ){}
+
+ public void glTexCoordPointer(
+ int size,
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glTexEnvf(
+ int target,
+ int pname,
+ float param
+ ){}
+
+ public void glTexEnvfv(
+ int target,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glTexEnvfv(
+ int target,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glTexEnvx(
+ int target,
+ int pname,
+ int param
+ ){}
+
+ public void glTexEnvxv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexEnvxv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glTexImage2D(
+ int target,
+ int level,
+ int internalformat,
+ int width,
+ int height,
+ int border,
+ int format,
+ int type,
+ java.nio.Buffer pixels
+ ){}
+
+ public void glTexParameterf(
+ int target,
+ int pname,
+ float param
+ ){}
+
+ public void glTexParameterx(
+ int target,
+ int pname,
+ int param
+ ){}
+
+ public void glTexSubImage2D(
+ int target,
+ int level,
+ int xoffset,
+ int yoffset,
+ int width,
+ int height,
+ int format,
+ int type,
+ java.nio.Buffer pixels
+ ){}
+
+ public void glTranslatef(
+ float x,
+ float y,
+ float z
+ ){}
+
+ public void glTranslatex(
+ int x,
+ int y,
+ int z
+ ){}
+
+ public void glVertexPointer(
+ int size,
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glViewport(
+ int x,
+ int y,
+ int width,
+ int height
+ ){}
+
+ public int glQueryMatrixxOES(
+ int[] mantissa,
+ int mantissaOffset,
+ int[] exponent,
+ int exponentOffset
+ ){ throw new UnsupportedOperationException(); }
+
+ public int glQueryMatrixxOES(
+ java.nio.IntBuffer mantissa,
+ java.nio.IntBuffer exponent
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glGetPointerv(int pname, java.nio.Buffer[] params){}
+ public void glBindBuffer(
+ int target,
+ int buffer
+ ){}
+
+ public void glBufferData(
+ int target,
+ int size,
+ java.nio.Buffer data,
+ int usage
+ ){}
+
+ public void glBufferSubData(
+ int target,
+ int offset,
+ int size,
+ java.nio.Buffer data
+ ){}
+
+ public void glClipPlanef(
+ int plane,
+ float[] equation,
+ int offset
+ ){}
+
+ public void glClipPlanef(
+ int plane,
+ java.nio.FloatBuffer equation
+ ){}
+
+ public void glClipPlanex(
+ int plane,
+ int[] equation,
+ int offset
+ ){}
+
+ public void glClipPlanex(
+ int plane,
+ java.nio.IntBuffer equation
+ ){}
+
+ public void glColor4ub(
+ byte red,
+ byte green,
+ byte blue,
+ byte alpha
+ ){}
+
+ public void glColorPointer(
+ int size,
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glDeleteBuffers(
+ int n,
+ int[] buffers,
+ int offset
+ ){}
+
+ public void glDeleteBuffers(
+ int n,
+ java.nio.IntBuffer buffers
+ ){}
+
+ public void glDrawElements(
+ int mode,
+ int count,
+ int type,
+ int offset
+ ){}
+
+ public void glGenBuffers(
+ int n,
+ int[] buffers,
+ int offset
+ ){}
+
+ public void glGenBuffers(
+ int n,
+ java.nio.IntBuffer buffers
+ ){}
+
+ public void glGetBooleanv(
+ int pname,
+ boolean[] params,
+ int offset
+ ){}
+
+ public void glGetBooleanv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetBufferParameteriv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetBufferParameteriv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetClipPlanef(
+ int pname,
+ float[] eqn,
+ int offset
+ ){}
+
+ public void glGetClipPlanef(
+ int pname,
+ java.nio.FloatBuffer eqn
+ ){}
+
+ public void glGetClipPlanex(
+ int pname,
+ int[] eqn,
+ int offset
+ ){}
+
+ public void glGetClipPlanex(
+ int pname,
+ java.nio.IntBuffer eqn
+ ){}
+
+ public void glGetFixedv(
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetFixedv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetFloatv(
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glGetFloatv(
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glGetLightfv(
+ int light,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glGetLightfv(
+ int light,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glGetLightxv(
+ int light,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetLightxv(
+ int light,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetMaterialfv(
+ int face,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glGetMaterialfv(
+ int face,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glGetMaterialxv(
+ int face,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetMaterialxv(
+ int face,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexEnviv(
+ int env,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexEnviv(
+ int env,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexEnvxv(
+ int env,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexEnvxv(
+ int env,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexParameterfv(
+ int target,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glGetTexParameterfv(
+ int target,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glGetTexParameteriv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexParameteriv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexParameterxv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexParameterxv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public boolean glIsBuffer(
+ int buffer
+ ){ throw new UnsupportedOperationException(); }
+
+ public boolean glIsEnabled(
+ int cap
+ ){ throw new UnsupportedOperationException(); }
+
+ public boolean glIsTexture(
+ int texture
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glNormalPointer(
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glPointParameterf(
+ int pname,
+ float param
+ ){}
+
+ public void glPointParameterfv(
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glPointParameterfv(
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glPointParameterx(
+ int pname,
+ int param
+ ){}
+
+ public void glPointParameterxv(
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glPointParameterxv(
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glPointSizePointerOES(
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glTexCoordPointer(
+ int size,
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glTexEnvi(
+ int target,
+ int pname,
+ int param
+ ){}
+
+ public void glTexEnviv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexEnviv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glTexParameterfv(
+ int target,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glTexParameterfv(
+ int target,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glTexParameteri(
+ int target,
+ int pname,
+ int param
+ ){}
+
+ public void glTexParameteriv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexParameteriv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glTexParameterxv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexParameterxv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glVertexPointer(
+ int size,
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glCurrentPaletteMatrixOES(
+ int matrixpaletteindex
+ ){}
+
+ public void glDrawTexfOES(
+ float x,
+ float y,
+ float z,
+ float width,
+ float height
+ ){}
+
+ public void glDrawTexfvOES(
+ float[] coords,
+ int offset
+ ){}
+
+ public void glDrawTexfvOES(
+ java.nio.FloatBuffer coords
+ ){}
+
+ public void glDrawTexiOES(
+ int x,
+ int y,
+ int z,
+ int width,
+ int height
+ ){}
+
+ public void glDrawTexivOES(
+ int[] coords,
+ int offset
+ ){}
+
+ public void glDrawTexivOES(
+ java.nio.IntBuffer coords
+ ){}
+
+ public void glDrawTexsOES(
+ short x,
+ short y,
+ short z,
+ short width,
+ short height
+ ){}
+
+ public void glDrawTexsvOES(
+ short[] coords,
+ int offset
+ ){}
+
+ public void glDrawTexsvOES(
+ java.nio.ShortBuffer coords
+ ){}
+
+ public void glDrawTexxOES(
+ int x,
+ int y,
+ int z,
+ int width,
+ int height
+ ){}
+
+ public void glDrawTexxvOES(
+ int[] coords,
+ int offset
+ ){}
+
+ public void glDrawTexxvOES(
+ java.nio.IntBuffer coords
+ ){}
+
+ public void glLoadPaletteFromModelViewMatrixOES(
+ ){}
+
+ public void glMatrixIndexPointerOES(
+ int size,
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glMatrixIndexPointerOES(
+ int size,
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glWeightPointerOES(
+ int size,
+ int type,
+ int stride,
+ java.nio.Buffer pointer
+ ){}
+
+ public void glWeightPointerOES(
+ int size,
+ int type,
+ int stride,
+ int offset
+ ){}
+
+ public void glBindFramebufferOES(
+ int target,
+ int framebuffer
+ ){}
+
+ public void glBindRenderbufferOES(
+ int target,
+ int renderbuffer
+ ){}
+
+ public void glBlendEquation(
+ int mode
+ ){}
+
+ public void glBlendEquationSeparate(
+ int modeRGB,
+ int modeAlpha
+ ){}
+
+ public void glBlendFuncSeparate(
+ int srcRGB,
+ int dstRGB,
+ int srcAlpha,
+ int dstAlpha
+ ){}
+
+ public int glCheckFramebufferStatusOES(
+ int target
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glDeleteFramebuffersOES(
+ int n,
+ int[] framebuffers,
+ int offset
+ ){}
+
+ public void glDeleteFramebuffersOES(
+ int n,
+ java.nio.IntBuffer framebuffers
+ ){}
+
+ public void glDeleteRenderbuffersOES(
+ int n,
+ int[] renderbuffers,
+ int offset
+ ){}
+
+ public void glDeleteRenderbuffersOES(
+ int n,
+ java.nio.IntBuffer renderbuffers
+ ){}
+
+ public void glFramebufferRenderbufferOES(
+ int target,
+ int attachment,
+ int renderbuffertarget,
+ int renderbuffer
+ ){}
+
+ public void glFramebufferTexture2DOES(
+ int target,
+ int attachment,
+ int textarget,
+ int texture,
+ int level
+ ){}
+
+ public void glGenerateMipmapOES(
+ int target
+ ){}
+
+ public void glGenFramebuffersOES(
+ int n,
+ int[] framebuffers,
+ int offset
+ ){}
+
+ public void glGenFramebuffersOES(
+ int n,
+ java.nio.IntBuffer framebuffers
+ ){}
+
+ public void glGenRenderbuffersOES(
+ int n,
+ int[] renderbuffers,
+ int offset
+ ){}
+
+ public void glGenRenderbuffersOES(
+ int n,
+ java.nio.IntBuffer renderbuffers
+ ){}
+
+ public void glGetFramebufferAttachmentParameterivOES(
+ int target,
+ int attachment,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetFramebufferAttachmentParameterivOES(
+ int target,
+ int attachment,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetRenderbufferParameterivOES(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetRenderbufferParameterivOES(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexGenfv(
+ int coord,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glGetTexGenfv(
+ int coord,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glGetTexGeniv(
+ int coord,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexGeniv(
+ int coord,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glGetTexGenxv(
+ int coord,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glGetTexGenxv(
+ int coord,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public boolean glIsFramebufferOES(
+ int framebuffer
+ ){ throw new UnsupportedOperationException(); }
+
+ public boolean glIsRenderbufferOES(
+ int renderbuffer
+ ){ throw new UnsupportedOperationException(); }
+
+ public void glRenderbufferStorageOES(
+ int target,
+ int internalformat,
+ int width,
+ int height
+ ){}
+
+ public void glTexGenf(
+ int coord,
+ int pname,
+ float param
+ ){}
+
+ public void glTexGenfv(
+ int coord,
+ int pname,
+ float[] params,
+ int offset
+ ){}
+
+ public void glTexGenfv(
+ int coord,
+ int pname,
+ java.nio.FloatBuffer params
+ ){}
+
+ public void glTexGeni(
+ int coord,
+ int pname,
+ int param
+ ){}
+
+ public void glTexGeniv(
+ int coord,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexGeniv(
+ int coord,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+
+ public void glTexGenx(
+ int coord,
+ int pname,
+ int param
+ ){}
+
+ public void glTexGenxv(
+ int coord,
+ int pname,
+ int[] params,
+ int offset
+ ){}
+
+ public void glTexGenxv(
+ int coord,
+ int pname,
+ java.nio.IntBuffer params
+ ){}
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLViewMock.java b/tests/src/com/android/gallery3d/ui/GLViewMock.java
new file mode 100644
index 000000000..7b941daad
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLViewMock.java
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+class GLViewMock extends GLView {
+ // onAttachToRoot
+ int mOnAttachCalled;
+ GLRoot mRoot;
+ // onDetachFromRoot
+ int mOnDetachCalled;
+ // onVisibilityChanged
+ int mOnVisibilityChangedCalled;
+ // onLayout
+ int mOnLayoutCalled;
+ boolean mOnLayoutChangeSize;
+ // renderBackground
+ int mRenderBackgroundCalled;
+ // onMeasure
+ int mOnMeasureCalled;
+ int mOnMeasureWidthSpec;
+ int mOnMeasureHeightSpec;
+
+ @Override
+ public void onAttachToRoot(GLRoot root) {
+ mRoot = root;
+ mOnAttachCalled++;
+ super.onAttachToRoot(root);
+ }
+
+ @Override
+ public void onDetachFromRoot() {
+ mRoot = null;
+ mOnDetachCalled++;
+ super.onDetachFromRoot();
+ }
+
+ @Override
+ protected void onVisibilityChanged(int visibility) {
+ mOnVisibilityChangedCalled++;
+ }
+
+ @Override
+ protected void onLayout(boolean changeSize, int left, int top,
+ int right, int bottom) {
+ mOnLayoutCalled++;
+ mOnLayoutChangeSize = changeSize;
+ // call children's layout.
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView item = getComponent(i);
+ item.layout(left, top, right, bottom);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ mOnMeasureCalled++;
+ mOnMeasureWidthSpec = widthSpec;
+ mOnMeasureHeightSpec = heightSpec;
+ // call children's measure.
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView item = getComponent(i);
+ item.measure(widthSpec, heightSpec);
+ }
+ setMeasuredSize(widthSpec, heightSpec);
+ }
+
+ @Override
+ protected void renderBackground(GLCanvas view) {
+ mRenderBackgroundCalled++;
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/GLViewTest.java b/tests/src/com/android/gallery3d/ui/GLViewTest.java
new file mode 100644
index 000000000..a9377bfee
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/GLViewTest.java
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import android.graphics.Rect;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.MotionEvent;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class GLViewTest extends TestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = "GLViewTest";
+
+ @SmallTest
+ public void testVisibility() {
+ GLViewMock a = new GLViewMock();
+ assertEquals(GLView.VISIBLE, a.getVisibility());
+ assertEquals(0, a.mOnVisibilityChangedCalled);
+ a.setVisibility(GLView.INVISIBLE);
+ assertEquals(GLView.INVISIBLE, a.getVisibility());
+ assertEquals(1, a.mOnVisibilityChangedCalled);
+ a.setVisibility(GLView.VISIBLE);
+ assertEquals(GLView.VISIBLE, a.getVisibility());
+ assertEquals(2, a.mOnVisibilityChangedCalled);
+ }
+
+ @SmallTest
+ public void testComponents() {
+ GLView view = new GLView();
+ assertEquals(0, view.getComponentCount());
+ try {
+ view.getComponent(0);
+ fail();
+ } catch (IndexOutOfBoundsException ex) {
+ // expected
+ }
+
+ GLView x = new GLView();
+ GLView y = new GLView();
+ view.addComponent(x);
+ view.addComponent(y);
+ assertEquals(2, view.getComponentCount());
+ assertSame(x, view.getComponent(0));
+ assertSame(y, view.getComponent(1));
+ view.removeComponent(x);
+ assertSame(y, view.getComponent(0));
+ try {
+ view.getComponent(1);
+ fail();
+ } catch (IndexOutOfBoundsException ex) {
+ // expected
+ }
+ try {
+ view.addComponent(y);
+ fail();
+ } catch (IllegalStateException ex) {
+ // expected
+ }
+ view.addComponent(x);
+ view.removeAllComponents();
+ assertEquals(0, view.getComponentCount());
+ }
+
+ @SmallTest
+ public void testBounds() {
+ GLView view = new GLView();
+
+ assertEquals(0, view.getWidth());
+ assertEquals(0, view.getHeight());
+
+ Rect b = view.bounds();
+ assertEquals(0, b.left);
+ assertEquals(0, b.top);
+ assertEquals(0, b.right);
+ assertEquals(0, b.bottom);
+
+ view.layout(10, 20, 30, 100);
+ assertEquals(20, view.getWidth());
+ assertEquals(80, view.getHeight());
+
+ b = view.bounds();
+ assertEquals(10, b.left);
+ assertEquals(20, b.top);
+ assertEquals(30, b.right);
+ assertEquals(100, b.bottom);
+ }
+
+ @SmallTest
+ public void testPaddings() {
+ GLView view = new GLView();
+
+ Rect p = view.getPaddings();
+ assertEquals(0, p.left);
+ assertEquals(0, p.top);
+ assertEquals(0, p.right);
+ assertEquals(0, p.bottom);
+
+ view.setPaddings(10, 20, 30, 100);
+ p = view.getPaddings();
+ assertEquals(10, p.left);
+ assertEquals(20, p.top);
+ assertEquals(30, p.right);
+ assertEquals(100, p.bottom);
+
+ p = new Rect(11, 22, 33, 104);
+ view.setPaddings(p);
+ p = view.getPaddings();
+ assertEquals(11, p.left);
+ assertEquals(22, p.top);
+ assertEquals(33, p.right);
+ assertEquals(104, p.bottom);
+ }
+
+ @SmallTest
+ public void testParent() {
+ GLView a = new GLView();
+ GLView b = new GLView();
+ assertNull(b.mParent);
+ a.addComponent(b);
+ assertSame(a, b.mParent);
+ a.removeComponent(b);
+ assertNull(b.mParent);
+ }
+
+ @SmallTest
+ public void testRoot() {
+ GLViewMock a = new GLViewMock();
+ GLViewMock b = new GLViewMock();
+ GLRoot r = new GLRootStub();
+ GLRoot r2 = new GLRootStub();
+ a.addComponent(b);
+
+ // Attach to root r
+ assertEquals(0, a.mOnAttachCalled);
+ assertEquals(0, b.mOnAttachCalled);
+ a.attachToRoot(r);
+ assertEquals(1, a.mOnAttachCalled);
+ assertEquals(1, b.mOnAttachCalled);
+ assertSame(r, a.getGLRoot());
+ assertSame(r, b.getGLRoot());
+
+ // Detach from r
+ assertEquals(0, a.mOnDetachCalled);
+ assertEquals(0, b.mOnDetachCalled);
+ a.detachFromRoot();
+ assertEquals(1, a.mOnDetachCalled);
+ assertEquals(1, b.mOnDetachCalled);
+
+ // Attach to another root r2
+ assertEquals(1, a.mOnAttachCalled);
+ assertEquals(1, b.mOnAttachCalled);
+ a.attachToRoot(r2);
+ assertEquals(2, a.mOnAttachCalled);
+ assertEquals(2, b.mOnAttachCalled);
+ assertSame(r2, a.getGLRoot());
+ assertSame(r2, b.getGLRoot());
+
+ // Detach from r2
+ assertEquals(1, a.mOnDetachCalled);
+ assertEquals(1, b.mOnDetachCalled);
+ a.detachFromRoot();
+ assertEquals(2, a.mOnDetachCalled);
+ assertEquals(2, b.mOnDetachCalled);
+ }
+
+ @SmallTest
+ public void testRoot2() {
+ GLView a = new GLViewMock();
+ GLViewMock b = new GLViewMock();
+ GLRoot r = new GLRootStub();
+
+ a.attachToRoot(r);
+
+ assertEquals(0, b.mOnAttachCalled);
+ a.addComponent(b);
+ assertEquals(1, b.mOnAttachCalled);
+
+ assertEquals(0, b.mOnDetachCalled);
+ a.removeComponent(b);
+ assertEquals(1, b.mOnDetachCalled);
+ }
+
+ @SmallTest
+ public void testInvalidate() {
+ GLView a = new GLView();
+ GLRootMock r = new GLRootMock();
+ a.attachToRoot(r);
+ assertEquals(0, r.mRequestRenderCalled);
+ a.invalidate();
+ assertEquals(1, r.mRequestRenderCalled);
+ }
+
+ @SmallTest
+ public void testRequestLayout() {
+ GLView a = new GLView();
+ GLView b = new GLView();
+ GLRootMock r = new GLRootMock();
+ a.attachToRoot(r);
+ a.addComponent(b);
+ assertEquals(0, r.mRequestLayoutContentPaneCalled);
+ b.requestLayout();
+ assertEquals(1, r.mRequestLayoutContentPaneCalled);
+ }
+
+ @SmallTest
+ public void testLayout() {
+ GLViewMock a = new GLViewMock();
+ GLViewMock b = new GLViewMock();
+ GLViewMock c = new GLViewMock();
+ GLRootMock r = new GLRootMock();
+
+ a.attachToRoot(r);
+ a.addComponent(b);
+ a.addComponent(c);
+
+ assertEquals(0, a.mOnLayoutCalled);
+ a.layout(10, 20, 60, 100);
+ assertEquals(1, a.mOnLayoutCalled);
+ assertEquals(1, b.mOnLayoutCalled);
+ assertEquals(1, c.mOnLayoutCalled);
+ assertTrue(a.mOnLayoutChangeSize);
+ assertTrue(b.mOnLayoutChangeSize);
+ assertTrue(c.mOnLayoutChangeSize);
+
+ // same size should not trigger onLayout
+ a.layout(10, 20, 60, 100);
+ assertEquals(1, a.mOnLayoutCalled);
+
+ // unless someone requested it, but only those on the path
+ // to the requester.
+ assertEquals(0, r.mRequestLayoutContentPaneCalled);
+ b.requestLayout();
+ a.layout(10, 20, 60, 100);
+ assertEquals(1, r.mRequestLayoutContentPaneCalled);
+ assertEquals(2, a.mOnLayoutCalled);
+ assertEquals(2, b.mOnLayoutCalled);
+ assertEquals(1, c.mOnLayoutCalled);
+ }
+
+ @SmallTest
+ public void testRender() {
+ GLViewMock a = new GLViewMock();
+ GLViewMock b = new GLViewMock();
+
+ a.addComponent(b);
+ GLCanvasStub canvas = new GLCanvasStub();
+ assertEquals(0, a.mRenderBackgroundCalled);
+ assertEquals(0, b.mRenderBackgroundCalled);
+ a.render(canvas);
+ assertEquals(1, a.mRenderBackgroundCalled);
+ assertEquals(1, b.mRenderBackgroundCalled);
+ }
+
+ @SmallTest
+ public void testMeasure() {
+ GLViewMock a = new GLViewMock();
+ GLViewMock b = new GLViewMock();
+ GLViewMock c = new GLViewMock();
+ GLRootMock r = new GLRootMock();
+
+ a.addComponent(b);
+ a.addComponent(c);
+ a.attachToRoot(r);
+
+ assertEquals(0, a.mOnMeasureCalled);
+ a.measure(100, 200);
+ assertEquals(1, a.mOnMeasureCalled);
+ assertEquals(1, b.mOnMeasureCalled);
+ assertEquals(100, a.mOnMeasureWidthSpec);
+ assertEquals(200, a.mOnMeasureHeightSpec);
+ assertEquals(100, b.mOnMeasureWidthSpec);
+ assertEquals(200, b.mOnMeasureHeightSpec);
+ assertEquals(100, a.getMeasuredWidth());
+ assertEquals(200, b.getMeasuredHeight());
+
+ // same spec should not trigger onMeasure
+ a.measure(100, 200);
+ assertEquals(1, a.mOnMeasureCalled);
+
+ // unless someone requested it, but only those on the path
+ // to the requester.
+ b.requestLayout();
+ a.measure(100, 200);
+ assertEquals(2, a.mOnMeasureCalled);
+ assertEquals(2, b.mOnMeasureCalled);
+ assertEquals(1, c.mOnMeasureCalled);
+ }
+
+ class MyGLView extends GLView {
+ private int mWidth;
+ int mOnTouchCalled;
+ int mOnTouchX;
+ int mOnTouchY;
+ int mOnTouchAction;
+
+ public MyGLView(int width) {
+ mWidth = width;
+ }
+
+ @Override
+ protected void onLayout(boolean changeSize, int left, int top,
+ int right, int bottom) {
+ // layout children from left to right
+ // call children's layout.
+ int x = 0;
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView item = getComponent(i);
+ item.measure(0, 0);
+ int w = item.getMeasuredWidth();
+ int h = item.getMeasuredHeight();
+ item.layout(x, 0, x + w, h);
+ x += w;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ setMeasuredSize(mWidth, 100);
+ }
+
+ @Override
+ protected boolean onTouch(MotionEvent event) {
+ mOnTouchCalled++;
+ mOnTouchX = (int) event.getX();
+ mOnTouchY = (int) event.getY();
+ mOnTouchAction = event.getAction();
+ return true;
+ }
+ }
+
+ private MotionEvent NewMotionEvent(int action, int x, int y) {
+ return MotionEvent.obtain(0, 0, action, x, y, 0);
+ }
+
+ @SmallTest
+ public void testTouchEvent() {
+ // We construct a tree with four nodes. Only the x coordinate is used:
+ // A = [0..............................300)
+ // B = [0......100)
+ // C = [100......200)
+ // D = [100..150)
+
+ MyGLView a = new MyGLView(300);
+ MyGLView b = new MyGLView(100);
+ MyGLView c = new MyGLView(100);
+ MyGLView d = new MyGLView(50);
+ GLRoot r = new GLRootStub();
+
+ a.addComponent(b);
+ a.addComponent(c);
+ c.addComponent(d);
+ a.attachToRoot(r);
+ a.layout(0, 0, 300, 100);
+
+ int DOWN = MotionEvent.ACTION_DOWN;
+ int UP = MotionEvent.ACTION_UP;
+ int MOVE = MotionEvent.ACTION_MOVE;
+ int CANCEL = MotionEvent.ACTION_CANCEL;
+
+ // simple case
+ assertEquals(0, a.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 250, 0));
+ assertEquals(DOWN, a.mOnTouchAction);
+ a.dispatchTouchEvent(NewMotionEvent(UP, 250, 0));
+ assertEquals(UP, a.mOnTouchAction);
+ assertEquals(2, a.mOnTouchCalled);
+
+ // pass to a child, check the location is offseted.
+ assertEquals(0, c.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0));
+ a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0));
+ assertEquals(75, c.mOnTouchX);
+ assertEquals(0, c.mOnTouchY);
+ assertEquals(2, c.mOnTouchCalled);
+ assertEquals(2, a.mOnTouchCalled);
+
+ // motion target cancel event
+ assertEquals(0, d.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0));
+ assertEquals(1, d.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(MOVE, 250, 0));
+ assertEquals(2, d.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(MOVE, 50, 0));
+ assertEquals(3, d.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0));
+ assertEquals(4, d.mOnTouchCalled);
+ assertEquals(CANCEL, d.mOnTouchAction);
+ assertEquals(3, c.mOnTouchCalled);
+ assertEquals(DOWN, c.mOnTouchAction);
+ a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0));
+
+ // motion target is removed
+ assertEquals(4, d.mOnTouchCalled);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0));
+ assertEquals(5, d.mOnTouchCalled);
+ a.removeComponent(c);
+ assertEquals(6, d.mOnTouchCalled);
+ assertEquals(CANCEL, d.mOnTouchAction);
+
+ // invisible component should not get events
+ assertEquals(2, a.mOnTouchCalled);
+ assertEquals(0, b.mOnTouchCalled);
+ b.setVisibility(GLView.INVISIBLE);
+ a.dispatchTouchEvent(NewMotionEvent(DOWN, 50, 0));
+ assertEquals(3, a.mOnTouchCalled);
+ assertEquals(0, b.mOnTouchCalled);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/PointerInfo.java b/tests/src/com/android/gallery3d/ui/PointerInfo.java
new file mode 100644
index 000000000..6c78556e1
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/PointerInfo.java
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+
+import javax.microedition.khronos.opengles.GL10;
+
+public class PointerInfo {
+
+ /**
+ * The number of coordinates per vertex. 1..4
+ */
+ public int mSize;
+
+ /**
+ * The type of each coordinate.
+ */
+ public int mType;
+
+ /**
+ * The byte offset between consecutive vertices. 0 means mSize *
+ * sizeof(mType)
+ */
+ public int mStride;
+ public Buffer mPointer;
+ public ByteBuffer mTempByteBuffer;
+
+ public PointerInfo(int size, int type, int stride, Buffer pointer) {
+ mSize = size;
+ mType = type;
+ mStride = stride;
+ mPointer = pointer;
+ }
+
+ private int getStride() {
+ return mStride > 0 ? mStride : sizeof(mType) * mSize;
+ }
+
+ public void bindByteBuffer() {
+ mTempByteBuffer = mPointer == null ? null : toByteBuffer(-1, mPointer);
+ }
+
+ public void unbindByteBuffer() {
+ mTempByteBuffer = null;
+ }
+
+ private static int sizeof(int type) {
+ switch (type) {
+ case GL10.GL_UNSIGNED_BYTE:
+ return 1;
+ case GL10.GL_BYTE:
+ return 1;
+ case GL10.GL_SHORT:
+ return 2;
+ case GL10.GL_FIXED:
+ return 4;
+ case GL10.GL_FLOAT:
+ return 4;
+ default:
+ return 0;
+ }
+ }
+
+ private static ByteBuffer toByteBuffer(int byteCount, Buffer input) {
+ ByteBuffer result = null;
+ boolean convertWholeBuffer = (byteCount < 0);
+ if (input instanceof ByteBuffer) {
+ ByteBuffer input2 = (ByteBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = input2.limit() - position;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ for (int i = 0; i < byteCount; i++) {
+ result.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof CharBuffer) {
+ CharBuffer input2 = (CharBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position) * 2;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ CharBuffer result2 = result.asCharBuffer();
+ for (int i = 0; i < byteCount / 2; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof ShortBuffer) {
+ ShortBuffer input2 = (ShortBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position)* 2;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ ShortBuffer result2 = result.asShortBuffer();
+ for (int i = 0; i < byteCount / 2; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof IntBuffer) {
+ IntBuffer input2 = (IntBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position) * 4;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ IntBuffer result2 = result.asIntBuffer();
+ for (int i = 0; i < byteCount / 4; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof FloatBuffer) {
+ FloatBuffer input2 = (FloatBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position) * 4;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ FloatBuffer result2 = result.asFloatBuffer();
+ for (int i = 0; i < byteCount / 4; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof DoubleBuffer) {
+ DoubleBuffer input2 = (DoubleBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position) * 8;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ DoubleBuffer result2 = result.asDoubleBuffer();
+ for (int i = 0; i < byteCount / 8; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else if (input instanceof LongBuffer) {
+ LongBuffer input2 = (LongBuffer) input;
+ int position = input2.position();
+ if (convertWholeBuffer) {
+ byteCount = (input2.limit() - position) * 8;
+ }
+ result = ByteBuffer.allocate(byteCount).order(input2.order());
+ LongBuffer result2 = result.asLongBuffer();
+ for (int i = 0; i < byteCount / 8; i++) {
+ result2.put(input2.get());
+ }
+ input2.position(position);
+ } else {
+ throw new RuntimeException("Unimplemented Buffer subclass.");
+ }
+ result.rewind();
+ // The OpenGL API will interpret the result in hardware byte order,
+ // so we better do that as well:
+ result.order(ByteOrder.nativeOrder());
+ return result;
+ }
+
+ public void getArrayElement(int index, double[] result) {
+ if (mTempByteBuffer == null) {
+ throw new IllegalArgumentException("undefined pointer");
+ }
+ if (mStride < 0) {
+ throw new IllegalArgumentException("invalid stride");
+ }
+
+ int stride = getStride();
+ ByteBuffer byteBuffer = mTempByteBuffer;
+ int size = mSize;
+ int type = mType;
+ int sizeofType = sizeof(type);
+ int byteOffset = stride * index;
+
+ for (int i = 0; i < size; i++) {
+ switch (type) {
+ case GL10.GL_BYTE:
+ case GL10.GL_UNSIGNED_BYTE:
+ result[i] = byteBuffer.get(byteOffset);
+ break;
+ case GL10.GL_SHORT:
+ ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
+ result[i] = shortBuffer.get(byteOffset / 2);
+ break;
+ case GL10.GL_FIXED:
+ IntBuffer intBuffer = byteBuffer.asIntBuffer();
+ result[i] = intBuffer.get(byteOffset / 4);
+ break;
+ case GL10.GL_FLOAT:
+ FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
+ result[i] = floatBuffer.get(byteOffset / 4);
+ break;
+ default:
+ throw new UnsupportedOperationException("unknown type");
+ }
+ byteOffset += sizeofType;
+ }
+ }
+}
diff --git a/tests/src/com/android/gallery3d/ui/TextureTest.java b/tests/src/com/android/gallery3d/ui/TextureTest.java
new file mode 100644
index 000000000..fb26060bc
--- /dev/null
+++ b/tests/src/com/android/gallery3d/ui/TextureTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.ui;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import javax.microedition.khronos.opengles.GL11;
+
+import junit.framework.TestCase;
+
+@SmallTest
+public class TextureTest extends TestCase {
+ @SuppressWarnings("unused")
+ private static final String TAG = "TextureTest";
+
+ class MyBasicTexture extends BasicTexture {
+ int mOnBindCalled;
+ int mOpaqueCalled;
+
+ MyBasicTexture(GLCanvas canvas, int id) {
+ super(canvas, id, BasicTexture.STATE_UNLOADED);
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ mOnBindCalled++;
+ return true;
+ }
+
+ public boolean isOpaque() {
+ mOpaqueCalled++;
+ return true;
+ }
+
+ void upload() {
+ mState = STATE_LOADED;
+ }
+ }
+
+ @SmallTest
+ public void testBasicTexture() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+ MyBasicTexture texture = new MyBasicTexture(canvas, 47);
+
+ assertEquals(47, texture.getId());
+ texture.setSize(1, 1);
+ assertEquals(1, texture.getWidth());
+ assertEquals(1, texture.getHeight());
+ assertEquals(1, texture.getTextureWidth());
+ assertEquals(1, texture.getTextureHeight());
+ texture.setSize(3, 5);
+ assertEquals(3, texture.getWidth());
+ assertEquals(5, texture.getHeight());
+ assertEquals(4, texture.getTextureWidth());
+ assertEquals(8, texture.getTextureHeight());
+
+ assertFalse(texture.isLoaded(canvas));
+ texture.upload();
+ assertTrue(texture.isLoaded(canvas));
+
+ // For a different GL, it's not loaded.
+ GLCanvas canvas2 = new GLCanvasImpl(new GLStub());
+ assertFalse(texture.isLoaded(canvas2));
+
+ assertEquals(0, texture.mOnBindCalled);
+ assertEquals(0, texture.mOpaqueCalled);
+ texture.draw(canvas, 100, 200, 1, 1);
+ assertEquals(1, texture.mOnBindCalled);
+ assertEquals(1, texture.mOpaqueCalled);
+ texture.draw(canvas, 0, 0);
+ assertEquals(2, texture.mOnBindCalled);
+ assertEquals(2, texture.mOpaqueCalled);
+ }
+
+ @SmallTest
+ public void testRawTexture() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+ RawTexture texture = RawTexture.newInstance(canvas);
+ texture.onBind(canvas);
+
+ GLCanvas canvas2 = new GLCanvasImpl(new GLStub());
+ try {
+ texture.onBind(canvas2);
+ fail();
+ } catch (RuntimeException ex) {
+ // expected.
+ }
+
+ assertTrue(texture.isOpaque());
+ }
+
+ @SmallTest
+ public void testColorTexture() {
+ GLCanvasMock canvas = new GLCanvasMock();
+ ColorTexture texture = new ColorTexture(0x12345678);
+
+ texture.setSize(42, 47);
+ assertEquals(texture.getWidth(), 42);
+ assertEquals(texture.getHeight(), 47);
+ assertEquals(0, canvas.mFillRectCalled);
+ texture.draw(canvas, 0, 0);
+ assertEquals(1, canvas.mFillRectCalled);
+ assertEquals(0x12345678, canvas.mFillRectColor);
+ assertEquals(42f, canvas.mFillRectWidth);
+ assertEquals(47f, canvas.mFillRectHeight);
+ assertFalse(texture.isOpaque());
+ assertTrue(new ColorTexture(0xFF000000).isOpaque());
+ }
+
+ private class MyUploadedTexture extends UploadedTexture {
+ int mGetCalled;
+ int mFreeCalled;
+ Bitmap mBitmap;
+ @Override
+ protected Bitmap onGetBitmap() {
+ mGetCalled++;
+ Config config = Config.ARGB_8888;
+ mBitmap = Bitmap.createBitmap(47, 42, config);
+ return mBitmap;
+ }
+ @Override
+ protected void onFreeBitmap(Bitmap bitmap) {
+ mFreeCalled++;
+ assertSame(mBitmap, bitmap);
+ mBitmap.recycle();
+ mBitmap = null;
+ }
+ }
+
+ @SmallTest
+ public void testUploadedTexture() {
+ GL11 glStub = new GLStub();
+ GLCanvas canvas = new GLCanvasImpl(glStub);
+ MyUploadedTexture texture = new MyUploadedTexture();
+
+ // draw it and the bitmap should be fetched.
+ assertEquals(0, texture.mFreeCalled);
+ assertEquals(0, texture.mGetCalled);
+ texture.draw(canvas, 0, 0);
+ assertEquals(1, texture.mGetCalled);
+ assertTrue(texture.isLoaded(canvas));
+ assertTrue(texture.isContentValid(canvas));
+
+ // invalidate content and it should be freed.
+ texture.invalidateContent();
+ assertFalse(texture.isContentValid(canvas));
+ assertEquals(1, texture.mFreeCalled);
+ assertTrue(texture.isLoaded(canvas)); // But it's still loaded
+
+ // draw it again and the bitmap should be fetched again.
+ texture.draw(canvas, 0, 0);
+ assertEquals(2, texture.mGetCalled);
+ assertTrue(texture.isLoaded(canvas));
+ assertTrue(texture.isContentValid(canvas));
+
+ // recycle the texture and it should be freed again.
+ texture.recycle();
+ assertEquals(2, texture.mFreeCalled);
+ // TODO: these two are broken and waiting for fix.
+ //assertFalse(texture.isLoaded(canvas));
+ //assertFalse(texture.isContentValid(canvas));
+ }
+
+ class MyTextureForMixed extends BasicTexture {
+ MyTextureForMixed(GLCanvas canvas, int id) {
+ super(canvas, id, BasicTexture.STATE_UNLOADED);
+ }
+
+ @Override
+ protected boolean onBind(GLCanvas canvas) {
+ return true;
+ }
+
+ public boolean isOpaque() {
+ return true;
+ }
+ }
+
+ @SmallTest
+ public void testBitmapTexture() {
+ Config config = Config.ARGB_8888;
+ Bitmap bitmap = Bitmap.createBitmap(47, 42, config);
+ assertFalse(bitmap.isRecycled());
+ BitmapTexture texture = new BitmapTexture(bitmap);
+ texture.recycle();
+ assertFalse(bitmap.isRecycled());
+ bitmap.recycle();
+ assertTrue(bitmap.isRecycled());
+ }
+}
diff --git a/tests/src/com/android/gallery3d/util/IntArrayTest.java b/tests/src/com/android/gallery3d/util/IntArrayTest.java
new file mode 100644
index 000000000..83e605006
--- /dev/null
+++ b/tests/src/com/android/gallery3d/util/IntArrayTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package com.android.gallery3d.util;
+
+import com.android.gallery3d.util.IntArray;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+@SmallTest
+public class IntArrayTest extends TestCase {
+ private static final String TAG = "IntArrayTest";
+
+ public void testIntArray() {
+ IntArray a = new IntArray();
+ assertEquals(0, a.size());
+ assertTrue(Arrays.equals(new int[] {}, a.toArray(null)));
+
+ a.add(0);
+ assertEquals(1, a.size());
+ assertTrue(Arrays.equals(new int[] {0}, a.toArray(null)));
+
+ a.add(1);
+ assertEquals(2, a.size());
+ assertTrue(Arrays.equals(new int[] {0, 1}, a.toArray(null)));
+
+ int[] buf = new int[2];
+ int[] result = a.toArray(buf);
+ assertSame(buf, result);
+
+ IntArray b = new IntArray();
+ for (int i = 0; i < 100; i++) {
+ b.add(i * i);
+ }
+
+ assertEquals(100, b.size());
+ result = b.toArray(buf);
+ assertEquals(100, result.length);
+ for (int i = 0; i < 100; i++) {
+ assertEquals(i * i, result[i]);
+ }
+ }
+}