• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.verifier.camera.analyzer;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.BitmapFactory;
21 import android.graphics.ImageFormat;
22 import android.graphics.Rect;
23 import android.hardware.Camera;
24 import android.hardware.Camera.Area;
25 import android.util.Log;
26 import android.widget.ImageView;
27 
28 import java.io.FileOutputStream;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Random;
34 
35 /**
36  * Implements a test to verify whether the camera metering system works as
37  * described in the API.
38  *
39  * The test consists two sub-categories. The first one has tests with only
40  * one metering area defined. The second one has tests with two metering areas
41  * defined. For each single sub-test, we use a random number generator to
42  * decide where to put some of the metering areas to and how much weight should
43  * be assigned to each area. For different tests, we use different ways to
44  * define other metering areas and their weight, in order to cover all possible
45  * fail cases. The metering areas are contrained to the grey squares in the
46  * bottom of the color checker.
47  */
48 public class MeteringTest extends CameraTests {
49 
50     private static final String TAG = "MeteringTest";
51 
52     /** A long wait.*/
53     private static final int LONG_SLEEP = 4000;
54     /** Debug result in text. */
55     private String mDebugText;
56     /** Thread lock. */
57     private final Object mProcessingImage = new Object();
58     /** Memory address of the native test handler. */
59     private long mTestHandler;
60     /** The maximum number of metering area the device supports. */
61     private int mMaxNumMeteringArea;
62     /** The metering areas. */
63     private List<Camera.Area> mGreyAreas;
64     /** The coordinates of the grey squares on the color checker. */
65     private int[] mGreyCoordinates = new int[24];
66     /** Random number generator. */
67     private final Random mRandomGenerator = new Random();
68     /** Reference comparison result for tests. */
69     private ArrayList<Boolean>  mReferenceCompareResults;
70     /** Number of tests in the same instance. */
71     private int mTestCount;
72     /** Reference test logs. */
73     private ArrayList<String> mReferenceLogs;
74     /** Test result to show. */
75     private int[] mTestResults;
76     /** Number of tests. */
77     private int mNumTests;
78     /** Camera Parameters. */
79     private Camera.Parameters mParams;
80     /** Singleton test instance. */
81     private static MeteringTest singletonTest = null;
82 
83     /** Constructs a <code>MeteringTest</code> instance with the given
84      * camera pointer.
85      */
MeteringTest()86     private MeteringTest() {
87         super();
88     }
89 
updateCamera()90     public void updateCamera() {
91         // Looks up how many metering area the device supports.
92         mParams = mTestCamera.getParameters();
93         mMaxNumMeteringArea = mParams.getMaxNumMeteringAreas();
94         Log.v(TAG, String.format("Maximum number if metering area is %d", mMaxNumMeteringArea));
95         if (mMaxNumMeteringArea == 0) {
96             mDebugText = "Custom Metering not supported!";
97             Log.v(TAG, "Custom Metering not supported");
98         }
99     }
100 
getSingletonTest()101     public static synchronized MeteringTest getSingletonTest() {
102         if (singletonTest == null) {
103             Log.v(TAG, "Creating a new MeteringTest instance");
104             singletonTest = new MeteringTest();
105             singletonTest.initializeTest();
106         }
107         return singletonTest;
108     }
109 
initializeTest()110     private void initializeTest() {
111         // Creates a native metering test handler.
112         mTestHandler = createMeteringTest();
113         mDebugText = new String();
114         mReferenceCompareResults = new ArrayList<Boolean>();
115         mReferenceLogs = new ArrayList<String>();
116         mNumTests = 3;
117         mTestResults = new int[mNumTests];
118         for (int i = 0; i < mNumTests; ++i) {
119             mTestResults[i] = CameraTests.CAMERA_TEST_NOT_RUN;
120         }
121     }
122 
123     /**
124      * Runs the metering test instance.
125      */
126     @Override
run(int index)127     public synchronized void run(int index) {
128         if (index == 0) {
129             run(1);
130             run(2);
131             return;
132         }
133         Log.v(TAG, "MeteringTest thread started!");
134 
135         // Finds the coordinates of the grey squares on the color checker.
136         // The coordinate system has (-1000, -1000) on the upper left corner.
137         // And (1000, 1000) on the bottom right corner.
138         findGreyCoordinates(mGreyCoordinates, getCheckerCenter(), getCheckerRadius());
139 
140         if (mMaxNumMeteringArea > 0) {
141             mTestCount = 0;
142             // Runs the metering tests category by category.
143             switch (index) {
144                 case 1:
145                     runOneAreaTest();
146                     break;
147                 case 2:
148                     if (mMaxNumMeteringArea > 1) {
149                         runTwoAreasTest();
150                     }
151                     break;
152                 default:
153                     break;
154             }
155         }
156 
157         mParams = mTestCamera.getParameters();
158         mParams.setMeteringAreas(null);
159         mTestCamera.setParameters(mParams);
160 
161         boolean[] testCompareResults = new boolean[2 * mTestCount];
162 
163         // Processes the image data taken so far and stores the test results.
164         processMeteringTest(mTestHandler, testCompareResults);
165         // Prepares debug output based on the test results.
166         prepareDebugText(testCompareResults, index);
167 
168         mReferenceCompareResults.clear();
169         mReferenceLogs.clear();
170     }
171 
172     /**
173      * Prepares the test results in HTML text string to show in the UI.
174      *
175      * If the test result is the same as the reference result, the text will be
176      * shown in green. Otherwise it would be shown as red.
177      *
178      * @param testCompareResults the array storing the comparison results from
179      * the data taken by the camera so far.
180      */
prepareDebugText(boolean[] testCompareResults, int index)181     private void prepareDebugText(boolean[] testCompareResults, int index) {
182         mDebugText = "";
183         boolean groupTestPassed = true;
184         for (int i = 0; i < mTestCount; ++i) {
185               String testLog;
186               boolean testPassed = true;
187               testLog = mReferenceLogs.get(i);
188               mDebugText += (testLog + "<br/>");
189 
190               if (testCompareResults[i * 2] == mReferenceCompareResults.get(i * 2)) {
191                   mDebugText += String.format(
192                       "Picture 1 equivalent to Picture 2 is %b \n",
193                       testCompareResults[i * 2]);
194               } else {
195                   mDebugText += String.format(
196                       "Picture 1 equivalent to Picture 2 is %b \n",
197                       testCompareResults[i * 2]);
198                   testPassed = false;
199               }
200 
201               if (testCompareResults[i * 2 + 1] == mReferenceCompareResults.get(i * 2 + 1)) {
202                   mDebugText += String.format(
203                       "Picture 1 darker than Picture 2 is %b \n",
204                       testCompareResults[i * 2 + 1]);
205               } else {
206                   mDebugText += String.format(
207                       "Picture 1 darker than Picture 2 is %b \n",
208                       testCompareResults[i * 2 + 1]);
209                   testPassed = false;
210               }
211 
212               if (testPassed) {
213                   mDebugText += "Test passed! \n";
214               } else {
215                   mDebugText += "Test failed! \n";
216                   groupTestPassed = false;
217               }
218               Log.v(TAG, String.format("%s", mDebugText));
219          }
220 
221         if (groupTestPassed) {
222             mTestResults[index] = CameraTests.CAMERA_TEST_SUCCESS;
223         } else {
224             mTestResults[index] = CameraTests.CAMERA_TEST_FAILURE;
225         }
226 
227     }
228 
229     /**
230      * Runs tests to check whether the metering functionalities work properly
231      * when one metering area is added.
232      */
runOneAreaTest()233     private void runOneAreaTest() {
234         int weight1;
235         int weight2;
236         int square1;
237         int square2;
238 
239         Log.v(TAG, "Running one area Test");
240 
241         // Test case 1: Two images have the same metering area. Image 1 has
242         // a diffent weight than Image 2. The result images should be
243         // identical.
244         // Tests whether weight normalization works.
245         square1 = mRandomGenerator.nextInt(6);
246         weight1 = mRandomGenerator.nextInt(100) + 1;
247         runSingleTest(square1, square1, weight1);
248 
249         square2 = square1;
250         weight2 = mRandomGenerator.nextInt(100) + 901;
251         runSingleTest(square2, square2, weight2);
252         mReferenceCompareResults.add(true);
253         mReferenceCompareResults.add(false);
254         Log.v(TAG, String.format("Running test for %d square with weights %d, %d",
255                                  square1, weight1, weight2));
256         mReferenceLogs.add(String.format(
257             "Running test for %d 1x1 square with weights %d, %d", square1, weight1, weight2));
258         ++mTestCount;
259 
260         // Test case 2: Two images have different metering areas. Image 1 has
261         // one of the grey squares as its metering area. Image 2 has a darker
262         // grey square as its metering area. The weights for both images are
263         // the same. Image 1 is expected to be darker than Image 2.
264         // Tests whether metering on uni-brightness patches work.
265         square1 = mRandomGenerator.nextInt(5);
266         weight1 = mRandomGenerator.nextInt(1000) + 1;
267         runSingleTest(square1, square1, weight1);
268 
269         square2 = mRandomGenerator.nextInt(6 - square1 - 1) + square1 + 1;
270         weight2 = weight1;
271         runSingleTest(square2, square2, weight2);
272         mReferenceCompareResults.add(false);
273         mReferenceCompareResults.add(true);
274         mReferenceLogs.add(String.format(
275             "Running test for %d, %d 1x1 square with weight %d", square1, square2, weight1));
276         ++mTestCount;
277 
278         // Test case 3: Two images have different metering areas. Image one has
279         // one of the grey squares as its metering area. Image 2 has a
280         // rectangle which contains Image 1's metering area and the neighboring
281         // darker grey square. The weights for both tests are the same. Image 1
282         // is expected to be darker than Image 2.
283         // Tests whether metering on patches with different brightness works.
284         square1 = mRandomGenerator.nextInt(5);
285         weight1 = mRandomGenerator.nextInt(1000) + 1;
286         runSingleTest(square1, square1, weight1);
287 
288         square2 = square1;
289         weight2 = weight1;
290         runSingleTest(square2, square2 + 1, weight2);
291         mReferenceCompareResults.add(false);
292         mReferenceCompareResults.add(true);
293         mReferenceLogs.add(String.format(
294             "Running test for %d 1x1, 1x2 square with weight %d", square1, weight1));
295         ++mTestCount;
296 
297         // Test case 4: Two images have different metering areas. Image one has
298         // two neighboring grey squares as its metering area. Image 2 has two
299         // darker neighboring grey squares as its metering area. Weights are
300         // the same for both images. Image 1 is expected to be darker than
301         // Image 2.
302         // Tests whether metering on two mixed-brightness patches work.
303         square1 = mRandomGenerator.nextInt(4);
304         weight1 = mRandomGenerator.nextInt(1000) + 1;
305         runSingleTest(square1, square1 + 1, weight1);
306 
307         square2 = mRandomGenerator.nextInt(5 - square1 - 1) + square1 + 1;
308         weight2 = weight1;
309         runSingleTest(square2, square2 + 1, weight2);
310         mReferenceCompareResults.add(false);
311         mReferenceCompareResults.add(true);
312         mReferenceLogs.add(String.format(
313             "Running test for %d, %d 1x2 square with weight %d", square1, square2, weight1));
314         ++mTestCount;
315 
316         // Test case 5: Two images have different metering areas. Image one has
317         // three neighboring grey squares as its metering area. Image 2 has
318         // three darker neighboring grey squares as its metering area. Weights
319         // are the same. Image 1 is expected to be darker than Image 2.
320         // Tests whether metering on three mixed-brightness patches work.
321         square1 = mRandomGenerator.nextInt(3);
322         weight1 = mRandomGenerator.nextInt(1000) + 1;
323         runSingleTest(square1, square1 + 2, weight1);
324 
325         square2 = mRandomGenerator.nextInt(4 - square1 - 1) + square1 + 1;
326         weight2 = weight1;
327         runSingleTest(square2, square2 + 2, weight2);
328         mReferenceCompareResults.add(false);
329         mReferenceCompareResults.add(true);
330         mReferenceLogs.add(String.format(
331             "Running test for %d, %d 1x3 square with weight %d", square1, square2, weight1));
332         ++mTestCount;
333     }
334 
335     /**
336      * Runs metering tests to verify the functionalities when there are two
337      * areas set as the metering area.
338      */
runTwoAreasTest()339     private void runTwoAreasTest() {
340         int[] weight1 = new int[2];
341         int[] weight2 = new int[2];
342         int[] square1Start = new int[2];
343         int[] square2Start = new int[2];
344         int[] square1End = new int[2];
345         int[] square2End = new int[2];
346 
347         Log.v(TAG, "Running two-area Test");
348 
349         // Test case 1: Image 1 has two metering areas. They are two adjacent
350         // grey squares (each set as a metering area). The two areas have the
351         // same weight. Image 2 has one metering area, which is the combination
352         // of Image 1's two metering areas as a rectangle. The weight is the
353         // same as that of Image 1's individual area. Image 1 is expected to
354         // be equivalent to Image 2.
355         // Tests whether having seperating a metering area into two will yield
356         // the same result.
357         square1Start[0] = mRandomGenerator.nextInt(5);
358         square1End[0] = square1Start[0];
359         weight1[0] = mRandomGenerator.nextInt(1000) + 1;
360         square1Start[1] = square1Start[0] + 1;
361         square1End[1] = square1Start[1];
362         weight1[1] = weight1[0];
363         runMultipleAreaTest(square1Start, square1End, weight1);
364 
365         square2Start[0] = square1Start[0];
366         weight2[0] = weight1[0];
367         runSingleTest(square2Start[0], square2Start[0] + 1, weight2[0]);
368         mReferenceCompareResults.add(true);
369         mReferenceCompareResults.add(false);
370         mReferenceLogs.add(String.format(
371             "Running test for %d, %d 1x1 square with weight %d",
372             square1Start[0], square1Start[1], weight1[0]));
373         ++mTestCount;
374 
375         // Test case 2: Image 1 has two metering areas. They are two random
376         // grey squareson the color checker. The brighter square has a larger
377         // weight than the darker square. Image 2 has the same two metering
378         // areas as Image 1. The weights for both are equal to the weight of
379         // the darker square in Image 1, which is smaller than the weight of
380         // the brighter square in Image 1. Image 1 is expected to be darker
381         // than Image 2.
382         // Tests whether giving one of the two metering areas a different
383         // weight would change the image in the correct way.
384         square1Start[0] = mRandomGenerator.nextInt(4);
385         square1End[0] = square1Start[0];
386         weight1[0] = mRandomGenerator.nextInt(100) + 901;
387         square1Start[1] = mRandomGenerator.nextInt(5 - square1Start[0] - 1) + square1Start[0] + 1;
388         square1End[1] = square1Start[1];
389         weight1[1] = mRandomGenerator.nextInt(100) + 1;
390         runMultipleAreaTest(square1Start, square1End, weight1);
391 
392         square2Start[0] = square1Start[0];
393         square2End[0] = square2Start[0];
394         weight2[0] = weight1[1];
395         square2Start[1] = square1Start[1];
396         square2End[1] = square1End[1];
397         weight2[1] = weight2[0];
398         runMultipleAreaTest(square2Start, square2End, weight2);
399         mReferenceCompareResults.add(false);
400         mReferenceCompareResults.add(true);
401         mReferenceLogs.add(String.format(
402             "Running test for %d, %d 1x1 square with weight %d, %d",
403             square1Start[0], square1Start[1], weight1[0], weight2[1]));
404         ++mTestCount;
405 
406         // Test case 3: Image 1 has two metering areas. Both are set to the
407         // same random grey square on the color checker. The weight for both
408         // are the same. Image 2 has one meterig area, which is the same as
409         // Image 1's chosen grey square. The weight for it is the same as
410         // Image 1's weight for one metering area. Image 1 is expected to be
411         // equivalent to Image 2.
412         // Tests whether defining overlapping metering area works.
413         square1Start[0] = mRandomGenerator.nextInt(6);
414         square1End[0] = square1Start[0];
415         weight1[0] = mRandomGenerator.nextInt(1000) + 1;
416         square1Start[1] = square1Start[0];
417         square1End[1] = square1Start[1];
418         weight1[1] = weight1[0];
419         runMultipleAreaTest(square1Start, square1End, weight1);
420 
421         square2Start[0] = square1Start[0];
422         square2End[0] = square2Start[0];
423         weight2[0] = weight1[0];
424         runSingleTest(square2Start[0], square2End[0], weight2[0]);
425         mReferenceCompareResults.add(true);
426         mReferenceCompareResults.add(false);
427         mReferenceLogs.add(String.format(
428             "Running test for %d 1x1 square with weight %d,", square1Start[0], weight1[0]));
429         ++mTestCount;
430 
431         // Test case 4: Image 1 has two metering areas. The first one is a
432         // grey square on the color checker. The second one is a rectangle
433         // containing the first metering area's grey square and its neighboring
434         // darker square. The weights for both metering area are the same.
435         // Image 2 has two metering areas. The first one is the same grey
436         // square as Image 1's first metering area. The second one is the
437         // neighboring darker grey square. The weight for the brighter square
438         // is double the weight of Image 1's weights for each metering area.
439         // The weight for the Image 2's darker grey square is the same as
440         // Image 1's weight for each of its metering areas. Image 1 is expected
441         // to be equivalent to Image 2.
442         // Tests whether the weights for overlapping metering area add up.
443         square1Start[0] = mRandomGenerator.nextInt(2);
444         square1End[0] = square1Start[0];
445         weight1[0] = mRandomGenerator.nextInt(500) + 1;
446         square1Start[1] = square1Start[0];
447         square1End[1] = square1Start[1] + 1;
448         weight1[1] = weight1[0];
449         runMultipleAreaTest(square1Start, square1End, weight1);
450 
451         square2Start[0] = square1Start[0];
452         square2End[0] = square1End[0];
453         weight2[0] = weight1[0] * 2;
454         square2Start[1] = square2Start[0] + 1;
455         square2End[1] = square2Start[1];
456         weight2[1] = weight1[1];
457         runMultipleAreaTest(square2Start, square2End, weight2);
458         mReferenceCompareResults.add(true);
459         mReferenceCompareResults.add(false);
460         mReferenceLogs.add(String.format(
461             "Running test for %d 1x2 1x1 and 1x2 square with weight %d,",
462             square1Start[0], weight1[0]));
463         ++mTestCount;
464     }
465 
466     /**
467      * Runs the metering test when multiple metering areas are defined.
468      *
469      * @param startIndex the array storing the index of the grey square where
470      * one metering area starts
471      * @param endIndex the array storing the index of the grey square where one
472      * metering area ends.
473      * @param weight the array storing the weight for each metering area.
474      */
runMultipleAreaTest(int[] startIndex, int[] endIndex, int[] weight)475     private void runMultipleAreaTest(int[] startIndex, int[] endIndex, int[] weight) {
476         int numAreas = startIndex.length;
477         mParams = mTestCamera.getParameters();
478         List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
479 
480         for (int i = 0; i < numAreas; ++i) {
481             meteringAreas.add(makeArea(startIndex[i], endIndex[i], weight[i]));
482             Log.v(TAG, String.format("Add metering area for %d, %d, %d",
483                                      startIndex[i], endIndex[i], weight[i]));
484         }
485         mParams.setMeteringAreas(meteringAreas);
486         mTestCamera.setParameters(mParams);
487         takePicture();
488     }
489 
490     /**
491      * Runs the metering test when one metering area is defined.
492      *
493      * @param startIndex the index of the grey square where the metering area
494      * starts
495      * @param endIndex the index of the grey square where the metering area
496      * ends.
497      * @param weight the weight for the metering area.
498      */
runSingleTest(int startIndex, int endIndex, int weight)499     private void runSingleTest(int startIndex, int endIndex, int weight) {
500         mParams = mTestCamera.getParameters();
501         List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
502 
503         Log.v(TAG, String.format("Single test for %d, %d, %d", startIndex, endIndex, weight));
504         meteringAreas.add(makeArea(startIndex, endIndex, weight));
505         mParams.setMeteringAreas(meteringAreas);
506         mTestCamera.setParameters(mParams);
507         takePicture();
508     }
509 
510     /**
511      * Takes picture with the camera instance linked to this test class.
512      */
takePicture()513     private void takePicture() {
514         // Waits for the metering to be stable
515         try{
516             Log.v(TAG, "Waiting for metering");
517             Thread.sleep(LONG_SLEEP);
518             Log.v(TAG, "END Waiting");
519         } catch (InterruptedException e) {}
520 
521         mTestCamera.takePicture(null, null, null, mTestJpegListener);
522 
523         // Locks thread until picture is taken and ready for processing.
524         synchronized (mProcessingImage) {
525             try{
526                 Log.v(TAG, "Start waiting for Image");
527 
528                 mProcessingImage.wait();
529             } catch (InterruptedException e) {
530                 Log.v(TAG, "Callback wait fails!");
531             }
532         }
533     }
534 
535     /**
536      * Constructs a <code>Camera.Area</code> object of the metering area.
537      * Given the start and end index of one metering area, it takes the upper
538      * left corner of the starting square and the bottom right corner of the
539      * end square to construct an Area.
540      *
541      * @param startIndex the index of the grey square where the metering area
542      * starts
543      * @param endIndex the index of the grey square where the metering area
544      * ends
545      * @param weight the weight of this metering area.
546      *
547      * @return a <code>Camera.Area</code> object which represents this metering
548      * area
549      */
makeArea(int startIndex, int endIndex, int weight)550     private Camera.Area makeArea(int startIndex, int endIndex, int weight) {
551         Rect areaRect = new Rect(mGreyCoordinates[startIndex * 4],
552                                  mGreyCoordinates[startIndex * 4 + 1],
553                                  mGreyCoordinates[endIndex * 4 + 2],
554                                  mGreyCoordinates[endIndex * 4 + 3]);
555         Camera.Area area = new Camera.Area(areaRect, weight);
556 
557         return area;
558     }
559 
560     @Override
getDebugText()561     public String getDebugText() {
562         return mDebugText;
563     }
564 
565     @Override
getResultText()566     public String getResultText() {
567         return mDebugText;
568     }
569 
570     @Override
getTestName()571     public String getTestName() {
572         return "Metering Test: \n";
573     }
574 
575     @Override
getTestName(int index)576     public String getTestName(int index) {
577         switch (index) {
578             case 0:
579                 return "Run all tests";
580             case 1:
581                 return "One metering area tests";
582             case 2:
583                 return "Multiple metering areas tests";
584             default:
585                 return "";
586         }
587     }
588 
589     @Override
getResult(int index)590     public int getResult(int index) {
591         return mTestResults[index];
592     }
593 
594     @Override
getNumTests()595     public int getNumTests() {
596         return mNumTests;
597     }
598 
599     private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
600         public void onPictureTaken(byte[] data, Camera mCamera) {
601             Log.v(TAG, "Shutter pressed down!");
602             Bitmap inputImage;
603             try {
604                 FileOutputStream outStream = new FileOutputStream(
605                     String.format("/sdcard/metering%d.jpg", System.currentTimeMillis()));
606                 outStream.write(data);
607                 outStream.close();
608             } catch (FileNotFoundException e) {
609             } catch (IOException e) {}
610 
611             // Decodes the input data of the camera.
612             inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
613 
614             // Records the memory address of the native image class instance.
615             long bufferAddress = findNative(inputImage);
616             Log.v(TAG, "findNative method finishes");
617 
618             // Cleans up the memory taken by the bitmap.
619             inputImage.recycle();
620             data = null;
621             inputImage = null;
622             System.gc();
623 
624             // Add the image data to the native test handler.
625             createMeteringClass(bufferAddress, mTestHandler,
626                                 getCheckerCenter(), getCheckerRadius());
627             mCamera.startPreview();
628 
629             // Releases thread lock after the image is processed.
630             synchronized (mProcessingImage) {
631                 mProcessingImage.notifyAll();
632             }
633         }
634     };
635 
636     /**
637      * Finds the coordinates of the grey squares on the color checker.
638      * The coordinates are computed by using the checker center and radius.
639      * The coordinates are converted to a system with (-1000, -1000) in the
640      * upper left corner and (1000, 1000) in the  bottom right corner.
641      *
642      * @param greyCoordinates the array to store the coordinates of the grey
643      * squares
644      * @param checkerCenterAddress the memory address pointing to the vector
645      * storing the color checker's centers.
646      * @param checkerRadiusAddress the memory address pointing to the vetor
647      * storing the color checker's radius.
648      */
findGreyCoordinates(int[] greyCoordinates, long checkerCenterAddress, long checkerRadiusAddress)649     private native void findGreyCoordinates(int[] greyCoordinates,
650                                             long checkerCenterAddress, long checkerRadiusAddress);
651 
652     /**
653      * Creates the native metering test handler with no debug image.
654      *
655      * @return the memory address pointing to the native test handler instance
656      */
createMeteringTest()657     private native long createMeteringTest();
658 
659     /**
660      * Adds the data from the native image class instance to the native test
661      * handler.
662      *
663      * @param bufferAddress the meory address of the native image class
664      * @param handlerAddress the memory address of the native test handler
665      * @param checkerCenterAddress the memory address of the checker cneters
666      * @param checkerRadiusAddress the meory address of the checker radius
667      */
createMeteringClass(long bufferAddress, long handlerAddress, long checkerCenterAddress, long checkerRadiusAddress)668     private native void createMeteringClass(long bufferAddress, long handlerAddress,
669                                             long checkerCenterAddress,
670                                             long checkerRadiusAddress);
671 
672     /**
673      * Process the data stored in the native test handler and stores the
674      * comparison results.
675      *
676      * @param handlerAddress the memory address of the native test handler
677      * @param testCompareResults the boolean array to store the test comparison
678      * results
679      */
processMeteringTest(long handlerAddress, boolean[] testCompareResults)680     private native void processMeteringTest(long handlerAddress, boolean[] testCompareResults);
681 
682     static {
683         System.loadLibrary("cameraanalyzer");
684     }
685 }
686