1 /*
2  * Copyright (C) 2019 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 android.graphics.cts;
18 
19 import static android.system.OsConstants.SEEK_SET;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.fail;
25 
26 import android.content.ContentResolver;
27 import android.content.res.AssetManager;
28 import android.content.res.Resources;
29 import android.graphics.Bitmap;
30 import android.graphics.BitmapFactory;
31 import android.graphics.Color;
32 import android.graphics.ColorSpace;
33 import android.graphics.ColorSpace.Named;
34 import android.graphics.ImageDecoder;
35 import android.graphics.Rect;
36 import android.graphics.drawable.cts.AnimatedImageDrawableTest;
37 import android.net.Uri;
38 import android.os.ParcelFileDescriptor;
39 import android.system.ErrnoException;
40 import android.system.Os;
41 import android.util.DisplayMetrics;
42 
43 import androidx.test.InstrumentationRegistry;
44 
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 
48 import java.io.File;
49 import java.io.FileDescriptor;
50 import java.io.FileNotFoundException;
51 import java.io.FileOutputStream;
52 import java.io.IOException;
53 import java.io.InputStream;
54 
55 import junitparams.JUnitParamsRunner;
56 import junitparams.Parameters;
57 
58 @RunWith(JUnitParamsRunner.class)
59 public class AImageDecoderTest {
60     static {
61         System.loadLibrary("ctsgraphics_jni");
62     }
63 
getAssetManager()64     private static AssetManager getAssetManager() {
65         return InstrumentationRegistry.getTargetContext().getAssets();
66     }
67 
getResources()68     private static Resources getResources() {
69         return InstrumentationRegistry.getTargetContext().getResources();
70     }
71 
getContentResolver()72     private static ContentResolver getContentResolver() {
73         return InstrumentationRegistry.getTargetContext().getContentResolver();
74     }
75 
76     // These match the formats in the NDK.
77     // ANDROID_BITMAP_FORMAT_NONE is used by nTestDecode to signal using the default.
78     private static final int ANDROID_BITMAP_FORMAT_NONE = 0;
79     private static final int ANDROID_BITMAP_FORMAT_RGB_565 = 4;
80     private static final int ANDROID_BITMAP_FORMAT_A_8 = 8;
81     private static final int ANDROID_BITMAP_FORMAT_RGBA_F16 = 9;
82 
83     @Test
testEmptyCreate()84     public void testEmptyCreate() {
85         nTestEmptyCreate();
86     }
87 
getAssetRecords()88     private static Object[] getAssetRecords() {
89         return ImageDecoderTest.getAssetRecords();
90     }
91 
getRecords()92     private static Object[] getRecords() {
93         return ImageDecoderTest.getRecords();
94     }
95 
96     // For testing all of the assets as premul and unpremul.
getAssetRecordsUnpremul()97     private static Object[] getAssetRecordsUnpremul() {
98         return Utils.crossProduct(getAssetRecords(), new Object[] { true, false });
99     }
100 
getRecordsUnpremul()101     private static Object[] getRecordsUnpremul() {
102         return Utils.crossProduct(getRecords(), new Object[] { true, false });
103     }
104 
105     // For testing all of the assets at different sample sizes.
getAssetRecordsSample()106     private static Object[] getAssetRecordsSample() {
107         return Utils.crossProduct(getAssetRecords(), new Object[] { 2, 3, 4, 8, 16 });
108     }
109 
getRecordsSample()110     private static Object[] getRecordsSample() {
111         return Utils.crossProduct(getRecords(), new Object[] { 2, 3, 4, 8, 16 });
112     }
113 
114     @Test
115     @Parameters(method = "getAssetRecords")
testNullDecoder(ImageDecoderTest.AssetRecord record)116     public void testNullDecoder(ImageDecoderTest.AssetRecord record) {
117         nTestNullDecoder(getAssetManager(), record.name);
118     }
119 
nativeDataSpace(ColorSpace cs)120     private static int nativeDataSpace(ColorSpace cs) {
121         if (cs == null) {
122             return DataSpace.ADATASPACE_UNKNOWN;
123         }
124         return DataSpace.fromColorSpace(cs);
125     }
126 
127     @Test
128     @Parameters(method = "getAssetRecords")
testCreateBuffer(ImageDecoderTest.AssetRecord record)129     public void testCreateBuffer(ImageDecoderTest.AssetRecord record) {
130         // Note: This uses an asset for simplicity, but in native it gets a
131         // buffer.
132         long asset = nOpenAsset(getAssetManager(), record.name);
133         long aimagedecoder = nCreateFromAssetBuffer(asset);
134 
135         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
136                 record.isF16, nativeDataSpace(record.getColorSpace()));
137         nCloseAsset(asset);
138     }
139 
140     @Test
141     @Parameters(method = "getAssetRecords")
testCreateFd(ImageDecoderTest.AssetRecord record)142     public void testCreateFd(ImageDecoderTest.AssetRecord record) {
143         // Note: This uses an asset for simplicity, but in native it gets a
144         // file descriptor.
145         long asset = nOpenAsset(getAssetManager(), record.name);
146         long aimagedecoder = nCreateFromAssetFd(asset);
147 
148         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
149                 record.isF16, nativeDataSpace(record.getColorSpace()));
150         nCloseAsset(asset);
151     }
152 
153     @Test
154     @Parameters(method = "getAssetRecords")
testCreateAsset(ImageDecoderTest.AssetRecord record)155     public void testCreateAsset(ImageDecoderTest.AssetRecord record) {
156         long asset = nOpenAsset(getAssetManager(), record.name);
157         long aimagedecoder = nCreateFromAsset(asset);
158 
159         nTestInfo(aimagedecoder, record.width, record.height, "image/png",
160                 record.isF16, nativeDataSpace(record.getColorSpace()));
161         nCloseAsset(asset);
162     }
163 
open(int resId, int offset)164     private static ParcelFileDescriptor open(int resId, int offset) throws FileNotFoundException {
165         File file = Utils.obtainFile(resId, offset);
166         assertNotNull(file);
167 
168         ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
169                 ParcelFileDescriptor.MODE_READ_ONLY);
170         assertNotNull(pfd);
171         return pfd;
172     }
173 
open(int resId)174     private static ParcelFileDescriptor open(int resId) throws FileNotFoundException {
175         return open(resId, 0);
176     }
177 
178     @Test
179     @Parameters(method = "getRecords")
testCreateFdResources(ImageDecoderTest.Record record)180     public void testCreateFdResources(ImageDecoderTest.Record record) throws IOException {
181         try (ParcelFileDescriptor pfd = open(record.resId)) {
182             long aimagedecoder = nCreateFromFd(pfd.getFd());
183 
184             nTestInfo(aimagedecoder, record.width, record.height, record.mimeType,
185                     false /*isF16*/, nativeDataSpace(record.colorSpace));
186         } catch (FileNotFoundException e) {
187             fail("Could not open " + Utils.getAsResourceUri(record.resId));
188         }
189     }
190 
191     @Test
192     @Parameters(method = "getRecords")
testCreateFdOffset(ImageDecoderTest.Record record)193     public void testCreateFdOffset(ImageDecoderTest.Record record) throws IOException {
194         // Use an arbitrary offset. This ensures that we rewind to the correct offset.
195         final int offset = 15;
196         try (ParcelFileDescriptor pfd = open(record.resId, offset)) {
197             FileDescriptor fd = pfd.getFileDescriptor();
198             Os.lseek(fd, offset, SEEK_SET);
199             long aimagedecoder = nCreateFromFd(pfd.getFd());
200 
201             nTestInfo(aimagedecoder, record.width, record.height, record.mimeType,
202                     false /*isF16*/, nativeDataSpace(record.colorSpace));
203         } catch (FileNotFoundException e) {
204             fail("Could not open " + Utils.getAsResourceUri(record.resId));
205         } catch (ErrnoException err) {
206             fail("Failed to seek " + Utils.getAsResourceUri(record.resId));
207         }
208     }
209 
210     @Test
testCreateIncomplete()211     public void testCreateIncomplete() {
212         String file = "green-srgb.png";
213         // This truncates the file before the IDAT.
214         nTestCreateIncomplete(getAssetManager(), file, 823);
215     }
216 
217     @Test
218     @Parameters({"shaders/tri.frag", "test_video.mp4"})
testUnsupportedFormat(String file)219     public void testUnsupportedFormat(String file) {
220         nTestCreateUnsupported(getAssetManager(), file);
221     }
222 
223     @Test
224     @Parameters(method = "getAssetRecords")
testSetFormat(ImageDecoderTest.AssetRecord record)225     public void testSetFormat(ImageDecoderTest.AssetRecord record) {
226         long asset = nOpenAsset(getAssetManager(), record.name);
227         long aimagedecoder = nCreateFromAsset(asset);
228 
229         nTestSetFormat(aimagedecoder, record.isF16, record.isGray);
230         nCloseAsset(asset);
231     }
232 
233     @Test
234     @Parameters(method = "getRecords")
testSetFormatResources(ImageDecoderTest.Record record)235     public void testSetFormatResources(ImageDecoderTest.Record record) throws IOException {
236         try (ParcelFileDescriptor pfd = open(record.resId)) {
237             long aimagedecoder = nCreateFromFd(pfd.getFd());
238 
239             nTestSetFormat(aimagedecoder, false /* isF16 */, record.isGray);
240         } catch (FileNotFoundException e) {
241             fail("Could not open " + Utils.getAsResourceUri(record.resId));
242         }
243     }
244 
245     @Test
246     @Parameters(method = "getAssetRecords")
testSetUnpremul(ImageDecoderTest.AssetRecord record)247     public void testSetUnpremul(ImageDecoderTest.AssetRecord record) {
248         long asset = nOpenAsset(getAssetManager(), record.name);
249         long aimagedecoder = nCreateFromAsset(asset);
250 
251         nTestSetUnpremul(aimagedecoder, record.hasAlpha);
252         nCloseAsset(asset);
253     }
254 
255     @Test
256     @Parameters(method = "getRecords")
testSetUnpremulResources(ImageDecoderTest.Record record)257     public void testSetUnpremulResources(ImageDecoderTest.Record record) throws IOException {
258         try (ParcelFileDescriptor pfd = open(record.resId)) {
259             long aimagedecoder = nCreateFromFd(pfd.getFd());
260 
261             nTestSetUnpremul(aimagedecoder, record.hasAlpha);
262         } catch (FileNotFoundException e) {
263             fail("Could not open " + Utils.getAsResourceUri(record.resId));
264         }
265     }
266 
267     @Test
268     @Parameters(method = "getAssetRecords")
testGetMinimumStride(ImageDecoderTest.AssetRecord record)269     public void testGetMinimumStride(ImageDecoderTest.AssetRecord record) {
270         long asset = nOpenAsset(getAssetManager(), record.name);
271         long aimagedecoder = nCreateFromAsset(asset);
272 
273         nTestGetMinimumStride(aimagedecoder, record.isF16, record.isGray);
274     }
275 
276     @Test
277     @Parameters(method = "getRecords")
testGetMinimumStrideResources(ImageDecoderTest.Record record)278     public void testGetMinimumStrideResources(ImageDecoderTest.Record record) throws IOException {
279         try (ParcelFileDescriptor pfd = open(record.resId)) {
280             long aimagedecoder = nCreateFromFd(pfd.getFd());
281 
282             nTestGetMinimumStride(aimagedecoder, false /* isF16 */, record.isGray);
283         } catch (FileNotFoundException e) {
284             fail("Could not open " + Utils.getAsResourceUri(record.resId));
285         }
286     }
287 
decode(ImageDecoder.Source src, boolean unpremul)288     private static Bitmap decode(ImageDecoder.Source src, boolean unpremul) {
289         try {
290             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
291                 // So we can compare pixels to the native decode.
292                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
293                 decoder.setUnpremultipliedRequired(unpremul);
294             });
295         } catch (IOException e) {
296             fail("Failed to decode in Java with " + e);
297             return null;
298         }
299     }
300 
decode(int resId, boolean unpremul)301     private static Bitmap decode(int resId, boolean unpremul) {
302         // This test relies on ImageDecoder *not* scaling to account for density.
303         // Temporarily change the DisplayMetrics to prevent that scaling.
304         Resources res = getResources();
305         final int originalDensity = res.getDisplayMetrics().densityDpi;
306         try {
307             res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT;
308             ImageDecoder.Source src = ImageDecoder.createSource(res, resId);
309             return decode(src, unpremul);
310         } finally {
311             res.getDisplayMetrics().densityDpi = originalDensity;
312         }
313     }
314 
315     @Test
316     @Parameters(method = "getAssetRecordsUnpremul")
testDecode(ImageDecoderTest.AssetRecord record, boolean unpremul)317     public void testDecode(ImageDecoderTest.AssetRecord record, boolean unpremul) {
318         AssetManager assets = getAssetManager();
319         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
320         Bitmap bm = decode(src, unpremul);
321 
322         long asset = nOpenAsset(assets, record.name);
323         long aimagedecoder = nCreateFromAsset(asset);
324 
325         nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, unpremul, bm);
326         nCloseAsset(asset);
327     }
328 
329     @Test
330     @Parameters(method = "getRecordsUnpremul")
testDecodeResources(ImageDecoderTest.Record record, boolean unpremul)331     public void testDecodeResources(ImageDecoderTest.Record record, boolean unpremul)
332             throws IOException {
333         Bitmap bm = decode(record.resId, unpremul);
334         try (ParcelFileDescriptor pfd = open(record.resId)) {
335             long aimagedecoder = nCreateFromFd(pfd.getFd());
336 
337             nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, unpremul, bm);
338         } catch (FileNotFoundException e) {
339             fail("Could not open " + Utils.getAsResourceUri(record.resId));
340         }
341     }
342 
decode(ImageDecoder.Source src, Bitmap.Config config)343     private static Bitmap decode(ImageDecoder.Source src, Bitmap.Config config) {
344         try {
345             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
346                 // So we can compare pixels to the native decode.
347                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
348                 switch (config) {
349                     case RGB_565:
350                         decoder.setMemorySizePolicy(ImageDecoder.MEMORY_POLICY_LOW_RAM);
351                         break;
352                     case ALPHA_8:
353                         decoder.setDecodeAsAlphaMaskEnabled(true);
354                         break;
355                     default:
356                         fail("Unexpected Config " + config);
357                         break;
358                 }
359             });
360         } catch (IOException e) {
361             fail("Failed to decode in Java with " + e);
362             return null;
363         }
364     }
365 
366     private static Bitmap decode(int resId, Bitmap.Config config) {
367         // This test relies on ImageDecoder *not* scaling to account for density.
368         // Temporarily change the DisplayMetrics to prevent that scaling.
369         Resources res = getResources();
370         final int originalDensity = res.getDisplayMetrics().densityDpi;
371         try {
372             res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT;
373             ImageDecoder.Source src = ImageDecoder.createSource(res, resId);
374             return decode(src, config);
375         } finally {
376             res.getDisplayMetrics().densityDpi = originalDensity;
377         }
378     }
379 
380     @Test
381     @Parameters(method = "getAssetRecords")
382     public void testDecode565(ImageDecoderTest.AssetRecord record) {
383         AssetManager assets = getAssetManager();
384         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
385         Bitmap bm = decode(src, Bitmap.Config.RGB_565);
386 
387         if (bm.getConfig() != Bitmap.Config.RGB_565) {
388             bm = null;
389         }
390 
391         long asset = nOpenAsset(assets, record.name);
392         long aimagedecoder = nCreateFromAsset(asset);
393 
394         nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGB_565, false, bm);
395         nCloseAsset(asset);
396     }
397 
398     @Test
399     @Parameters(method = "getRecords")
400     public void testDecode565Resources(ImageDecoderTest.Record record)
401             throws IOException {
402         Bitmap bm = decode(record.resId, Bitmap.Config.RGB_565);
403 
404         if (bm.getConfig() != Bitmap.Config.RGB_565) {
405             bm = null;
406         }
407 
408         try (ParcelFileDescriptor pfd = open(record.resId)) {
409             long aimagedecoder = nCreateFromFd(pfd.getFd());
410 
411             nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGB_565, false, bm);
412         } catch (FileNotFoundException e) {
413             fail("Could not open " + Utils.getAsResourceUri(record.resId));
414         }
415     }
416 
417     @Test
418     @Parameters("grayscale-linearSrgb.png")
419     public void testDecodeA8(String name) {
420         AssetManager assets = getAssetManager();
421         ImageDecoder.Source src = ImageDecoder.createSource(assets, name);
422         Bitmap bm = decode(src, Bitmap.Config.ALPHA_8);
423 
424         assertNotNull(bm);
425         assertNull(bm.getColorSpace());
426         assertEquals(Bitmap.Config.ALPHA_8, bm.getConfig());
427 
428         long asset = nOpenAsset(assets, name);
429         long aimagedecoder = nCreateFromAsset(asset);
430 
431         nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_A_8, false, bm);
432         nCloseAsset(asset);
433     }
434 
435     @Test
436     public void testDecodeA8Resources()
437             throws IOException {
438         final int resId = R.drawable.grayscale_jpg;
439         Bitmap bm = decode(resId, Bitmap.Config.ALPHA_8);
440 
441         assertNotNull(bm);
442         assertNull(bm.getColorSpace());
443         assertEquals(Bitmap.Config.ALPHA_8, bm.getConfig());
444 
445         try (ParcelFileDescriptor pfd = open(resId)) {
446             long aimagedecoder = nCreateFromFd(pfd.getFd());
447 
448             nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_A_8, false, bm);
449         } catch (FileNotFoundException e) {
450             fail("Could not open " + Utils.getAsResourceUri(resId));
451         }
452     }
453 
454     @Test
455     @Parameters(method = "getAssetRecordsUnpremul")
456     public void testDecodeF16(ImageDecoderTest.AssetRecord record, boolean unpremul) {
457         AssetManager assets = getAssetManager();
458 
459         // ImageDecoder doesn't allow forcing a decode to F16, so use BitmapFactory.
460         BitmapFactory.Options options = new BitmapFactory.Options();
461         options.inPreferredConfig = Bitmap.Config.RGBA_F16;
462         options.inPremultiplied = !unpremul;
463 
464         InputStream is = null;
465         try {
466             is = assets.open(record.name);
467         } catch (IOException e) {
468             fail("Failed to open " + record.name + " with " + e);
469         }
470         assertNotNull(is);
471 
472         Bitmap bm = BitmapFactory.decodeStream(is, null, options);
473         assertNotNull(bm);
474 
475         long asset = nOpenAsset(assets, record.name);
476         long aimagedecoder = nCreateFromAsset(asset);
477 
478         nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGBA_F16, unpremul, bm);
479         nCloseAsset(asset);
480     }
481 
482     @Test
483     @Parameters(method = "getRecordsUnpremul")
484     public void testDecodeF16Resources(ImageDecoderTest.Record record, boolean unpremul)
485             throws IOException {
486         // ImageDecoder doesn't allow forcing a decode to F16, so use BitmapFactory.
487         BitmapFactory.Options options = new BitmapFactory.Options();
488         options.inPreferredConfig = Bitmap.Config.RGBA_F16;
489         options.inPremultiplied = !unpremul;
490         options.inScaled = false;
491 
492         Bitmap bm = BitmapFactory.decodeResource(getResources(),
493                 record.resId, options);
494         assertNotNull(bm);
495 
496         try (ParcelFileDescriptor pfd = open(record.resId)) {
497             long aimagedecoder = nCreateFromFd(pfd.getFd());
498 
499             nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_RGBA_F16, unpremul, bm);
500         } catch (FileNotFoundException e) {
501             fail("Could not open " + Utils.getAsResourceUri(record.resId));
502         }
503     }
504 
505     @Test
506     @Parameters(method = "getAssetRecords")
507     public void testDecodeStride(ImageDecoderTest.AssetRecord record) {
508         long asset = nOpenAsset(getAssetManager(), record.name);
509         long aimagedecoder = nCreateFromAsset(asset);
510         nTestDecodeStride(aimagedecoder);
511         nCloseAsset(asset);
512     }
513 
514     @Test
515     @Parameters(method = "getRecords")
516     public void testDecodeStrideResources(ImageDecoderTest.Record record)
517             throws IOException {
518         try (ParcelFileDescriptor pfd = open(record.resId)) {
519             long aimagedecoder = nCreateFromFd(pfd.getFd());
520 
521             nTestDecodeStride(aimagedecoder);
522         } catch (FileNotFoundException e) {
523             fail("Could not open " + Utils.getAsResourceUri(record.resId));
524         }
525     }
526 
527     @Test
528     @Parameters(method = "getAssetRecords")
529     public void testSetTargetSize(ImageDecoderTest.AssetRecord record) {
530         long asset = nOpenAsset(getAssetManager(), record.name);
531         long aimagedecoder = nCreateFromAsset(asset);
532         nTestSetTargetSize(aimagedecoder);
533         nCloseAsset(asset);
534     }
535 
536     @Test
537     @Parameters(method = "getRecords")
538     public void testSetTargetSizeResources(ImageDecoderTest.Record record)
539             throws IOException {
540         try (ParcelFileDescriptor pfd = open(record.resId)) {
541             long aimagedecoder = nCreateFromFd(pfd.getFd());
542 
543             nTestSetTargetSize(aimagedecoder);
544         } catch (FileNotFoundException e) {
545             fail("Could not open " + Utils.getAsResourceUri(record.resId));
546         }
547     }
548 
549     private Bitmap decodeSampled(String name, ImageDecoder.Source src, int sampleSize) {
550         try {
551             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
552                 // So we can compare pixels to the native decode.
553                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
554                 decoder.setTargetSampleSize(sampleSize);
555             });
556         } catch (IOException e) {
557             fail("Failed to decode " + name + " in Java (sampleSize: "
558                     + sampleSize + ") with " + e);
559             return null;
560         }
561     }
562 
563     @Test
564     @Parameters(method = "getAssetRecordsSample")
565     public void testDecodeSampled(ImageDecoderTest.AssetRecord record, int sampleSize) {
566         AssetManager assets = getAssetManager();
567         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
568         Bitmap bm = decodeSampled(record.name, src, sampleSize);
569 
570         long asset = nOpenAsset(assets, record.name);
571         long aimagedecoder = nCreateFromAsset(asset);
572 
573         nTestDecodeScaled(aimagedecoder, bm);
574         nCloseAsset(asset);
575     }
576 
577     @Test
578     @Parameters(method = "getRecordsSample")
579     public void testDecodeResourceSampled(ImageDecoderTest.Record record, int sampleSize)
580             throws IOException {
581         ImageDecoder.Source src = ImageDecoder.createSource(getResources(),
582                 record.resId);
583         String name = Utils.getAsResourceUri(record.resId).toString();
584         Bitmap bm = decodeSampled(name, src, sampleSize);
585         assertNotNull(bm);
586 
587         try (ParcelFileDescriptor pfd = open(record.resId)) {
588             long aimagedecoder = nCreateFromFd(pfd.getFd());
589 
590             nTestDecodeScaled(aimagedecoder, bm);
591         } catch (FileNotFoundException e) {
592             fail("Could not open " + name + ": " + e);
593         }
594     }
595 
596     @Test
597     @Parameters(method = "getRecordsSample")
598     public void testComputeSampledSize(ImageDecoderTest.Record record, int sampleSize)
599             throws IOException {
600         if (record.mimeType.equals("image/x-adobe-dng")) {
601             // SkRawCodec does not support sampling.
602             return;
603         }
604         testComputeSampledSizeInternal(record.resId, sampleSize);
605     }
606 
607     private void testComputeSampledSizeInternal(int resId, int sampleSize)
608             throws IOException {
609         ImageDecoder.Source src = ImageDecoder.createSource(getResources(), resId);
610         String name = Utils.getAsResourceUri(resId).toString();
611         Bitmap bm = decodeSampled(name, src, sampleSize);
612         assertNotNull(bm);
613 
614         try (ParcelFileDescriptor pfd = open(resId)) {
615             long aimagedecoder = nCreateFromFd(pfd.getFd());
616 
617             nTestComputeSampledSize(aimagedecoder, bm, sampleSize);
618         } catch (FileNotFoundException e) {
619             fail("Could not open " + name + ": " + e);
620         }
621     }
622 
623     private static Object[] getExifsSample() {
624         return Utils.crossProduct(getExifImages(), new Object[] { 2, 3, 4, 8, 16 });
625     }
626 
627     @Test
628     @Parameters(method = "getExifsSample")
629     public void testComputeSampledSizeExif(int resId, int sampleSize)
630             throws IOException {
631         testComputeSampledSizeInternal(resId, sampleSize);
632     }
633 
634     private Bitmap decodeScaled(String name, ImageDecoder.Source src) {
635         try {
636             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
637                 // So we can compare pixels to the native decode.
638                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
639 
640                 // Scale to an arbitrary width and height.
641                 decoder.setTargetSize(300, 300);
642             });
643         } catch (IOException e) {
644             fail("Failed to decode " + name + " in Java (size: "
645                     + "300 x 300) with " + e);
646             return null;
647         }
648     }
649 
650     @Test
651     @Parameters(method = "getAssetRecords")
652     public void testDecodeScaled(ImageDecoderTest.AssetRecord record) {
653         AssetManager assets = getAssetManager();
654         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
655         Bitmap bm = decodeScaled(record.name, src);
656 
657         long asset = nOpenAsset(assets, record.name);
658         long aimagedecoder = nCreateFromAsset(asset);
659 
660         nTestDecodeScaled(aimagedecoder, bm);
661         nCloseAsset(asset);
662     }
663 
664     @Test
665     @Parameters(method = "getRecords")
666     public void testDecodeResourceScaled(ImageDecoderTest.Record record)
667             throws IOException {
668         ImageDecoder.Source src = ImageDecoder.createSource(getResources(),
669                 record.resId);
670         String name = Utils.getAsResourceUri(record.resId).toString();
671         Bitmap bm = decodeScaled(name, src);
672         assertNotNull(bm);
673 
674         try (ParcelFileDescriptor pfd = open(record.resId)) {
675             long aimagedecoder = nCreateFromFd(pfd.getFd());
676 
677             nTestDecodeScaled(aimagedecoder, bm);
678         } catch (FileNotFoundException e) {
679             fail("Could not open " + name + ": " + e);
680         }
681     }
682 
683     private Bitmap decodeScaleUp(String name, ImageDecoder.Source src) {
684         try {
685             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
686                 // So we can compare pixels to the native decode.
687                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
688 
689                 decoder.setTargetSize(info.getSize().getWidth() * 2,
690                         info.getSize().getHeight() * 2);
691             });
692         } catch (IOException e) {
693             fail("Failed to decode " + name + " in Java (scaled up) with " + e);
694             return null;
695         }
696     }
697 
698     @Test
699     @Parameters(method = "getAssetRecords")
700     public void testDecodeScaleUp(ImageDecoderTest.AssetRecord record) {
701         AssetManager assets = getAssetManager();
702         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
703         Bitmap bm = decodeScaleUp(record.name, src);
704 
705         long asset = nOpenAsset(assets, record.name);
706         long aimagedecoder = nCreateFromAsset(asset);
707 
708         nTestDecodeScaled(aimagedecoder, bm);
709         nCloseAsset(asset);
710     }
711 
712     @Test
713     @Parameters(method = "getRecords")
714     public void testDecodeResourceScaleUp(ImageDecoderTest.Record record)
715             throws IOException {
716         ImageDecoder.Source src = ImageDecoder.createSource(getResources(),
717                 record.resId);
718         String name = Utils.getAsResourceUri(record.resId).toString();
719         Bitmap bm = decodeScaleUp(name, src);
720         assertNotNull(bm);
721 
722         try (ParcelFileDescriptor pfd = open(record.resId)) {
723             long aimagedecoder = nCreateFromFd(pfd.getFd());
724 
725             nTestDecodeScaled(aimagedecoder, bm);
726         } catch (FileNotFoundException e) {
727             fail("Could not open " + name + ": " + e);
728         }
729     }
730 
731     @Test
732     @Parameters(method = "getAssetRecords")
733     public void testSetCrop(ImageDecoderTest.AssetRecord record) {
734         nTestSetCrop(getAssetManager(), record.name);
735     }
736 
737     private static class Cropper implements ImageDecoder.OnHeaderDecodedListener {
738         Cropper(boolean scale) {
739             mScale = scale;
740         }
741 
742         public boolean withScale() {
743             return mScale;
744         }
745 
746         public int getWidth() {
747             return mWidth;
748         }
749 
750         public int getHeight() {
751             return mHeight;
752         }
753 
754         public Rect getCropRect() {
755             return mCropRect;
756         }
757 
758         @Override
759         public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
760                 ImageDecoder.Source source) {
761             mWidth = info.getSize().getWidth();
762             mHeight = info.getSize().getHeight();
763             if (mScale) {
764                 mWidth = 40;
765                 mHeight = 40;
766                 decoder.setTargetSize(mWidth, mHeight);
767             }
768 
769             mCropRect = new Rect(mWidth / 2, mHeight / 2, mWidth, mHeight);
770             decoder.setCrop(mCropRect);
771 
772             // So we can compare pixels to the native decode.
773             decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
774         }
775 
776         private final boolean mScale;
777         private Rect mCropRect;
778         private int mWidth;
779         private int mHeight;
780     }
781 
782     private static Bitmap decodeCropped(String name, Cropper cropper, ImageDecoder.Source src) {
783         try {
784             return ImageDecoder.decodeBitmap(src, cropper);
785         } catch (IOException e) {
786             fail("Failed to decode " + name + " in Java with "
787                     + (cropper.withScale() ? "scale and " : "a ") + "crop ("
788                     + cropper.getCropRect() + "): " + e);
789             return null;
790         }
791     }
792 
793     private static Bitmap decodeCropped(String name, Cropper cropper, int resId) {
794         // This test relies on ImageDecoder *not* scaling to account for density.
795         // Temporarily change the DisplayMetrics to prevent that scaling.
796         Resources res = getResources();
797         final int originalDensity = res.getDisplayMetrics().densityDpi;
798         try {
799             res.getDisplayMetrics().densityDpi = DisplayMetrics.DENSITY_DEFAULT;
800             ImageDecoder.Source src = ImageDecoder.createSource(res, resId);
801             return decodeCropped(name, cropper, src);
802         } finally {
803             res.getDisplayMetrics().densityDpi = originalDensity;
804         }
805     }
806 
807     @Test
808     @Parameters(method = "getAssetRecords")
809     public void testCrop(ImageDecoderTest.AssetRecord record) {
810         AssetManager assets = getAssetManager();
811         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
812         Cropper cropper = new Cropper(false /* scale */);
813         Bitmap bm = decodeCropped(record.name, cropper, src);
814 
815         long asset = nOpenAsset(assets, record.name);
816         long aimagedecoder = nCreateFromAsset(asset);
817 
818         Rect crop = cropper.getCropRect();
819         nTestDecodeCrop(aimagedecoder, bm, 0, 0, crop.left, crop.top, crop.right, crop.bottom);
820         nCloseAsset(asset);
821     }
822 
823     @Test
824     @Parameters(method = "getRecords")
825     public void testCropResource(ImageDecoderTest.Record record)
826             throws IOException {
827         String name = Utils.getAsResourceUri(record.resId).toString();
828         Cropper cropper = new Cropper(false /* scale */);
829         Bitmap bm = decodeCropped(name, cropper, record.resId);
830         assertNotNull(bm);
831 
832         try (ParcelFileDescriptor pfd = open(record.resId)) {
833             long aimagedecoder = nCreateFromFd(pfd.getFd());
834 
835             Rect crop = cropper.getCropRect();
836             nTestDecodeCrop(aimagedecoder, bm, 0, 0, crop.left, crop.top, crop.right, crop.bottom);
837         } catch (FileNotFoundException e) {
838             fail("Could not open " + name + ": " + e);
839         }
840     }
841 
842     @Test
843     @Parameters(method = "getAssetRecords")
844     public void testCropAndScale(ImageDecoderTest.AssetRecord record) {
845         AssetManager assets = getAssetManager();
846         ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
847         Cropper cropper = new Cropper(true /* scale */);
848         Bitmap bm = decodeCropped(record.name, cropper, src);
849 
850         long asset = nOpenAsset(assets, record.name);
851         long aimagedecoder = nCreateFromAsset(asset);
852 
853         Rect crop = cropper.getCropRect();
854         nTestDecodeCrop(aimagedecoder, bm, cropper.getWidth(), cropper.getHeight(),
855                 crop.left, crop.top, crop.right, crop.bottom);
856         nCloseAsset(asset);
857     }
858 
859     @Test
860     @Parameters(method = "getRecords")
861     public void testCropAndScaleResource(ImageDecoderTest.Record record)
862             throws IOException {
863         ImageDecoder.Source src = ImageDecoder.createSource(getResources(),
864                 record.resId);
865         String name = Utils.getAsResourceUri(record.resId).toString();
866         Cropper cropper = new Cropper(true /* scale */);
867         Bitmap bm = decodeCropped(name, cropper, src);
868         assertNotNull(bm);
869 
870         try (ParcelFileDescriptor pfd = open(record.resId)) {
871             long aimagedecoder = nCreateFromFd(pfd.getFd());
872 
873             Rect crop = cropper.getCropRect();
874             nTestDecodeCrop(aimagedecoder, bm, cropper.getWidth(), cropper.getHeight(),
875                     crop.left, crop.top, crop.right, crop.bottom);
876         } catch (FileNotFoundException e) {
877             fail("Could not open " + name + ": " + e);
878         }
879     }
880 
881     private static Object[] getExifImages() {
882         return new Object[] {
883             R.drawable.orientation_1,
884             R.drawable.orientation_2,
885             R.drawable.orientation_3,
886             R.drawable.orientation_4,
887             R.drawable.orientation_5,
888             R.drawable.orientation_6,
889             R.drawable.orientation_7,
890             R.drawable.orientation_8,
891             R.drawable.webp_orientation1,
892             R.drawable.webp_orientation2,
893             R.drawable.webp_orientation3,
894             R.drawable.webp_orientation4,
895             R.drawable.webp_orientation5,
896             R.drawable.webp_orientation6,
897             R.drawable.webp_orientation7,
898             R.drawable.webp_orientation8,
899         };
900     }
901 
902     @Test
903     @Parameters(method = "getExifImages")
904     public void testRespectOrientation(int resId) throws IOException {
905         Uri uri = Utils.getAsResourceUri(resId);
906         ImageDecoder.Source src = ImageDecoder.createSource(getContentResolver(),
907                 uri);
908         Bitmap bm = decode(src, false /* unpremul */);
909         assertNotNull(bm);
910         assertEquals(100, bm.getWidth());
911         assertEquals(80,  bm.getHeight());
912 
913         // First verify that the info (and in particular, the width and height)
914         // are correct. This uses a separate ParcelFileDescriptor/aimagedecoder
915         // because the native methods delete the aimagedecoder.
916         try (ParcelFileDescriptor pfd = open(resId)) {
917             long aimagedecoder = nCreateFromFd(pfd.getFd());
918 
919             String mimeType = uri.toString().contains("webp") ? "image/webp" : "image/jpeg";
920             nTestInfo(aimagedecoder, 100, 80, mimeType, false,
921                     DataSpace.fromColorSpace(bm.getColorSpace()));
922         } catch (FileNotFoundException e) {
923             e.printStackTrace();
924             fail("Could not open " + uri + " to check info");
925         }
926 
927         try (ParcelFileDescriptor pfd = open(resId)) {
928             long aimagedecoder = nCreateFromFd(pfd.getFd());
929 
930             nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, false /* unpremul */, bm);
931         } catch (FileNotFoundException e) {
932             e.printStackTrace();
933             fail("Could not open " + uri);
934         }
935         bm.recycle();
936     }
937 
938     @Test
939     @Parameters(method = "getAssetRecords")
940     public void testScalePlusUnpremul(ImageDecoderTest.AssetRecord record) {
941         long asset = nOpenAsset(getAssetManager(), record.name);
942         long aimagedecoder = nCreateFromAsset(asset);
943 
944         nTestScalePlusUnpremul(aimagedecoder);
945         nCloseAsset(asset);
946     }
947 
948     private static File createCompressedBitmap(int width, int height, ColorSpace colorSpace,
949             Bitmap.CompressFormat format) {
950         File dir = InstrumentationRegistry.getTargetContext().getFilesDir();
951         dir.mkdirs();
952 
953         File file = new File(dir, colorSpace.getName());
954         try {
955             file.createNewFile();
956         } catch (IOException e) {
957             e.printStackTrace();
958             // If the file does not exist it will be handled below.
959         }
960         if (!file.exists()) {
961             fail("Failed to create new File for " + file + "!");
962         }
963 
964         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888, true,
965                 colorSpace);
966         bitmap.eraseColor(Color.BLUE);
967 
968         try (FileOutputStream fOutput = new FileOutputStream(file)) {
969             bitmap.compress(format, 80, fOutput);
970             return file;
971         } catch (IOException e) {
972             e.printStackTrace();
973             fail("Failed to create file \"" + file + "\" with exception " + e);
974             return null;
975         }
976     }
977 
978     private static Object[] rgbColorSpaces() {
979         return BitmapTest.getRgbColorSpaces().toArray();
980     }
981 
982     private static Object[] rgbColorSpacesAndCompressFormats() {
983         return Utils.crossProduct(rgbColorSpaces(), Bitmap.CompressFormat.values());
984     }
985 
986     String toMimeType(Bitmap.CompressFormat format) {
987         switch (format) {
988             case JPEG:
989                 return "image/jpeg";
990             case PNG:
991                 return "image/png";
992             case WEBP:
993             case WEBP_LOSSY:
994             case WEBP_LOSSLESS:
995                 return "image/webp";
996             default:
997                 return "";
998         }
999     }
1000 
1001     @Test
1002     @Parameters(method = "rgbColorSpacesAndCompressFormats")
1003     public void testGetDataSpace(ColorSpace colorSpace, Bitmap.CompressFormat format) {
1004         if (colorSpace == ColorSpace.get(Named.EXTENDED_SRGB)
1005                 || colorSpace == ColorSpace.get(Named.LINEAR_EXTENDED_SRGB)) {
1006             // These will only be reported when the default AndroidBitmapFormat is F16.
1007             // Bitmap.compress will not compress to an image that will be decoded as F16 by default,
1008             // so these are covered by the AssetRecord tests.
1009             return;
1010         }
1011 
1012         final int width = 10;
1013         final int height = 10;
1014         File file = createCompressedBitmap(width, height, colorSpace, format);
1015         assertNotNull(file);
1016 
1017         int dataSpace = DataSpace.fromColorSpace(colorSpace);
1018 
1019         try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file,
1020                 ParcelFileDescriptor.MODE_READ_ONLY)) {
1021             long aimagedecoder = nCreateFromFd(pfd.getFd());
1022             nTestInfo(aimagedecoder, width, height, toMimeType(format), false, dataSpace);
1023         } catch (IOException e) {
1024             e.printStackTrace();
1025             fail("Could not read " + file);
1026         }
1027     }
1028 
1029     private static Bitmap decode(ImageDecoder.Source src, ColorSpace colorSpace) {
1030         try {
1031             return ImageDecoder.decodeBitmap(src, (decoder, info, source) -> {
1032                 // So we can compare pixels to the native decode.
1033                 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
1034 
1035                 decoder.setTargetColorSpace(colorSpace);
1036             });
1037         } catch (IOException e) {
1038             fail("Failed to decode in Java with " + e);
1039             return null;
1040         }
1041     }
1042 
1043     @Test
1044     @Parameters(method = "rgbColorSpaces")
1045     public void testSetDataSpace(ColorSpace colorSpace) {
1046         int dataSpace = DataSpace.fromColorSpace(colorSpace);
1047         if (dataSpace == DataSpace.ADATASPACE_UNKNOWN) {
1048             // AImageDecoder cannot decode to these ADATASPACEs
1049             return;
1050         }
1051 
1052         String name = "translucent-green-p3.png";
1053         AssetManager assets = getAssetManager();
1054         ImageDecoder.Source src = ImageDecoder.createSource(assets, name);
1055         Bitmap bm = decode(src, colorSpace);
1056         assertEquals(colorSpace, bm.getColorSpace());
1057 
1058         long asset = nOpenAsset(assets, name);
1059         long aimagedecoder = nCreateFromAsset(asset);
1060 
1061         nTestDecode(aimagedecoder, bm, dataSpace);
1062         nCloseAsset(asset);
1063     }
1064 
1065     @Test
1066     @Parameters({ "cmyk_yellow_224_224_32.jpg", "wide_gamut_yellow_224_224_64.jpeg" })
1067     public void testNonStandardDataSpaces(String name) {
1068         AssetManager assets = getAssetManager();
1069         long asset = nOpenAsset(assets, name);
1070         long aimagedecoder = nCreateFromAsset(asset);
1071 
1072         // These images have profiles that do not map to ADataSpaces (or even SkColorSpaces).
1073         // Verify that by default, AImageDecoder will treat them as ADATASPACE_UNKNOWN.
1074         nTestInfo(aimagedecoder, 32, 32, "image/jpeg", false, DataSpace.ADATASPACE_UNKNOWN);
1075         nCloseAsset(asset);
1076     }
1077 
1078     @Test
1079     @Parameters({ "cmyk_yellow_224_224_32.jpg,#FFD8FC04",
1080                   "wide_gamut_yellow_224_224_64.jpeg,#FFE0E040" })
1081     public void testNonStandardDataSpacesDecode(String name, String color) {
1082         AssetManager assets = getAssetManager();
1083         long asset = nOpenAsset(assets, name);
1084         long aimagedecoder = nCreateFromAsset(asset);
1085 
1086         // These images are each a solid color. If we correctly do no color correction, they should
1087         // match |color|.
1088         int colorInt = Color.parseColor(color);
1089         Bitmap bm = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
1090         bm.eraseColor(colorInt);
1091 
1092         nTestDecode(aimagedecoder, ANDROID_BITMAP_FORMAT_NONE, false /* unpremul */, bm);
1093         nCloseAsset(asset);
1094     }
1095 
1096     @Test
1097     @Parameters(method = "getAssetRecords")
1098     public void testNotAnimatedAssets(ImageDecoderTest.AssetRecord record) {
1099         long asset = nOpenAsset(getAssetManager(), record.name);
1100         long aimagedecoder = nCreateFromAsset(asset);
1101 
1102         nTestIsAnimated(aimagedecoder, false);
1103         nCloseAsset(asset);
1104     }
1105 
1106     @Test
1107     @Parameters(method = "getRecords")
1108     public void testNotAnimated(ImageDecoderTest.Record record) throws IOException {
1109         try (ParcelFileDescriptor pfd = open(record.resId)) {
1110             long aimagedecoder = nCreateFromFd(pfd.getFd());
1111 
1112             nTestIsAnimated(aimagedecoder, false);
1113         } catch (FileNotFoundException e) {
1114             fail("Could not open " + Utils.getAsResourceUri(record.resId));
1115         }
1116     }
1117 
1118     private static Object[] getAnimatedImagesPlusRepeatCounts() {
1119         return AnimatedImageDrawableTest.parametersForTestEncodedRepeats();
1120     }
1121 
1122     // Although these images have an encoded repeat count, they have only one frame,
1123     // so they are not considered animated.
1124     @Test
1125     @Parameters({"still_with_loop_count.gif", "webp_still_with_loop_count.webp"})
1126     public void testStill(String name) {
1127         long asset = nOpenAsset(getAssetManager(), name);
1128         long aimagedecoder = nCreateFromAsset(asset);
1129 
1130         nTestIsAnimated(aimagedecoder, false);
1131         nCloseAsset(asset);
1132     }
1133 
1134     @Test
1135     @Parameters(method = "getAnimatedImagesPlusRepeatCounts")
1136     public void testAnimated(int resId, int unused) throws IOException {
1137         try (ParcelFileDescriptor pfd = open(resId)) {
1138             long aimagedecoder = nCreateFromFd(pfd.getFd());
1139 
1140             nTestIsAnimated(aimagedecoder, true);
1141         } catch (FileNotFoundException e) {
1142             fail("Could not open " + Utils.getAsResourceUri(resId));
1143         }
1144     }
1145 
1146     @Test
1147     @Parameters(method = "getAnimatedImagesPlusRepeatCounts")
1148     public void testRepeatCount(int resId, int repeatCount) throws IOException {
1149         try (ParcelFileDescriptor pfd = open(resId)) {
1150             long aimagedecoder = nCreateFromFd(pfd.getFd());
1151 
1152             nTestRepeatCount(aimagedecoder, repeatCount);
1153         } catch (FileNotFoundException e) {
1154             fail("Could not open " + Utils.getAsResourceUri(resId));
1155         }
1156     }
1157 
1158     @Test
1159     @Parameters({"still_with_loop_count.gif, 1", "webp_still_with_loop_count.webp,31999"})
1160     public void testRepeatCountStill(String name, int repeatCount) {
1161         long asset = nOpenAsset(getAssetManager(), name);
1162         long aimagedecoder = nCreateFromAsset(asset);
1163 
1164         nTestRepeatCount(aimagedecoder, repeatCount);
1165         nCloseAsset(asset);
1166     }
1167 
1168     // Return a pointer to the native AAsset named |file|. Must be closed with nCloseAsset.
1169     // Throws an Exception on failure.
1170     private static native long nOpenAsset(AssetManager assets, String file);
1171     private static native void nCloseAsset(long asset);
1172 
1173     // Methods for creating and returning a pointer to an AImageDecoder. All
1174     // throw an Exception on failure.
1175     private static native long nCreateFromFd(int fd);
1176     private static native long nCreateFromAsset(long asset);
1177     private static native long nCreateFromAssetFd(long asset);
1178     private static native long nCreateFromAssetBuffer(long asset);
1179 
1180     private static native void nTestEmptyCreate();
1181     private static native void nTestNullDecoder(AssetManager assets, String file);
1182     private static native void nTestCreateIncomplete(AssetManager assets,
1183             String file, int truncatedLength);
1184     private static native void nTestCreateUnsupported(AssetManager assets, String file);
1185 
1186     // For convenience, all methods that take aimagedecoder as a parameter delete
1187     // it.
1188     private static native void nTestInfo(long aimagedecoder, int width, int height,
1189             String mimeType, boolean isF16, int dataspace);
1190     private static native void nTestSetFormat(long aimagedecoder, boolean isF16, boolean isGray);
1191     private static native void nTestSetUnpremul(long aimagedecoder, boolean hasAlpha);
1192     private static native void nTestGetMinimumStride(long aimagedecoder,
1193             boolean isF16, boolean isGray);
1194     private static native void nTestDecode(long aimagedecoder,
1195             int requestedAndroidBitmapFormat, boolean unpremul, Bitmap bitmap);
1196     private static native void nTestDecodeStride(long aimagedecoder);
1197     private static native void nTestSetTargetSize(long aimagedecoder);
1198     // Decode with the target width and height to match |bitmap|.
1199     private static native void nTestDecodeScaled(long aimagedecoder, Bitmap bitmap);
1200     private static native void nTestComputeSampledSize(long aimagedecoder, Bitmap bm,
1201             int sampleSize);
1202     private static native void nTestSetCrop(AssetManager assets, String file);
1203     // Decode and compare to |bitmap|, where they both use the specified target
1204     // size and crop rect. target size of 0 means to skip scaling.
1205     private static native void nTestDecodeCrop(long aimagedecoder,
1206             Bitmap bitmap, int targetWidth, int targetHeight,
1207             int cropLeft, int cropTop, int cropRight, int cropBottom);
1208     private static native void nTestScalePlusUnpremul(long aimagedecoder);
1209     private static native void nTestDecode(long aimagedecoder, Bitmap bm, int dataSpace);
1210     private static native void nTestIsAnimated(long aimagedecoder, boolean animated);
1211     private static native void nTestRepeatCount(long aimagedecoder, int repeatCount);
1212 }
1213