18f8784c2622bc9900e772853bced17d091c4daf5Jason Monk/* 28f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * Copyright 2018 The Android Open Source Project 38f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * 48f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 58f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * you may not use this file except in compliance with the License. 68f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * You may obtain a copy of the License at 78f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * 88f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 98f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * 108f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * Unless required by applicable law or agreed to in writing, software 118f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * distributed under the License is distributed on an "AS IS" BASIS, 128f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * See the License for the specific language governing permissions and 148f8784c2622bc9900e772853bced17d091c4daf5Jason Monk * limitations under the License. 158f8784c2622bc9900e772853bced17d091c4daf5Jason Monk */ 168f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1785ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikaspackage androidx.slice.render; 188f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 198f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport static android.view.View.MeasureSpec.makeMeasureSpec; 208f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 218f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.app.Activity; 228f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.app.ProgressDialog; 238f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.graphics.Bitmap; 248f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.graphics.Canvas; 2507a4a56611cc044fd48b052db05aea332201216eJason Monkimport android.net.Uri; 268f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.os.Handler; 278f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.util.Log; 288f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.util.TypedValue; 298f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.view.LayoutInflater; 308f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.view.View; 318f8784c2622bc9900e772853bced17d091c4daf5Jason Monkimport android.view.ViewGroup; 328f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 33cdfd2c2d98a8ff23b18ef3a960a5bb5c90a67d43Mady Mellorimport androidx.recyclerview.widget.RecyclerView; 3485ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.Slice; 3585ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.SliceProvider; 3607a4a56611cc044fd48b052db05aea332201216eJason Monkimport androidx.slice.SliceUtils; 3785ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.view.test.R; 3885ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.widget.SliceLiveData; 3985ef1446b82c8783a50af92c4cb1389fe0d0e907Aurimas Liutikasimport androidx.slice.widget.SliceView; 408f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 4107a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.io.ByteArrayInputStream; 4207a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.io.ByteArrayOutputStream; 4307a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.io.File; 4407a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.io.FileOutputStream; 4507a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.util.concurrent.CountDownLatch; 4607a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.util.concurrent.ExecutorService; 4707a4a56611cc044fd48b052db05aea332201216eJason Monkimport java.util.concurrent.Executors; 4807a4a56611cc044fd48b052db05aea332201216eJason Monk 498f8784c2622bc9900e772853bced17d091c4daf5Jason Monkpublic class SliceRenderer { 508f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 518f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private static final String TAG = "SliceRenderer"; 526d23526ab0ebfee286a772d3038fb194a88c0c0eJason Monk public static final String SCREENSHOT_DIR = "slice-screenshots"; 5307a4a56611cc044fd48b052db05aea332201216eJason Monk 5407a4a56611cc044fd48b052db05aea332201216eJason Monk private static final int MAX_CONCURRENT = 5; 5507a4a56611cc044fd48b052db05aea332201216eJason Monk 568f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private static File sScreenshotDirectory; 578f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 5807a4a56611cc044fd48b052db05aea332201216eJason Monk private final Object mRenderLock = new Object(); 5907a4a56611cc044fd48b052db05aea332201216eJason Monk 608f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final Activity mContext; 618f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final View mLayout; 628f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final SliceView mSV1; 638f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final SliceView mSV2; 648f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final SliceView mSV3; 658f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final ViewGroup mParent; 668f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final Handler mHandler; 678f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private final SliceCreator mSliceCreator; 688f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private CountDownLatch mDoneLatch; 698f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 708f8784c2622bc9900e772853bced17d091c4daf5Jason Monk public SliceRenderer(Activity context) { 718f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mContext = context; 728f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mParent = new ViewGroup(mContext) { 738f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 748f8784c2622bc9900e772853bced17d091c4daf5Jason Monk protected void onLayout(boolean changed, int l, int t, int r, int b) { 750f591e3e9b5147d04d6379fd2b7ba6cab66f1b4fMady Mellor int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1000, 768f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mContext.getResources().getDisplayMetrics()); 77cdfd2c2d98a8ff23b18ef3a960a5bb5c90a67d43Mady Mellor int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 330, 788f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mContext.getResources().getDisplayMetrics()); 798f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mLayout.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY), 808f8784c2622bc9900e772853bced17d091c4daf5Jason Monk makeMeasureSpec(height, View.MeasureSpec.EXACTLY)); 818f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mLayout.layout(0, 0, width, height); 828f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 838f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 848f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 858f8784c2622bc9900e772853bced17d091c4daf5Jason Monk protected boolean drawChild(Canvas canvas, View child, long drawingTime) { 868f8784c2622bc9900e772853bced17d091c4daf5Jason Monk return false; 878f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 888f8784c2622bc9900e772853bced17d091c4daf5Jason Monk }; 898f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mLayout = LayoutInflater.from(context).inflate(R.layout.render_layout, null); 908f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV1 = mLayout.findViewById(R.id.sv1); 918f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV1.setMode(SliceView.MODE_SHORTCUT); 928f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV2 = mLayout.findViewById(R.id.sv2); 938f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV2.setMode(SliceView.MODE_SMALL); 948f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV3 = mLayout.findViewById(R.id.sv3); 958f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSV3.setMode(SliceView.MODE_LARGE); 968f8784c2622bc9900e772853bced17d091c4daf5Jason Monk disableAnims(mLayout); 978f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mHandler = new Handler(); 988f8784c2622bc9900e772853bced17d091c4daf5Jason Monk ((ViewGroup) mContext.getWindow().getDecorView()).addView(mParent); 998f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mParent.addView(mLayout); 1008f8784c2622bc9900e772853bced17d091c4daf5Jason Monk SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); 1018f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mSliceCreator = new SliceCreator(mContext); 1028f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1038f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1048f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private void disableAnims(View view) { 1058f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (view instanceof RecyclerView) { 1068f8784c2622bc9900e772853bced17d091c4daf5Jason Monk ((RecyclerView) view).setItemAnimator(null); 1078f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1088f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (view instanceof ViewGroup) { 1098f8784c2622bc9900e772853bced17d091c4daf5Jason Monk ViewGroup viewGroup = (ViewGroup) view; 1108f8784c2622bc9900e772853bced17d091c4daf5Jason Monk for (int i = 0; i < viewGroup.getChildCount(); i++) { 1118f8784c2622bc9900e772853bced17d091c4daf5Jason Monk disableAnims(viewGroup.getChildAt(i)); 1128f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1138f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1148f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1158f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1168f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1176d23526ab0ebfee286a772d3038fb194a88c0c0eJason Monk private File getScreenshotDirectory() { 1188f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (sScreenshotDirectory == null) { 11938db00ef5d4b5a9d0d171f1bb15a5df567d448f6Jason Monk File storage = mContext.getFilesDir(); 1208f8784c2622bc9900e772853bced17d091c4daf5Jason Monk sScreenshotDirectory = new File(storage, SCREENSHOT_DIR); 1218f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (!sScreenshotDirectory.exists()) { 1228f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (!sScreenshotDirectory.mkdirs()) { 1238f8784c2622bc9900e772853bced17d091c4daf5Jason Monk throw new RuntimeException( 1248f8784c2622bc9900e772853bced17d091c4daf5Jason Monk "Failed to create a screenshot directory."); 1258f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1268f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1278f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1288f8784c2622bc9900e772853bced17d091c4daf5Jason Monk return sScreenshotDirectory; 1298f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1308f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1318f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 1328f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private void doRender() { 13307a4a56611cc044fd48b052db05aea332201216eJason Monk final File output = getScreenshotDirectory(); 1348f8784c2622bc9900e772853bced17d091c4daf5Jason Monk if (!output.exists()) { 1358f8784c2622bc9900e772853bced17d091c4daf5Jason Monk output.mkdir(); 1368f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 13707a4a56611cc044fd48b052db05aea332201216eJason Monk mDoneLatch = new CountDownLatch(SliceCreator.URI_PATHS.length * 2 + 2); 13807a4a56611cc044fd48b052db05aea332201216eJason Monk 13907a4a56611cc044fd48b052db05aea332201216eJason Monk ExecutorService executor = Executors.newFixedThreadPool(5); 14007a4a56611cc044fd48b052db05aea332201216eJason Monk for (final String slice : SliceCreator.URI_PATHS) { 14107a4a56611cc044fd48b052db05aea332201216eJason Monk final Slice s = mSliceCreator.onBindSlice(SliceCreator.getUri(slice, mContext)); 14207a4a56611cc044fd48b052db05aea332201216eJason Monk 14307a4a56611cc044fd48b052db05aea332201216eJason Monk executor.execute(new Runnable() { 14407a4a56611cc044fd48b052db05aea332201216eJason Monk @Override 14507a4a56611cc044fd48b052db05aea332201216eJason Monk public void run() { 14607a4a56611cc044fd48b052db05aea332201216eJason Monk doRender(slice, s, new File(output, String.format("%s.png", slice)), 14707a4a56611cc044fd48b052db05aea332201216eJason Monk true /* scrollable */); 14807a4a56611cc044fd48b052db05aea332201216eJason Monk } 14907a4a56611cc044fd48b052db05aea332201216eJason Monk }); 15007a4a56611cc044fd48b052db05aea332201216eJason Monk final Slice serialized = serAndUnSer(s); 15107a4a56611cc044fd48b052db05aea332201216eJason Monk executor.execute(new Runnable() { 15207a4a56611cc044fd48b052db05aea332201216eJason Monk @Override 15307a4a56611cc044fd48b052db05aea332201216eJason Monk public void run() { 15407a4a56611cc044fd48b052db05aea332201216eJason Monk doRender(slice + "-ser", serialized, new File(output, String.format( 15507a4a56611cc044fd48b052db05aea332201216eJason Monk "%s-serialized.png", slice)), true /* scrollable */); 15607a4a56611cc044fd48b052db05aea332201216eJason Monk } 15707a4a56611cc044fd48b052db05aea332201216eJason Monk }); 15853380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor if (slice.equals("wifi") || slice.equals("wifi2")) { 15953380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor // Test scrolling 16007a4a56611cc044fd48b052db05aea332201216eJason Monk executor.execute(new Runnable() { 16107a4a56611cc044fd48b052db05aea332201216eJason Monk @Override 16207a4a56611cc044fd48b052db05aea332201216eJason Monk public void run() { 16307a4a56611cc044fd48b052db05aea332201216eJason Monk doRender(slice + "-ns", s, new File(output, String.format( 16407a4a56611cc044fd48b052db05aea332201216eJason Monk "%s-no-scroll.png", slice)), false /* scrollable */); 16507a4a56611cc044fd48b052db05aea332201216eJason Monk } 16607a4a56611cc044fd48b052db05aea332201216eJason Monk }); 16753380fecd1a1537e913578d1e53aa516d3f6e58eMady Mellor } 1688f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 16907a4a56611cc044fd48b052db05aea332201216eJason Monk try { 17007a4a56611cc044fd48b052db05aea332201216eJason Monk mDoneLatch.await(); 17107a4a56611cc044fd48b052db05aea332201216eJason Monk } catch (InterruptedException e) { 17207a4a56611cc044fd48b052db05aea332201216eJason Monk } 1738f8784c2622bc9900e772853bced17d091c4daf5Jason Monk Log.d(TAG, "Wrote render to " + output.getAbsolutePath()); 1748f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mContext.runOnUiThread(new Runnable() { 1758f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 1768f8784c2622bc9900e772853bced17d091c4daf5Jason Monk public void run() { 1778f8784c2622bc9900e772853bced17d091c4daf5Jason Monk ((ViewGroup) mParent.getParent()).removeView(mParent); 1788f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 1798f8784c2622bc9900e772853bced17d091c4daf5Jason Monk }); 18007a4a56611cc044fd48b052db05aea332201216eJason Monk } 18107a4a56611cc044fd48b052db05aea332201216eJason Monk 18207a4a56611cc044fd48b052db05aea332201216eJason Monk private Slice serAndUnSer(Slice s) { 1838f8784c2622bc9900e772853bced17d091c4daf5Jason Monk try { 18407a4a56611cc044fd48b052db05aea332201216eJason Monk ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 18507a4a56611cc044fd48b052db05aea332201216eJason Monk SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", 18607a4a56611cc044fd48b052db05aea332201216eJason Monk new SliceUtils.SerializeOptions() 18707a4a56611cc044fd48b052db05aea332201216eJason Monk .setImageMode(SliceUtils.SerializeOptions.MODE_CONVERT) 18807a4a56611cc044fd48b052db05aea332201216eJason Monk .setActionMode(SliceUtils.SerializeOptions.MODE_CONVERT)); 18907a4a56611cc044fd48b052db05aea332201216eJason Monk 19007a4a56611cc044fd48b052db05aea332201216eJason Monk byte[] bytes = outputStream.toByteArray(); 19138db00ef5d4b5a9d0d171f1bb15a5df567d448f6Jason Monk Log.d(TAG, "Serialized: " + new String(bytes)); 19207a4a56611cc044fd48b052db05aea332201216eJason Monk ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes); 19307a4a56611cc044fd48b052db05aea332201216eJason Monk return SliceUtils.parseSlice(mContext, inputStream, "UTF-8", 19407a4a56611cc044fd48b052db05aea332201216eJason Monk new SliceUtils.SliceActionListener() { 19507a4a56611cc044fd48b052db05aea332201216eJason Monk @Override 19638db00ef5d4b5a9d0d171f1bb15a5df567d448f6Jason Monk public void onSliceAction(Uri actionUri) { } 19707a4a56611cc044fd48b052db05aea332201216eJason Monk }); 19807a4a56611cc044fd48b052db05aea332201216eJason Monk } catch (Exception e) { 19907a4a56611cc044fd48b052db05aea332201216eJason Monk throw new RuntimeException(e); 2008f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2018f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2028f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 20307a4a56611cc044fd48b052db05aea332201216eJason Monk private void doRender(final String slice, final Slice s, final File file, 20407a4a56611cc044fd48b052db05aea332201216eJason Monk final boolean scrollable) { 2058f8784c2622bc9900e772853bced17d091c4daf5Jason Monk Log.d(TAG, "Rendering " + slice + " to " + file.getAbsolutePath()); 2068f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 20707a4a56611cc044fd48b052db05aea332201216eJason Monk try { 20807a4a56611cc044fd48b052db05aea332201216eJason Monk final CountDownLatch l = new CountDownLatch(1); 20907a4a56611cc044fd48b052db05aea332201216eJason Monk final Bitmap[] b = new Bitmap[1]; 21007a4a56611cc044fd48b052db05aea332201216eJason Monk synchronized (mRenderLock) { 21107a4a56611cc044fd48b052db05aea332201216eJason Monk mContext.runOnUiThread(new Runnable() { 2128f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 21307a4a56611cc044fd48b052db05aea332201216eJason Monk public void run() { 21407a4a56611cc044fd48b052db05aea332201216eJason Monk mSV1.setSlice(s); 21507a4a56611cc044fd48b052db05aea332201216eJason Monk mSV2.setSlice(s); 21607a4a56611cc044fd48b052db05aea332201216eJason Monk mSV3.setSlice(s); 21707a4a56611cc044fd48b052db05aea332201216eJason Monk mSV3.setScrollable(scrollable); 21807a4a56611cc044fd48b052db05aea332201216eJason Monk mSV1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { 2198f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 22007a4a56611cc044fd48b052db05aea332201216eJason Monk public void onLayoutChange(View v, int left, int top, int right, 22107a4a56611cc044fd48b052db05aea332201216eJason Monk int bottom, 22207a4a56611cc044fd48b052db05aea332201216eJason Monk int oldLeft, int oldTop, int oldRight, int oldBottom) { 22307a4a56611cc044fd48b052db05aea332201216eJason Monk mSV1.removeOnLayoutChangeListener(this); 22407a4a56611cc044fd48b052db05aea332201216eJason Monk mSV1.postDelayed(new Runnable() { 22507a4a56611cc044fd48b052db05aea332201216eJason Monk @Override 22607a4a56611cc044fd48b052db05aea332201216eJason Monk public void run() { 22707a4a56611cc044fd48b052db05aea332201216eJason Monk Log.d(TAG, "Drawing " + slice); 22807a4a56611cc044fd48b052db05aea332201216eJason Monk b[0] = Bitmap.createBitmap(mLayout.getMeasuredWidth(), 22907a4a56611cc044fd48b052db05aea332201216eJason Monk mLayout.getMeasuredHeight(), 23007a4a56611cc044fd48b052db05aea332201216eJason Monk Bitmap.Config.ARGB_8888); 23107a4a56611cc044fd48b052db05aea332201216eJason Monk 23207a4a56611cc044fd48b052db05aea332201216eJason Monk mLayout.draw(new Canvas(b[0])); 23307a4a56611cc044fd48b052db05aea332201216eJason Monk l.countDown(); 23407a4a56611cc044fd48b052db05aea332201216eJason Monk } 23507a4a56611cc044fd48b052db05aea332201216eJason Monk }, 10); 2368f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 23707a4a56611cc044fd48b052db05aea332201216eJason Monk }); 2388f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2398f8784c2622bc9900e772853bced17d091c4daf5Jason Monk }); 24007a4a56611cc044fd48b052db05aea332201216eJason Monk l.await(); 2418f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 24207a4a56611cc044fd48b052db05aea332201216eJason Monk doCompress(slice, b[0], new FileOutputStream(file)); 24307a4a56611cc044fd48b052db05aea332201216eJason Monk } catch (Exception e) { 24407a4a56611cc044fd48b052db05aea332201216eJason Monk throw new RuntimeException(e); 2458f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2468f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2478f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 2488f8784c2622bc9900e772853bced17d091c4daf5Jason Monk private void doCompress(final String slice, final Bitmap b, final FileOutputStream s) { 24907a4a56611cc044fd48b052db05aea332201216eJason Monk Log.d(TAG, "Compressing " + slice); 25007a4a56611cc044fd48b052db05aea332201216eJason Monk if (!b.compress(Bitmap.CompressFormat.PNG, 100, s)) { 25107a4a56611cc044fd48b052db05aea332201216eJason Monk throw new RuntimeException("Unable to compress"); 25207a4a56611cc044fd48b052db05aea332201216eJason Monk } 2538f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 25407a4a56611cc044fd48b052db05aea332201216eJason Monk b.recycle(); 25507a4a56611cc044fd48b052db05aea332201216eJason Monk mDoneLatch.countDown(); 25607a4a56611cc044fd48b052db05aea332201216eJason Monk Log.d(TAG, "Done " + slice); 2578f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2588f8784c2622bc9900e772853bced17d091c4daf5Jason Monk 2598f8784c2622bc9900e772853bced17d091c4daf5Jason Monk public void renderAll(final Runnable runnable) { 2608f8784c2622bc9900e772853bced17d091c4daf5Jason Monk final ProgressDialog dialog = ProgressDialog.show(mContext, null, "Rendering..."); 2618f8784c2622bc9900e772853bced17d091c4daf5Jason Monk new Thread(new Runnable() { 2628f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 2638f8784c2622bc9900e772853bced17d091c4daf5Jason Monk public void run() { 2648f8784c2622bc9900e772853bced17d091c4daf5Jason Monk doRender(); 2658f8784c2622bc9900e772853bced17d091c4daf5Jason Monk mContext.runOnUiThread(new Runnable() { 2668f8784c2622bc9900e772853bced17d091c4daf5Jason Monk @Override 2678f8784c2622bc9900e772853bced17d091c4daf5Jason Monk public void run() { 2688f8784c2622bc9900e772853bced17d091c4daf5Jason Monk dialog.dismiss(); 2698f8784c2622bc9900e772853bced17d091c4daf5Jason Monk runnable.run(); 2708f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2718f8784c2622bc9900e772853bced17d091c4daf5Jason Monk }); 2728f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2738f8784c2622bc9900e772853bced17d091c4daf5Jason Monk }).start(); 2748f8784c2622bc9900e772853bced17d091c4daf5Jason Monk } 2758f8784c2622bc9900e772853bced17d091c4daf5Jason Monk} 276