1b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher/*
2b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * Copyright (C) 2014 The Android Open Source Project
3b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher *
4b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * Licensed under the Apache License, Version 2.0 (the "License");
5b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * you may not use this file except in compliance with the License.
6b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * You may obtain a copy of the License at
7b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher *
8b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher *      http://www.apache.org/licenses/LICENSE-2.0
9b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher *
10b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * Unless required by applicable law or agreed to in writing, software
11b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * distributed under the License is distributed on an "AS IS" BASIS,
12b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * See the License for the specific language governing permissions and
14b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher * limitations under the License.
15b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher */
16b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
17b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherpackage com.example.android.camera2.cameratoo;
18b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
19b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport static org.junit.Assert.assertEquals;
20b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport static org.junit.Assert.assertTrue;
21b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport static org.mockito.Mockito.mock;
22b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport static org.mockito.Mockito.when;
23b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
24b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport android.media.Image;
25b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport android.os.Environment;
26b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport android.util.Size;
27b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
28b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.io.File;
29b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.io.FileInputStream;
30b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.io.FileNotFoundException;
31b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.io.FilenameFilter;
32b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.io.IOException;
33b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.nio.ByteBuffer;
34b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.util.Arrays;
35b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.util.Comparator;
36b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.util.HashSet;
37b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport java.util.Set;
38b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
39b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport com.example.android.camera2.cameratoo.CameraTooActivity;
40b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherimport org.junit.Test;
41b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
42b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucherpublic class CameraTooTest {
43b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    private <T> void assertComparatorEq(T lhs, T rhs, Comparator<T> rel) {
44b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertEquals(String.format("%s should be equal to %s", lhs, rhs), rel.compare(lhs, rhs), 0);
45b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertEquals(String.format("%s should be equal to %s (reverse check)", lhs, rhs),
46b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                rel.compare(rhs, lhs), 0);
47b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
48b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
49b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    private <T> void assertComparatorLt(T lhs, T rhs, Comparator<T> rel) {
50b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertTrue(String.format("%s should be less than %s", lhs, rhs), rel.compare(lhs, rhs) < 0);
51b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertTrue(String.format("%s should be less than %s (reverse check)", lhs, rhs),
52b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                rel.compare(rhs, lhs) > 0);
53b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
54b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
55b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    @Test
56b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    public void compareSizesByArea() {
57b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
58b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
59b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size largeSquare = new Size(5, 5);
60b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Comparator<Size> rel = new CameraTooActivity.CompareSizesByArea();
61b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
62b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(empty, fatAndFlat, rel);
63b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(empty, tallAndThin, rel);
64b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(fatAndFlat, empty, rel);
65b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(fatAndFlat, tallAndThin, rel);
66b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(tallAndThin, empty, rel);
67b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(tallAndThin, fatAndFlat, rel);
68b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
69b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(smallSquare, horizRect, rel);
70b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(smallSquare, vertRect, rel);
71b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(horizRect, smallSquare, rel);
72b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(horizRect, vertRect, rel);
73b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(vertRect, smallSquare, rel);
74b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorEq(vertRect, horizRect, rel);
75b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
76b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(empty, smallSquare, rel);
77b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(empty, horizRect, rel);
78b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(empty, vertRect, rel);
79b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
80b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(fatAndFlat, smallSquare, rel);
81b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(fatAndFlat, horizRect, rel);
82b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(fatAndFlat, vertRect, rel);
83b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
84b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(tallAndThin, smallSquare, rel);
85b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(tallAndThin, horizRect, rel);
86b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(tallAndThin, vertRect, rel);
87b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
88b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(empty, largeSquare, rel);
89b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(fatAndFlat, largeSquare, rel);
90b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(tallAndThin, largeSquare, rel);
91b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(smallSquare, largeSquare, rel);
92b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(horizRect, largeSquare, rel);
93b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertComparatorLt(vertRect, largeSquare, rel);
94b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
95b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
96b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    private void assertOptimalSize(Size[] options, int minWidth, int minHeight, Size expected) {
97b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size verdict = CameraTooActivity.chooseBigEnoughSize(options, minWidth, minHeight);
98b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertEquals(String.format("Expected optimal size %s but got %s", expected, verdict),
99b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                verdict, expected);
100b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
101b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
102b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    @Test
103b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    public void chooseBigEnoughSize() {
104b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size empty = new Size(0, 0), fatAndFlat = new Size(100, 0), tallAndThin = new Size(0, 100);
105b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size smallSquare = new Size(4, 4), horizRect = new Size(8, 2), vertRect = new Size(2, 8);
106b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size largeSquare = new Size(5, 5);
107b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Size[] siz =
108b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                { empty, fatAndFlat, tallAndThin, smallSquare, horizRect, vertRect, largeSquare };
109b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
110b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 0, 0, empty);
111b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
112b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 1, 0, fatAndFlat);
113b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 0, 1, tallAndThin);
114b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
115b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 4, 4, smallSquare);
116b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 1, 1, smallSquare);
117b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 2, 1, smallSquare);
118b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 1, 2, smallSquare);
119b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 3, 4, smallSquare);
120b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 4, 3, smallSquare);
121b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
122b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 8, 2, horizRect);
123b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 5, 1, horizRect);
124b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 5, 2, horizRect);
125b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
126b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 2, 8, vertRect);
127b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 1, 5, vertRect);
128b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 2, 5, vertRect);
129b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
130b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 5, 5, largeSquare);
131b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 3, 5, largeSquare);
132b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertOptimalSize(siz, 5, 3, largeSquare);
133b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
134b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
135b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    private static final FilenameFilter OUTPUT_FILE_DECIDER = new FilenameFilter() {
136b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        @Override
137b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        public boolean accept(File dir, String filename) {
138b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher            return filename.indexOf("cameratoo") == 0 &&
139b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                    filename.indexOf(".jpg") == filename.length() - ".jpg".length();
140b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        }};
141b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
142b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    private static <T> Set<T> newlyAddedElements(Set<T> before, Set<T> after) {
143b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Set<T> result = new HashSet<T>(after);
144b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        result.removeAll(before);
145b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        return result;
146b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
147b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
148b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    @Test
149b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    public void capturedImageSaver() throws FileNotFoundException, IOException {
150b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        ByteBuffer buf = ByteBuffer.allocate(25);
151b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        for(int index = 0; index < buf.capacity(); ++index)
152b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher            buf.put(index, (byte) index);
153b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
154b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Image.Plane plane = mock(Image.Plane.class);
155b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(plane.getBuffer()).thenReturn(buf);
156b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(plane.getPixelStride()).thenReturn(1);
157b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(plane.getRowStride()).thenReturn(5);
158b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
159b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Image.Plane[] onlyPlaneThatMatters = { plane };
160b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Image image = mock(Image.class);
161b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(image.getPlanes()).thenReturn(onlyPlaneThatMatters);
162b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(image.getWidth()).thenReturn(5);
163b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        when(image.getHeight()).thenReturn(5);
164b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
165b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        File picturesFolder =
166b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
167b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Set<File> preListing =
168b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
169b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
170b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        CameraTooActivity.CapturedImageSaver saver =
171b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                new CameraTooActivity.CapturedImageSaver(image);
172b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        saver.run();
173b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
174b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Set<File> postListing =
175b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher                new HashSet<File>(Arrays.asList(picturesFolder.listFiles(OUTPUT_FILE_DECIDER)));
176b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        Set<File> newFiles = newlyAddedElements(preListing, postListing);
177b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
178b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertEquals(newFiles.size(), 1);
179b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
180b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        File picture = newFiles.iterator().next();
181b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        FileInputStream istream = new FileInputStream(picture);
182b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher
183b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        for(int count = 0; count < buf.capacity(); ++count) {
184b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher            assertEquals(istream.read(), buf.get(count));
185b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        }
186b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertEquals(istream.read(), -1);
187b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher        assertTrue(picture.delete());
188b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher    }
189b84fdffad40226ca642680c7d1eec7c7799f07aaSol Boucher}
190