| 
				
			 | 
			
			
				@@ -1,12 +1,15 @@ 
			 | 
		
	
		
			
			| 
				1
			 | 
			
				1
			 | 
			
			
				 package fr.greweb.reactnativeviewshot; 
			 | 
		
	
		
			
			| 
				2
			 | 
			
				2
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				3
			 | 
			
				
			 | 
			
			
				-import javax.annotation.Nullable; 
			 | 
		
	
		
			
			| 
				4
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				5
			 | 
			
				3
			 | 
			
			
				 import android.app.Activity; 
			 | 
		
	
		
			
			| 
				6
			 | 
			
				
			 | 
			
			
				-import android.content.Intent; 
			 | 
		
	
		
			
			| 
				7
			 | 
			
				4
			 | 
			
			
				 import android.graphics.Bitmap; 
			 | 
		
	
		
			
			| 
				8
			 | 
			
				5
			 | 
			
			
				 import android.graphics.Canvas; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				6
			 | 
			
			
				+import android.graphics.Color; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				7
			 | 
			
			
				+import android.graphics.Point; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				8
			 | 
			
			
				+import android.graphics.Rect; 
			 | 
		
	
		
			
			| 
				9
			 | 
			
				9
			 | 
			
			
				 import android.net.Uri; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				10
			 | 
			
			
				+import android.support.annotation.IntDef; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				11
			 | 
			
			
				+import android.support.annotation.NonNull; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				12
			 | 
			
			
				+import android.support.annotation.StringDef; 
			 | 
		
	
		
			
			| 
				10
			 | 
			
				13
			 | 
			
			
				 import android.util.Base64; 
			 | 
		
	
		
			
			| 
				11
			 | 
			
				14
			 | 
			
			
				 import android.view.TextureView; 
			 | 
		
	
		
			
			| 
				12
			 | 
			
				15
			 | 
			
			
				 import android.view.View; 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -23,42 +26,113 @@ import java.io.File; 
			 | 
		
	
		
			
			| 
				23
			 | 
			
				26
			 | 
			
			
				 import java.io.FileOutputStream; 
			 | 
		
	
		
			
			| 
				24
			 | 
			
				27
			 | 
			
			
				 import java.io.IOException; 
			 | 
		
	
		
			
			| 
				25
			 | 
			
				28
			 | 
			
			
				 import java.io.OutputStream; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				29
			 | 
			
			
				+import java.nio.ByteBuffer; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				30
			 | 
			
			
				+import java.nio.charset.Charset; 
			 | 
		
	
		
			
			| 
				26
			 | 
			
				31
			 | 
			
			
				 import java.util.ArrayList; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				32
			 | 
			
			
				+import java.util.Arrays; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				33
			 | 
			
			
				+import java.util.Collections; 
			 | 
		
	
		
			
			| 
				27
			 | 
			
				34
			 | 
			
			
				 import java.util.List; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				35
			 | 
			
			
				+import java.util.Locale; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				36
			 | 
			
			
				+import java.util.Set; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				37
			 | 
			
			
				+import java.util.WeakHashMap; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				38
			 | 
			
			
				+import java.util.zip.Deflater; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				39
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				40
			 | 
			
			
				+import javax.annotation.Nullable; 
			 | 
		
	
		
			
			| 
				28
			 | 
			
				41
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				29
			 | 
			
				42
			 | 
			
			
				 /** 
			 | 
		
	
		
			
			| 
				30
			 | 
			
				43
			 | 
			
			
				  * Snapshot utility class allow to screenshot a view. 
			 | 
		
	
		
			
			| 
				31
			 | 
			
				44
			 | 
			
			
				  */ 
			 | 
		
	
		
			
			| 
				32
			 | 
			
				45
			 | 
			
			
				 public class ViewShot implements UIBlock { 
			 | 
		
	
		
			
			| 
				33
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				
			 | 
			
				46
			 | 
			
			
				+    //region Constants 
			 | 
		
	
		
			
			| 
				34
			 | 
			
				47
			 | 
			
			
				     static final String ERROR_UNABLE_TO_SNAPSHOT = "E_UNABLE_TO_SNAPSHOT"; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				48
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				49
			 | 
			
			
				+     * pre-allocated output stream size for screenshot. In real life example it will eb around 7Mb. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				50
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				51
			 | 
			
			
				+    private static final int PREALLOCATE_SIZE = 64 * 1024; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				52
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				53
			 | 
			
			
				+     * ARGB size in bytes. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				54
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				55
			 | 
			
			
				+    private static final int ARGB_SIZE = 4; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				56
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				57
			 | 
			
			
				+    @SuppressWarnings("WeakerAccess") 
			 | 
		
	
		
			
			| 
				
			 | 
			
				58
			 | 
			
			
				+    @IntDef({Formats.JPEG, Formats.PNG, Formats.WEBP, Formats.RAW}) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				59
			 | 
			
			
				+    public @interface Formats { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				60
			 | 
			
			
				+        int JPEG = 0; // Bitmap.CompressFormat.JPEG.ordinal(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				61
			 | 
			
			
				+        int PNG = 1;  // Bitmap.CompressFormat.PNG.ordinal(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				62
			 | 
			
			
				+        int WEBP = 2; // Bitmap.CompressFormat.WEBP.ordinal(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				63
			 | 
			
			
				+        int RAW = -1; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				64
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				65
			 | 
			
			
				+        Bitmap.CompressFormat[] mapping = { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				66
			 | 
			
			
				+                Bitmap.CompressFormat.JPEG, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				67
			 | 
			
			
				+                Bitmap.CompressFormat.PNG, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				68
			 | 
			
			
				+                Bitmap.CompressFormat.WEBP 
			 | 
		
	
		
			
			| 
				
			 | 
			
				69
			 | 
			
			
				+        }; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				70
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				71
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				72
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				73
			 | 
			
			
				+     * Supported Output results. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				74
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				75
			 | 
			
			
				+    @StringDef({Results.BASE_64, Results.DATA_URI, Results.TEMP_FILE, Results.ZIP_BASE_64}) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				76
			 | 
			
			
				+    public @interface Results { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				77
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				78
			 | 
			
			
				+         * Save screenshot as temp file on device. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				79
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				80
			 | 
			
			
				+        String TEMP_FILE = "tmpfile"; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				81
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				82
			 | 
			
			
				+         * Base 64 encoded image. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				83
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				84
			 | 
			
			
				+        String BASE_64 = "base64"; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				+         * Zipped RAW image in base 64 encoding. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				87
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				+        String ZIP_BASE_64 = "zip-base64"; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				+         * Base64 data uri. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				+        String DATA_URI = "data-uri"; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				93
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				94
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				35
			 | 
			
				95
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				96
			 | 
			
			
				+    //region Static members 
			 | 
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				98
			 | 
			
			
				+     * Image output buffer used as a source for base64 encoding 
			 | 
		
	
		
			
			| 
				
			 | 
			
				99
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				100
			 | 
			
			
				+    private static byte[] outputBuffer = new byte[PREALLOCATE_SIZE]; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				101
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				
			 | 
			
				102
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				103
			 | 
			
			
				+    //region Class members 
			 | 
		
	
		
			
			| 
				36
			 | 
			
				104
			 | 
			
			
				     private final int tag; 
			 | 
		
	
		
			
			| 
				37
			 | 
			
				105
			 | 
			
			
				     private final String extension; 
			 | 
		
	
		
			
			| 
				38
			 | 
			
				
			 | 
			
			
				-    private final Bitmap.CompressFormat format; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				106
			 | 
			
			
				+    @Formats 
			 | 
		
	
		
			
			| 
				
			 | 
			
				107
			 | 
			
			
				+    private final int format; 
			 | 
		
	
		
			
			| 
				39
			 | 
			
				108
			 | 
			
			
				     private final double quality; 
			 | 
		
	
		
			
			| 
				40
			 | 
			
				109
			 | 
			
			
				     private final Integer width; 
			 | 
		
	
		
			
			| 
				41
			 | 
			
				110
			 | 
			
			
				     private final Integer height; 
			 | 
		
	
		
			
			| 
				42
			 | 
			
				111
			 | 
			
			
				     private final File output; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				112
			 | 
			
			
				+    @Results 
			 | 
		
	
		
			
			| 
				43
			 | 
			
				113
			 | 
			
			
				     private final String result; 
			 | 
		
	
		
			
			| 
				44
			 | 
			
				114
			 | 
			
			
				     private final Promise promise; 
			 | 
		
	
		
			
			| 
				45
			 | 
			
				115
			 | 
			
			
				     private final Boolean snapshotContentContainer; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				116
			 | 
			
			
				+    @SuppressWarnings({"unused", "FieldCanBeLocal"}) 
			 | 
		
	
		
			
			| 
				46
			 | 
			
				117
			 | 
			
			
				     private final ReactApplicationContext reactContext; 
			 | 
		
	
		
			
			| 
				47
			 | 
			
				118
			 | 
			
			
				     private final Activity currentActivity; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				119
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				48
			 | 
			
				120
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				121
			 | 
			
			
				+    //region Constructors 
			 | 
		
	
		
			
			| 
				
			 | 
			
				122
			 | 
			
			
				+    @SuppressWarnings("WeakerAccess") 
			 | 
		
	
		
			
			| 
				49
			 | 
			
				123
			 | 
			
			
				     public ViewShot( 
			 | 
		
	
		
			
			| 
				50
			 | 
			
				
			 | 
			
			
				-            int tag, 
			 | 
		
	
		
			
			| 
				51
			 | 
			
				
			 | 
			
			
				-            String extension, 
			 | 
		
	
		
			
			| 
				52
			 | 
			
				
			 | 
			
			
				-            Bitmap.CompressFormat format, 
			 | 
		
	
		
			
			| 
				53
			 | 
			
				
			 | 
			
			
				-            double quality, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				124
			 | 
			
			
				+            final int tag, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				125
			 | 
			
			
				+            final String extension, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				126
			 | 
			
			
				+            @Formats final int format, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				127
			 | 
			
			
				+            final double quality, 
			 | 
		
	
		
			
			| 
				54
			 | 
			
				128
			 | 
			
			
				             @Nullable Integer width, 
			 | 
		
	
		
			
			| 
				55
			 | 
			
				129
			 | 
			
			
				             @Nullable Integer height, 
			 | 
		
	
		
			
			| 
				56
			 | 
			
				
			 | 
			
			
				-            File output, 
			 | 
		
	
		
			
			| 
				57
			 | 
			
				
			 | 
			
			
				-            String result, 
			 | 
		
	
		
			
			| 
				58
			 | 
			
				
			 | 
			
			
				-            Boolean snapshotContentContainer, 
			 | 
		
	
		
			
			| 
				59
			 | 
			
				
			 | 
			
			
				-            ReactApplicationContext reactContext, 
			 | 
		
	
		
			
			| 
				60
			 | 
			
				
			 | 
			
			
				-            Activity currentActivity, 
			 | 
		
	
		
			
			| 
				61
			 | 
			
				
			 | 
			
			
				-            Promise promise) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				130
			 | 
			
			
				+            final File output, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				131
			 | 
			
			
				+            @Results final String result, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				132
			 | 
			
			
				+            final Boolean snapshotContentContainer, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				133
			 | 
			
			
				+            final ReactApplicationContext reactContext, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				134
			 | 
			
			
				+            final Activity currentActivity, 
			 | 
		
	
		
			
			| 
				
			 | 
			
				135
			 | 
			
			
				+            final Promise promise) { 
			 | 
		
	
		
			
			| 
				62
			 | 
			
				136
			 | 
			
			
				         this.tag = tag; 
			 | 
		
	
		
			
			| 
				63
			 | 
			
				137
			 | 
			
			
				         this.extension = extension; 
			 | 
		
	
		
			
			| 
				64
			 | 
			
				138
			 | 
			
			
				         this.format = format; 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -72,7 +146,9 @@ public class ViewShot implements UIBlock { 
			 | 
		
	
		
			
			| 
				72
			 | 
			
				146
			 | 
			
			
				         this.currentActivity = currentActivity; 
			 | 
		
	
		
			
			| 
				73
			 | 
			
				147
			 | 
			
			
				         this.promise = promise; 
			 | 
		
	
		
			
			| 
				74
			 | 
			
				148
			 | 
			
			
				     } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				149
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				75
			 | 
			
				150
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				151
			 | 
			
			
				+    //region Overrides 
			 | 
		
	
		
			
			| 
				76
			 | 
			
				152
			 | 
			
			
				     @Override 
			 | 
		
	
		
			
			| 
				77
			 | 
			
				153
			 | 
			
			
				     public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { 
			 | 
		
	
		
			
			| 
				78
			 | 
			
				154
			 | 
			
			
				         final View view; 
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -84,74 +160,146 @@ public class ViewShot implements UIBlock { 
			 | 
		
	
		
			
			| 
				84
			 | 
			
				160
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				85
			 | 
			
				161
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				86
			 | 
			
				162
			 | 
			
			
				         if (view == null) { 
			 | 
		
	
		
			
			| 
				87
			 | 
			
				
			 | 
			
			
				-            promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: "+tag); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				163
			 | 
			
			
				+            promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: " + tag); 
			 | 
		
	
		
			
			| 
				88
			 | 
			
				164
			 | 
			
			
				             return; 
			 | 
		
	
		
			
			| 
				89
			 | 
			
				165
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				166
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				90
			 | 
			
				167
			 | 
			
			
				         try { 
			 | 
		
	
		
			
			| 
				91
			 | 
			
				
			 | 
			
			
				-            if ("tmpfile".equals(result)) { 
			 | 
		
	
		
			
			| 
				92
			 | 
			
				
			 | 
			
			
				-                captureView(view, new FileOutputStream(output)); 
			 | 
		
	
		
			
			| 
				93
			 | 
			
				
			 | 
			
			
				-                final String uri = Uri.fromFile(output).toString(); 
			 | 
		
	
		
			
			| 
				94
			 | 
			
				
			 | 
			
			
				-                promise.resolve(uri); 
			 | 
		
	
		
			
			| 
				95
			 | 
			
				
			 | 
			
			
				-            } else if ("base64".equals(result)) { 
			 | 
		
	
		
			
			| 
				96
			 | 
			
				
			 | 
			
			
				-                final ByteArrayOutputStream os = new ByteArrayOutputStream(); 
			 | 
		
	
		
			
			| 
				97
			 | 
			
				
			 | 
			
			
				-                captureView(view, os); 
			 | 
		
	
		
			
			| 
				98
			 | 
			
				
			 | 
			
			
				-                final byte[] bytes = os.toByteArray(); 
			 | 
		
	
		
			
			| 
				99
			 | 
			
				
			 | 
			
			
				-                final String data = Base64.encodeToString(bytes, Base64.NO_WRAP); 
			 | 
		
	
		
			
			| 
				100
			 | 
			
				
			 | 
			
			
				-                promise.resolve(data); 
			 | 
		
	
		
			
			| 
				101
			 | 
			
				
			 | 
			
			
				-            } else if ("data-uri".equals(result)) { 
			 | 
		
	
		
			
			| 
				102
			 | 
			
				
			 | 
			
			
				-                final ByteArrayOutputStream os = new ByteArrayOutputStream(); 
			 | 
		
	
		
			
			| 
				103
			 | 
			
				
			 | 
			
			
				-                captureView(view, os); 
			 | 
		
	
		
			
			| 
				104
			 | 
			
				
			 | 
			
			
				-                final byte[] bytes = os.toByteArray(); 
			 | 
		
	
		
			
			| 
				105
			 | 
			
				
			 | 
			
			
				-                String data = Base64.encodeToString(bytes, Base64.NO_WRAP); 
			 | 
		
	
		
			
			| 
				106
			 | 
			
				
			 | 
			
			
				-                // correct the extension if JPG 
			 | 
		
	
		
			
			| 
				107
			 | 
			
				
			 | 
			
			
				-                String imageFormat = extension; 
			 | 
		
	
		
			
			| 
				108
			 | 
			
				
			 | 
			
			
				-                if ("jpg".equals(extension)) { 
			 | 
		
	
		
			
			| 
				109
			 | 
			
				
			 | 
			
			
				-                    imageFormat = "jpeg"; 
			 | 
		
	
		
			
			| 
				110
			 | 
			
				
			 | 
			
			
				-                } 
			 | 
		
	
		
			
			| 
				111
			 | 
			
				
			 | 
			
			
				-                data = "data:image/"+imageFormat+";base64," + data; 
			 | 
		
	
		
			
			| 
				112
			 | 
			
				
			 | 
			
			
				-                promise.resolve(data); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				168
			 | 
			
			
				+            final ReusableByteArrayOutputStream stream = new ReusableByteArrayOutputStream(outputBuffer); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				169
			 | 
			
			
				+            stream.setSize(proposeSize(view)); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				170
			 | 
			
			
				+            outputBuffer = stream.innerBuffer(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				171
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				172
			 | 
			
			
				+            if (Results.TEMP_FILE.equals(result) && Formats.RAW == this.format) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				+                saveToRawFileOnDevice(view); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				174
			 | 
			
			
				+            } else if (Results.TEMP_FILE.equals(result) && Formats.RAW != this.format) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				175
			 | 
			
			
				+                saveToTempFileOnDevice(view); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				176
			 | 
			
			
				+            } else if (Results.BASE_64.equals(result) || Results.ZIP_BASE_64.equals(result)) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				177
			 | 
			
			
				+                saveToBase64String(view); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				178
			 | 
			
			
				+            } else if (Results.DATA_URI.equals(result)) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				179
			 | 
			
			
				+                saveToDataUriString(view); 
			 | 
		
	
		
			
			| 
				113
			 | 
			
				180
			 | 
			
			
				             } 
			 | 
		
	
		
			
			| 
				114
			 | 
			
				
			 | 
			
			
				-        } catch (Exception e) { 
			 | 
		
	
		
			
			| 
				115
			 | 
			
				
			 | 
			
			
				-            e.printStackTrace(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				181
			 | 
			
			
				+        } catch (final Throwable ignored) { 
			 | 
		
	
		
			
			| 
				116
			 | 
			
				182
			 | 
			
			
				             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to capture view snapshot"); 
			 | 
		
	
		
			
			| 
				117
			 | 
			
				183
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				118
			 | 
			
				184
			 | 
			
			
				     } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				185
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				
			 | 
			
				186
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				187
			 | 
			
			
				+    //region Implementation 
			 | 
		
	
		
			
			| 
				
			 | 
			
				188
			 | 
			
			
				+    private void saveToTempFileOnDevice(@NonNull final View view) throws IOException { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				189
			 | 
			
			
				+        final FileOutputStream fos = new FileOutputStream(output); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				190
			 | 
			
			
				+        captureView(view, fos); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				191
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				192
			 | 
			
			
				+        promise.resolve(Uri.fromFile(output).toString()); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				193
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				194
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				195
			 | 
			
			
				+    private void saveToRawFileOnDevice(@NonNull final View view) throws IOException { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				196
			 | 
			
			
				+        final String uri = Uri.fromFile(output).toString(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				197
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				198
			 | 
			
			
				+        final FileOutputStream fos = new FileOutputStream(output); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				199
			 | 
			
			
				+        final ReusableByteArrayOutputStream os = new ReusableByteArrayOutputStream(outputBuffer); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				200
			 | 
			
			
				+        final Point size = captureView(view, os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				201
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				202
			 | 
			
			
				+        // in case of buffer grow that will be a new array with bigger size 
			 | 
		
	
		
			
			| 
				
			 | 
			
				203
			 | 
			
			
				+        outputBuffer = os.innerBuffer(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				204
			 | 
			
			
				+        final int length = os.size(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				205
			 | 
			
			
				+        final String resolution = String.format(Locale.US, "%d:%d|", size.x, size.y); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				206
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				207
			 | 
			
			
				+        fos.write(resolution.getBytes(Charset.forName("US-ASCII"))); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				208
			 | 
			
			
				+        fos.write(outputBuffer, 0, length); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				209
			 | 
			
			
				+        fos.close(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				210
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				211
			 | 
			
			
				+        promise.resolve(uri); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				212
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				119
			 | 
			
				213
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				120
			 | 
			
				
			 | 
			
			
				-    private List<View> getAllChildren(View v) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				214
			 | 
			
			
				+    private void saveToDataUriString(@NonNull final View view) throws IOException { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				215
			 | 
			
			
				+        final ReusableByteArrayOutputStream os = new ReusableByteArrayOutputStream(outputBuffer); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				216
			 | 
			
			
				+        captureView(view, os); 
			 | 
		
	
		
			
			| 
				121
			 | 
			
				217
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				
			 | 
			
				218
			 | 
			
			
				+        outputBuffer = os.innerBuffer(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				219
			 | 
			
			
				+        final int length = os.size(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				220
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				221
			 | 
			
			
				+        final String data = Base64.encodeToString(outputBuffer, 0, length, Base64.NO_WRAP); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				222
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				223
			 | 
			
			
				+        // correct the extension if JPG 
			 | 
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				+        final String imageFormat = "jpg".equals(extension) ? "jpeg" : extension; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				225
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				+        promise.resolve("data:image/" + imageFormat + ";base64," + data); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				228
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				229
			 | 
			
			
				+    private void saveToBase64String(@NonNull final View view) throws IOException { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				230
			 | 
			
			
				+        final boolean isRaw = Formats.RAW == this.format; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				231
			 | 
			
			
				+        final boolean isZippedBase64 = Results.ZIP_BASE_64.equals(this.result); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				232
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				233
			 | 
			
			
				+        final ReusableByteArrayOutputStream os = new ReusableByteArrayOutputStream(outputBuffer); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				234
			 | 
			
			
				+        final Point size = captureView(view, os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				235
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				236
			 | 
			
			
				+        // in case of buffer grow that will be a new array with bigger size 
			 | 
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				+        outputBuffer = os.innerBuffer(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				+        final int length = os.size(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				239
			 | 
			
			
				+        final String resolution = String.format(Locale.US, "%d:%d|", size.x, size.y); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				240
			 | 
			
			
				+        final String header = (isRaw ? resolution : ""); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				+        final String data; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				243
			 | 
			
			
				+        if (isZippedBase64) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				244
			 | 
			
			
				+            final Deflater deflater = new Deflater(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				245
			 | 
			
			
				+            deflater.setInput(outputBuffer, 0, length); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				246
			 | 
			
			
				+            deflater.finish(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				247
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				+            final ReusableByteArrayOutputStream zipped = new ReusableByteArrayOutputStream(new byte[32]); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				249
			 | 
			
			
				+            byte[] buffer = new byte[1024]; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				250
			 | 
			
			
				+            while (!deflater.finished()) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				251
			 | 
			
			
				+                int count = deflater.deflate(buffer); // returns the generated code... index 
			 | 
		
	
		
			
			| 
				
			 | 
			
				252
			 | 
			
			
				+                zipped.write(buffer, 0, count); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				253
			 | 
			
			
				+            } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				254
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				255
			 | 
			
			
				+            data = header + Base64.encodeToString(zipped.innerBuffer(), 0, zipped.size(), Base64.NO_WRAP); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				256
			 | 
			
			
				+        } else { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				257
			 | 
			
			
				+            data = header + Base64.encodeToString(outputBuffer, 0, length, Base64.NO_WRAP); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				258
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				259
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				260
			 | 
			
			
				+        promise.resolve(data); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				261
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				262
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				263
			 | 
			
			
				+    @NonNull 
			 | 
		
	
		
			
			| 
				
			 | 
			
				264
			 | 
			
			
				+    private List<View> getAllChildren(@NonNull final View v) { 
			 | 
		
	
		
			
			| 
				122
			 | 
			
				265
			 | 
			
			
				         if (!(v instanceof ViewGroup)) { 
			 | 
		
	
		
			
			| 
				123
			 | 
			
				
			 | 
			
			
				-            ArrayList<View> viewArrayList = new ArrayList<View>(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				266
			 | 
			
			
				+            final ArrayList<View> viewArrayList = new ArrayList<>(); 
			 | 
		
	
		
			
			| 
				124
			 | 
			
				267
			 | 
			
			
				             viewArrayList.add(v); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				268
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				125
			 | 
			
				269
			 | 
			
			
				             return viewArrayList; 
			 | 
		
	
		
			
			| 
				126
			 | 
			
				270
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				127
			 | 
			
				271
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				128
			 | 
			
				
			 | 
			
			
				-        ArrayList<View> result = new ArrayList<View>(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				272
			 | 
			
			
				+        final ArrayList<View> result = new ArrayList<>(); 
			 | 
		
	
		
			
			| 
				129
			 | 
			
				273
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				130
			 | 
			
				274
			 | 
			
			
				         ViewGroup viewGroup = (ViewGroup) v; 
			 | 
		
	
		
			
			| 
				131
			 | 
			
				275
			 | 
			
			
				         for (int i = 0; i < viewGroup.getChildCount(); i++) { 
			 | 
		
	
		
			
			| 
				132
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				133
			 | 
			
				276
			 | 
			
			
				             View child = viewGroup.getChildAt(i); 
			 | 
		
	
		
			
			| 
				134
			 | 
			
				277
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				135
			 | 
			
				278
			 | 
			
			
				             //Do not add any parents, just add child elements 
			 | 
		
	
		
			
			| 
				136
			 | 
			
				279
			 | 
			
			
				             result.addAll(getAllChildren(child)); 
			 | 
		
	
		
			
			| 
				137
			 | 
			
				280
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				281
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				138
			 | 
			
				282
			 | 
			
			
				         return result; 
			 | 
		
	
		
			
			| 
				139
			 | 
			
				283
			 | 
			
			
				     } 
			 | 
		
	
		
			
			| 
				140
			 | 
			
				284
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				141
			 | 
			
				285
			 | 
			
			
				     /** 
			 | 
		
	
		
			
			| 
				142
			 | 
			
				
			 | 
			
			
				-     * Screenshot a view and return the captured bitmap. 
			 | 
		
	
		
			
			| 
				143
			 | 
			
				
			 | 
			
			
				-     * @param view the view to capture 
			 | 
		
	
		
			
			| 
				144
			 | 
			
				
			 | 
			
			
				-     * @return the screenshot or null if it failed. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				286
			 | 
			
			
				+     * Wrap {@link #captureViewImpl(View, OutputStream)} call and on end close output stream. 
			 | 
		
	
		
			
			| 
				145
			 | 
			
				287
			 | 
			
			
				      */ 
			 | 
		
	
		
			
			| 
				146
			 | 
			
				
			 | 
			
			
				-    private void captureView(View view, OutputStream os) throws IOException { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				288
			 | 
			
			
				+    private Point captureView(@NonNull final View view, @NonNull final OutputStream os) throws IOException { 
			 | 
		
	
		
			
			| 
				147
			 | 
			
				289
			 | 
			
			
				         try { 
			 | 
		
	
		
			
			| 
				148
			 | 
			
				
			 | 
			
			
				-            captureViewImpl(view, os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				290
			 | 
			
			
				+            return captureViewImpl(view, os); 
			 | 
		
	
		
			
			| 
				149
			 | 
			
				291
			 | 
			
			
				         } finally { 
			 | 
		
	
		
			
			| 
				150
			 | 
			
				292
			 | 
			
			
				             os.close(); 
			 | 
		
	
		
			
			| 
				151
			 | 
			
				293
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				152
			 | 
			
				294
			 | 
			
			
				     } 
			 | 
		
	
		
			
			| 
				153
			 | 
			
				295
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				154
			 | 
			
				
			 | 
			
			
				-    private void captureViewImpl(View view, OutputStream os) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				296
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				297
			 | 
			
			
				+     * Screenshot a view and return the captured bitmap. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				298
			 | 
			
			
				+     * 
			 | 
		
	
		
			
			| 
				
			 | 
			
				299
			 | 
			
			
				+     * @param view the view to capture 
			 | 
		
	
		
			
			| 
				
			 | 
			
				300
			 | 
			
			
				+     * @return screenshot resolution, Width * Height 
			 | 
		
	
		
			
			| 
				
			 | 
			
				301
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				302
			 | 
			
			
				+    private Point captureViewImpl(@NonNull final View view, @NonNull final OutputStream os) { 
			 | 
		
	
		
			
			| 
				155
			 | 
			
				303
			 | 
			
			
				         int w = view.getWidth(); 
			 | 
		
	
		
			
			| 
				156
			 | 
			
				304
			 | 
			
			
				         int h = view.getHeight(); 
			 | 
		
	
		
			
			| 
				157
			 | 
			
				305
			 | 
			
			
				  
			 | 
		
	
	
		
			
			| 
				
			 | 
			
			
				@@ -161,47 +309,201 @@ public class ViewShot implements UIBlock { 
			 | 
		
	
		
			
			| 
				161
			 | 
			
				309
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				162
			 | 
			
				310
			 | 
			
			
				         //evaluate real height 
			 | 
		
	
		
			
			| 
				163
			 | 
			
				311
			 | 
			
			
				         if (snapshotContentContainer) { 
			 | 
		
	
		
			
			| 
				164
			 | 
			
				
			 | 
			
			
				-            h=0; 
			 | 
		
	
		
			
			| 
				165
			 | 
			
				
			 | 
			
			
				-            ScrollView scrollView = (ScrollView)view; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				312
			 | 
			
			
				+            h = 0; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				313
			 | 
			
			
				+            ScrollView scrollView = (ScrollView) view; 
			 | 
		
	
		
			
			| 
				166
			 | 
			
				314
			 | 
			
			
				             for (int i = 0; i < scrollView.getChildCount(); i++) { 
			 | 
		
	
		
			
			| 
				167
			 | 
			
				315
			 | 
			
			
				                 h += scrollView.getChildAt(i).getHeight(); 
			 | 
		
	
		
			
			| 
				168
			 | 
			
				316
			 | 
			
			
				             } 
			 | 
		
	
		
			
			| 
				169
			 | 
			
				317
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				170
			 | 
			
				
			 | 
			
			
				-        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
			 | 
		
	
		
			
			| 
				171
			 | 
			
				
			 | 
			
			
				-        Bitmap childBitmapBuffer; 
			 | 
		
	
		
			
			| 
				172
			 | 
			
				
			 | 
			
			
				-        Canvas c = new Canvas(bitmap); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				318
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				319
			 | 
			
			
				+        final Point resolution = new Point(w, h); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				320
			 | 
			
			
				+        Bitmap bitmap = getBitmapForScreenshot(w, h); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				321
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				322
			 | 
			
			
				+        final Canvas c = new Canvas(bitmap); 
			 | 
		
	
		
			
			| 
				173
			 | 
			
				323
			 | 
			
			
				         view.draw(c); 
			 | 
		
	
		
			
			| 
				174
			 | 
			
				324
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				175
			 | 
			
				325
			 | 
			
			
				         //after view is drawn, go through children 
			 | 
		
	
		
			
			| 
				176
			 | 
			
				
			 | 
			
			
				-        List<View> childrenList = getAllChildren(view); 
			 | 
		
	
		
			
			| 
				177
			 | 
			
				
			 | 
			
			
				- 
			 | 
		
	
		
			
			| 
				178
			 | 
			
				
			 | 
			
			
				-        for (View child : childrenList) { 
			 | 
		
	
		
			
			| 
				179
			 | 
			
				
			 | 
			
			
				-            if(child instanceof TextureView) { 
			 | 
		
	
		
			
			| 
				180
			 | 
			
				
			 | 
			
			
				-                ((TextureView) child).setOpaque(false); 
			 | 
		
	
		
			
			| 
				181
			 | 
			
				
			 | 
			
			
				-                childBitmapBuffer = ((TextureView) child).getBitmap(child.getWidth(), child.getHeight()); 
			 | 
		
	
		
			
			| 
				182
			 | 
			
				
			 | 
			
			
				-                if (childBitmapBuffer != null) { 
			 | 
		
	
		
			
			| 
				183
			 | 
			
				
			 | 
			
			
				-                    int left = child.getLeft(); 
			 | 
		
	
		
			
			| 
				184
			 | 
			
				
			 | 
			
			
				-                    int top = child.getTop(); 
			 | 
		
	
		
			
			| 
				185
			 | 
			
				
			 | 
			
			
				-                    View parentElem = (View)child.getParent(); 
			 | 
		
	
		
			
			| 
				186
			 | 
			
				
			 | 
			
			
				-                    while (parentElem != null) { 
			 | 
		
	
		
			
			| 
				187
			 | 
			
				
			 | 
			
			
				-                        if (parentElem == view) { 
			 | 
		
	
		
			
			| 
				188
			 | 
			
				
			 | 
			
			
				-                            break; 
			 | 
		
	
		
			
			| 
				189
			 | 
			
				
			 | 
			
			
				-                        } 
			 | 
		
	
		
			
			| 
				190
			 | 
			
				
			 | 
			
			
				-                        left += parentElem.getLeft(); 
			 | 
		
	
		
			
			| 
				191
			 | 
			
				
			 | 
			
			
				-                        top += parentElem.getTop(); 
			 | 
		
	
		
			
			| 
				192
			 | 
			
				
			 | 
			
			
				-                        parentElem = (View)parentElem.getParent(); 
			 | 
		
	
		
			
			| 
				193
			 | 
			
				
			 | 
			
			
				-                    } 
			 | 
		
	
		
			
			| 
				194
			 | 
			
				
			 | 
			
			
				-                    c.drawBitmap(childBitmapBuffer, left + child.getPaddingLeft(), top + child.getPaddingTop(), null); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				326
			 | 
			
			
				+        final List<View> childrenList = getAllChildren(view); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				327
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				328
			 | 
			
			
				+        for (final View child : childrenList) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				329
			 | 
			
			
				+            // skip any child that we don't know how to process 
			 | 
		
	
		
			
			| 
				
			 | 
			
				330
			 | 
			
			
				+            if (!(child instanceof TextureView)) continue; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				331
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				332
			 | 
			
			
				+            final TextureView tvChild = (TextureView) child; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				333
			 | 
			
			
				+            tvChild.setOpaque(false); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				334
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				335
			 | 
			
			
				+            final Point offsets = getParentOffsets(view, child); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				336
			 | 
			
			
				+            final int left = child.getLeft() + child.getPaddingLeft() + offsets.x; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				337
			 | 
			
			
				+            final int top = child.getTop() + child.getPaddingTop() + offsets.y; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				338
			 | 
			
			
				+            final int childWidth = child.getWidth(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				339
			 | 
			
			
				+            final int childHeight = child.getHeight(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				340
			 | 
			
			
				+            final Rect source = new Rect(0, 0, childWidth, childHeight); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				341
			 | 
			
			
				+            final Rect destination = new Rect(left, top, left + childWidth, top + childHeight); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				342
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				343
			 | 
			
			
				+            // get re-usable bitmap 
			 | 
		
	
		
			
			| 
				
			 | 
			
				344
			 | 
			
			
				+            final Bitmap childBitmapBuffer = tvChild.getBitmap(getBitmapForScreenshot(child.getWidth(), child.getHeight())); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				345
			 | 
			
			
				+            // due to re-use of bitmaps for screenshot, we can get bitmap that is bigger in size than requested 
			 | 
		
	
		
			
			| 
				
			 | 
			
				346
			 | 
			
			
				+            c.drawBitmap(childBitmapBuffer, source, destination, null); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				347
			 | 
			
			
				+            recycleBitmap(childBitmapBuffer); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				348
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				349
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				350
			 | 
			
			
				+        if (width != null && height != null && (width != w || height != h)) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				351
			 | 
			
			
				+            final Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				352
			 | 
			
			
				+            recycleBitmap(bitmap); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				353
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				354
			 | 
			
			
				+            bitmap = scaledBitmap; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				355
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				356
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				357
			 | 
			
			
				+        // special case, just save RAW ARGB array without any compression 
			 | 
		
	
		
			
			| 
				
			 | 
			
				358
			 | 
			
			
				+        if (Formats.RAW == this.format && os instanceof ReusableByteArrayOutputStream) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				359
			 | 
			
			
				+            final int total = w * h * ARGB_SIZE; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				360
			 | 
			
			
				+            final ReusableByteArrayOutputStream rbaos = cast(os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				361
			 | 
			
			
				+            bitmap.copyPixelsToBuffer(rbaos.asBuffer(total)); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				362
			 | 
			
			
				+            rbaos.setSize(total); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				363
			 | 
			
			
				+        } else { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				364
			 | 
			
			
				+            final Bitmap.CompressFormat cf = Formats.mapping[this.format]; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				365
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				366
			 | 
			
			
				+            bitmap.compress(cf, (int) (100.0 * quality), os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				367
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				368
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				369
			 | 
			
			
				+        recycleBitmap(bitmap); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				370
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				371
			 | 
			
			
				+        return resolution; // return image width and height 
			 | 
		
	
		
			
			| 
				
			 | 
			
				372
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				373
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				374
			 | 
			
			
				+    @NonNull 
			 | 
		
	
		
			
			| 
				
			 | 
			
				375
			 | 
			
			
				+    private Point getParentOffsets(@NonNull final View view, @NonNull final View child) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				376
			 | 
			
			
				+        int left = 0; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				377
			 | 
			
			
				+        int top = 0; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				378
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				379
			 | 
			
			
				+        View parentElem = (View) child.getParent(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				380
			 | 
			
			
				+        while (parentElem != null) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				381
			 | 
			
			
				+            if (parentElem == view) break; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				382
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				383
			 | 
			
			
				+            left += parentElem.getLeft(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				384
			 | 
			
			
				+            top += parentElem.getTop(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				385
			 | 
			
			
				+            parentElem = (View) parentElem.getParent(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				386
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				387
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				388
			 | 
			
			
				+        return new Point(left, top); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				389
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				390
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				391
			 | 
			
			
				+    @SuppressWarnings("unchecked") 
			 | 
		
	
		
			
			| 
				
			 | 
			
				392
			 | 
			
			
				+    private static <T extends A, A> T cast(final A instance) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				393
			 | 
			
			
				+        return (T) instance; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				394
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				395
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				
			 | 
			
				396
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				397
			 | 
			
			
				+    //region Cache re-usable bitmaps 
			 | 
		
	
		
			
			| 
				
			 | 
			
				398
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				399
			 | 
			
			
				+     * Synchronization guard. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				400
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				401
			 | 
			
			
				+    private static final Object guardBitmaps = new Object(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				402
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				403
			 | 
			
			
				+     * Reusable bitmaps for screenshots. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				404
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				405
			 | 
			
			
				+    private static final Set<Bitmap> weakBitmaps = Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>()); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				406
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				407
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				408
			 | 
			
			
				+     * Propose allocation size of the array output stream. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				409
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				410
			 | 
			
			
				+    private static int proposeSize(@NonNull final View view) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				411
			 | 
			
			
				+        final int w = view.getWidth(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				412
			 | 
			
			
				+        final int h = view.getHeight(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				413
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				414
			 | 
			
			
				+        return Math.min(w * h * ARGB_SIZE, 32); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				415
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				416
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				417
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				418
			 | 
			
			
				+     * Return bitmap to set of available. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				419
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				420
			 | 
			
			
				+    private static void recycleBitmap(@NonNull final Bitmap bitmap) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				421
			 | 
			
			
				+        synchronized (guardBitmaps) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				422
			 | 
			
			
				+            weakBitmaps.add(bitmap); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				423
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				424
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				425
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				426
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				427
			 | 
			
			
				+     * Try to find a bitmap for screenshot in reusabel set and if not found create a new one. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				428
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				429
			 | 
			
			
				+    @NonNull 
			 | 
		
	
		
			
			| 
				
			 | 
			
				430
			 | 
			
			
				+    private static Bitmap getBitmapForScreenshot(final int width, final int height) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				431
			 | 
			
			
				+        synchronized (guardBitmaps) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				432
			 | 
			
			
				+            for (final Bitmap bmp : weakBitmaps) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				433
			 | 
			
			
				+                if (bmp.getWidth() * bmp.getHeight() <= width * height) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				434
			 | 
			
			
				+                    weakBitmaps.remove(bmp); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				435
			 | 
			
			
				+                    bmp.eraseColor(Color.TRANSPARENT); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				436
			 | 
			
			
				+                    return bmp; 
			 | 
		
	
		
			
			| 
				195
			 | 
			
				437
			 | 
			
			
				                 } 
			 | 
		
	
		
			
			| 
				196
			 | 
			
				438
			 | 
			
			
				             } 
			 | 
		
	
		
			
			| 
				197
			 | 
			
				439
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				198
			 | 
			
				440
			 | 
			
			
				  
			 | 
		
	
		
			
			| 
				199
			 | 
			
				
			 | 
			
			
				-        if (width != null && height != null && (width != w || height != h)) { 
			 | 
		
	
		
			
			| 
				200
			 | 
			
				
			 | 
			
			
				-            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				441
			 | 
			
			
				+        return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				442
			 | 
			
			
				+    } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				443
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				
			 | 
			
				444
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				445
			 | 
			
			
				+    //region Nested declarations 
			 | 
		
	
		
			
			| 
				
			 | 
			
				446
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				447
			 | 
			
			
				+    /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				448
			 | 
			
			
				+     * Stream that can re-use pre-allocated buffer. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				449
			 | 
			
			
				+     */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				450
			 | 
			
			
				+    @SuppressWarnings("WeakerAccess") 
			 | 
		
	
		
			
			| 
				
			 | 
			
				451
			 | 
			
			
				+    public static class ReusableByteArrayOutputStream extends ByteArrayOutputStream { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				452
			 | 
			
			
				+        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				453
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				454
			 | 
			
			
				+        public ReusableByteArrayOutputStream(@NonNull final byte[] buffer) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				455
			 | 
			
			
				+            super(0); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				456
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				457
			 | 
			
			
				+            this.buf = buffer; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				458
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				459
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				460
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				461
			 | 
			
			
				+         * Get access to inner buffer without any memory copy operations. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				462
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				463
			 | 
			
			
				+        public byte[] innerBuffer() { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				464
			 | 
			
			
				+            return this.buf; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				465
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				466
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				467
			 | 
			
			
				+        @NonNull 
			 | 
		
	
		
			
			| 
				
			 | 
			
				468
			 | 
			
			
				+        public ByteBuffer asBuffer(final int size) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				469
			 | 
			
			
				+            if (this.buf.length < size) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				470
			 | 
			
			
				+                grow(size); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				471
			 | 
			
			
				+            } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				472
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				473
			 | 
			
			
				+            return ByteBuffer.wrap(this.buf); 
			 | 
		
	
		
			
			| 
				201
			 | 
			
				474
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				202
			 | 
			
				
			 | 
			
			
				-        if (bitmap == null) { 
			 | 
		
	
		
			
			| 
				203
			 | 
			
				
			 | 
			
			
				-            throw new RuntimeException("Impossible to snapshot the view"); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				475
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				476
			 | 
			
			
				+        public void setSize(final int size) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				477
			 | 
			
			
				+            this.count = size; 
			 | 
		
	
		
			
			| 
				204
			 | 
			
				478
			 | 
			
			
				         } 
			 | 
		
	
		
			
			| 
				205
			 | 
			
				
			 | 
			
			
				-        bitmap.compress(format, (int)(100.0 * quality), os); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				479
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				480
			 | 
			
			
				+        /** 
			 | 
		
	
		
			
			| 
				
			 | 
			
				481
			 | 
			
			
				+         * Increases the capacity to ensure that it can hold at least the 
			 | 
		
	
		
			
			| 
				
			 | 
			
				482
			 | 
			
			
				+         * number of elements specified by the minimum capacity argument. 
			 | 
		
	
		
			
			| 
				
			 | 
			
				483
			 | 
			
			
				+         * 
			 | 
		
	
		
			
			| 
				
			 | 
			
				484
			 | 
			
			
				+         * @param minCapacity the desired minimum capacity 
			 | 
		
	
		
			
			| 
				
			 | 
			
				485
			 | 
			
			
				+         */ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				486
			 | 
			
			
				+        protected void grow(int minCapacity) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				487
			 | 
			
			
				+            // overflow-conscious code 
			 | 
		
	
		
			
			| 
				
			 | 
			
				488
			 | 
			
			
				+            int oldCapacity = buf.length; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				489
			 | 
			
			
				+            int newCapacity = oldCapacity << 1; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				490
			 | 
			
			
				+            if (newCapacity - minCapacity < 0) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				491
			 | 
			
			
				+                newCapacity = minCapacity; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				492
			 | 
			
			
				+            if (newCapacity - MAX_ARRAY_SIZE > 0) 
			 | 
		
	
		
			
			| 
				
			 | 
			
				493
			 | 
			
			
				+                newCapacity = hugeCapacity(minCapacity); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				494
			 | 
			
			
				+            buf = Arrays.copyOf(buf, newCapacity); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				495
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				496
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				497
			 | 
			
			
				+        protected static int hugeCapacity(int minCapacity) { 
			 | 
		
	
		
			
			| 
				
			 | 
			
				498
			 | 
			
			
				+            if (minCapacity < 0) // overflow 
			 | 
		
	
		
			
			| 
				
			 | 
			
				499
			 | 
			
			
				+                throw new OutOfMemoryError(); 
			 | 
		
	
		
			
			| 
				
			 | 
			
				500
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				
			 | 
			
				501
			 | 
			
			
				+            return (minCapacity > MAX_ARRAY_SIZE) ? 
			 | 
		
	
		
			
			| 
				
			 | 
			
				502
			 | 
			
			
				+                    Integer.MAX_VALUE : 
			 | 
		
	
		
			
			| 
				
			 | 
			
				503
			 | 
			
			
				+                    MAX_ARRAY_SIZE; 
			 | 
		
	
		
			
			| 
				
			 | 
			
				504
			 | 
			
			
				+        } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				505
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				206
			 | 
			
				506
			 | 
			
			
				     } 
			 | 
		
	
		
			
			| 
				
			 | 
			
				507
			 | 
			
			
				+    //endregion 
			 | 
		
	
		
			
			| 
				
			 | 
			
				508
			 | 
			
			
				+ 
			 | 
		
	
		
			
			| 
				207
			 | 
			
				509
			 | 
			
			
				 } 
			 |