1*90c8c64dSAndroid Build Coastguard Worker /* 2*90c8c64dSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project 3*90c8c64dSAndroid Build Coastguard Worker * 4*90c8c64dSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*90c8c64dSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*90c8c64dSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*90c8c64dSAndroid Build Coastguard Worker * 8*90c8c64dSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*90c8c64dSAndroid Build Coastguard Worker * 10*90c8c64dSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*90c8c64dSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*90c8c64dSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*90c8c64dSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*90c8c64dSAndroid Build Coastguard Worker * limitations under the License. 15*90c8c64dSAndroid Build Coastguard Worker */ 16*90c8c64dSAndroid Build Coastguard Worker 17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.renderscriptintrinsic; 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker import android.app.Activity; 20*90c8c64dSAndroid Build Coastguard Worker import android.graphics.Bitmap; 21*90c8c64dSAndroid Build Coastguard Worker import android.graphics.BitmapFactory; 22*90c8c64dSAndroid Build Coastguard Worker import android.os.AsyncTask; 23*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle; 24*90c8c64dSAndroid Build Coastguard Worker import android.widget.CompoundButton; 25*90c8c64dSAndroid Build Coastguard Worker import android.widget.CompoundButton.OnCheckedChangeListener; 26*90c8c64dSAndroid Build Coastguard Worker import android.widget.ImageView; 27*90c8c64dSAndroid Build Coastguard Worker import android.widget.RadioButton; 28*90c8c64dSAndroid Build Coastguard Worker import android.widget.SeekBar; 29*90c8c64dSAndroid Build Coastguard Worker import android.widget.SeekBar.OnSeekBarChangeListener; 30*90c8c64dSAndroid Build Coastguard Worker import android.support.v8.renderscript.*; 31*90c8c64dSAndroid Build Coastguard Worker 32*90c8c64dSAndroid Build Coastguard Worker public class MainActivity extends Activity { 33*90c8c64dSAndroid Build Coastguard Worker /* Number of bitmaps that is used for renderScript thread and UI thread synchronization. 34*90c8c64dSAndroid Build Coastguard Worker Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI. 35*90c8c64dSAndroid Build Coastguard Worker Investigating a root cause. 36*90c8c64dSAndroid Build Coastguard Worker */ 37*90c8c64dSAndroid Build Coastguard Worker private final int NUM_BITMAPS = 3; 38*90c8c64dSAndroid Build Coastguard Worker private int mCurrentBitmap = 0; 39*90c8c64dSAndroid Build Coastguard Worker private Bitmap mBitmapIn; 40*90c8c64dSAndroid Build Coastguard Worker private Bitmap[] mBitmapsOut; 41*90c8c64dSAndroid Build Coastguard Worker private ImageView mImageView; 42*90c8c64dSAndroid Build Coastguard Worker 43*90c8c64dSAndroid Build Coastguard Worker private RenderScript mRS; 44*90c8c64dSAndroid Build Coastguard Worker private Allocation mInAllocation; 45*90c8c64dSAndroid Build Coastguard Worker private Allocation[] mOutAllocations; 46*90c8c64dSAndroid Build Coastguard Worker 47*90c8c64dSAndroid Build Coastguard Worker private ScriptIntrinsicBlur mScriptBlur; 48*90c8c64dSAndroid Build Coastguard Worker private ScriptIntrinsicConvolve5x5 mScriptConvolve; 49*90c8c64dSAndroid Build Coastguard Worker private ScriptIntrinsicColorMatrix mScriptMatrix; 50*90c8c64dSAndroid Build Coastguard Worker 51*90c8c64dSAndroid Build Coastguard Worker private final int MODE_BLUR = 0; 52*90c8c64dSAndroid Build Coastguard Worker private final int MODE_CONVOLVE = 1; 53*90c8c64dSAndroid Build Coastguard Worker private final int MODE_COLORMATRIX = 2; 54*90c8c64dSAndroid Build Coastguard Worker 55*90c8c64dSAndroid Build Coastguard Worker private int mFilterMode = MODE_BLUR; 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker private RenderScriptTask mLatestTask = null; 58*90c8c64dSAndroid Build Coastguard Worker 59*90c8c64dSAndroid Build Coastguard Worker @Override onCreate(Bundle savedInstanceState)60*90c8c64dSAndroid Build Coastguard Worker protected void onCreate(Bundle savedInstanceState) { 61*90c8c64dSAndroid Build Coastguard Worker super.onCreate(savedInstanceState); 62*90c8c64dSAndroid Build Coastguard Worker 63*90c8c64dSAndroid Build Coastguard Worker setContentView(R.layout.main_layout); 64*90c8c64dSAndroid Build Coastguard Worker 65*90c8c64dSAndroid Build Coastguard Worker /* 66*90c8c64dSAndroid Build Coastguard Worker * Initialize UI 67*90c8c64dSAndroid Build Coastguard Worker */ 68*90c8c64dSAndroid Build Coastguard Worker 69*90c8c64dSAndroid Build Coastguard Worker //Set up main image view 70*90c8c64dSAndroid Build Coastguard Worker mBitmapIn = loadBitmap(R.drawable.data); 71*90c8c64dSAndroid Build Coastguard Worker mBitmapsOut = new Bitmap[NUM_BITMAPS]; 72*90c8c64dSAndroid Build Coastguard Worker for (int i = 0; i < NUM_BITMAPS; ++i) { 73*90c8c64dSAndroid Build Coastguard Worker mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(), 74*90c8c64dSAndroid Build Coastguard Worker mBitmapIn.getHeight(), mBitmapIn.getConfig()); 75*90c8c64dSAndroid Build Coastguard Worker } 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard Worker mImageView = (ImageView) findViewById(R.id.imageView); 78*90c8c64dSAndroid Build Coastguard Worker mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]); 79*90c8c64dSAndroid Build Coastguard Worker mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS; 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker //Set up seekbar 82*90c8c64dSAndroid Build Coastguard Worker final SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1); 83*90c8c64dSAndroid Build Coastguard Worker seekbar.setProgress(50); 84*90c8c64dSAndroid Build Coastguard Worker seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 85*90c8c64dSAndroid Build Coastguard Worker public void onProgressChanged(SeekBar seekBar, int progress, 86*90c8c64dSAndroid Build Coastguard Worker boolean fromUser) { 87*90c8c64dSAndroid Build Coastguard Worker updateImage(progress); 88*90c8c64dSAndroid Build Coastguard Worker } 89*90c8c64dSAndroid Build Coastguard Worker 90*90c8c64dSAndroid Build Coastguard Worker @Override 91*90c8c64dSAndroid Build Coastguard Worker public void onStartTrackingTouch(SeekBar seekBar) { 92*90c8c64dSAndroid Build Coastguard Worker } 93*90c8c64dSAndroid Build Coastguard Worker 94*90c8c64dSAndroid Build Coastguard Worker @Override 95*90c8c64dSAndroid Build Coastguard Worker public void onStopTrackingTouch(SeekBar seekBar) { 96*90c8c64dSAndroid Build Coastguard Worker } 97*90c8c64dSAndroid Build Coastguard Worker }); 98*90c8c64dSAndroid Build Coastguard Worker 99*90c8c64dSAndroid Build Coastguard Worker //Setup effect selector 100*90c8c64dSAndroid Build Coastguard Worker RadioButton radio0 = (RadioButton) findViewById(R.id.radio0); 101*90c8c64dSAndroid Build Coastguard Worker radio0.setOnCheckedChangeListener(new OnCheckedChangeListener() { 102*90c8c64dSAndroid Build Coastguard Worker 103*90c8c64dSAndroid Build Coastguard Worker @Override 104*90c8c64dSAndroid Build Coastguard Worker public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 105*90c8c64dSAndroid Build Coastguard Worker if (isChecked) { 106*90c8c64dSAndroid Build Coastguard Worker mFilterMode = MODE_BLUR; 107*90c8c64dSAndroid Build Coastguard Worker updateImage(seekbar.getProgress()); 108*90c8c64dSAndroid Build Coastguard Worker } 109*90c8c64dSAndroid Build Coastguard Worker } 110*90c8c64dSAndroid Build Coastguard Worker }); 111*90c8c64dSAndroid Build Coastguard Worker RadioButton radio1 = (RadioButton) findViewById(R.id.radio1); 112*90c8c64dSAndroid Build Coastguard Worker radio1.setOnCheckedChangeListener(new OnCheckedChangeListener() { 113*90c8c64dSAndroid Build Coastguard Worker 114*90c8c64dSAndroid Build Coastguard Worker @Override 115*90c8c64dSAndroid Build Coastguard Worker public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 116*90c8c64dSAndroid Build Coastguard Worker if (isChecked) { 117*90c8c64dSAndroid Build Coastguard Worker mFilterMode = MODE_CONVOLVE; 118*90c8c64dSAndroid Build Coastguard Worker updateImage(seekbar.getProgress()); 119*90c8c64dSAndroid Build Coastguard Worker } 120*90c8c64dSAndroid Build Coastguard Worker } 121*90c8c64dSAndroid Build Coastguard Worker }); 122*90c8c64dSAndroid Build Coastguard Worker RadioButton radio2 = (RadioButton) findViewById(R.id.radio2); 123*90c8c64dSAndroid Build Coastguard Worker radio2.setOnCheckedChangeListener(new OnCheckedChangeListener() { 124*90c8c64dSAndroid Build Coastguard Worker 125*90c8c64dSAndroid Build Coastguard Worker @Override 126*90c8c64dSAndroid Build Coastguard Worker public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 127*90c8c64dSAndroid Build Coastguard Worker if (isChecked) { 128*90c8c64dSAndroid Build Coastguard Worker mFilterMode = MODE_COLORMATRIX; 129*90c8c64dSAndroid Build Coastguard Worker updateImage(seekbar.getProgress()); 130*90c8c64dSAndroid Build Coastguard Worker } 131*90c8c64dSAndroid Build Coastguard Worker } 132*90c8c64dSAndroid Build Coastguard Worker }); 133*90c8c64dSAndroid Build Coastguard Worker 134*90c8c64dSAndroid Build Coastguard Worker /* 135*90c8c64dSAndroid Build Coastguard Worker * Create renderScript 136*90c8c64dSAndroid Build Coastguard Worker */ 137*90c8c64dSAndroid Build Coastguard Worker createScript(); 138*90c8c64dSAndroid Build Coastguard Worker 139*90c8c64dSAndroid Build Coastguard Worker /* 140*90c8c64dSAndroid Build Coastguard Worker * Create thumbnails 141*90c8c64dSAndroid Build Coastguard Worker */ 142*90c8c64dSAndroid Build Coastguard Worker createThumbnail(); 143*90c8c64dSAndroid Build Coastguard Worker 144*90c8c64dSAndroid Build Coastguard Worker 145*90c8c64dSAndroid Build Coastguard Worker /* 146*90c8c64dSAndroid Build Coastguard Worker * Invoke renderScript kernel and update imageView 147*90c8c64dSAndroid Build Coastguard Worker */ 148*90c8c64dSAndroid Build Coastguard Worker mFilterMode = MODE_BLUR; 149*90c8c64dSAndroid Build Coastguard Worker updateImage(50); 150*90c8c64dSAndroid Build Coastguard Worker } 151*90c8c64dSAndroid Build Coastguard Worker createScript()152*90c8c64dSAndroid Build Coastguard Worker private void createScript() { 153*90c8c64dSAndroid Build Coastguard Worker mRS = RenderScript.create(this); 154*90c8c64dSAndroid Build Coastguard Worker 155*90c8c64dSAndroid Build Coastguard Worker mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn); 156*90c8c64dSAndroid Build Coastguard Worker 157*90c8c64dSAndroid Build Coastguard Worker mOutAllocations = new Allocation[NUM_BITMAPS]; 158*90c8c64dSAndroid Build Coastguard Worker for (int i = 0; i < NUM_BITMAPS; ++i) { 159*90c8c64dSAndroid Build Coastguard Worker mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]); 160*90c8c64dSAndroid Build Coastguard Worker } 161*90c8c64dSAndroid Build Coastguard Worker 162*90c8c64dSAndroid Build Coastguard Worker /* 163*90c8c64dSAndroid Build Coastguard Worker Create intrinsics. 164*90c8c64dSAndroid Build Coastguard Worker RenderScript has built-in features such as blur, convolve filter etc. 165*90c8c64dSAndroid Build Coastguard Worker These intrinsics are handy for specific operations without writing RenderScript kernel. 166*90c8c64dSAndroid Build Coastguard Worker In the sample, it's creating blur, convolve and matrix intrinsics. 167*90c8c64dSAndroid Build Coastguard Worker */ 168*90c8c64dSAndroid Build Coastguard Worker 169*90c8c64dSAndroid Build Coastguard Worker mScriptBlur = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS)); 170*90c8c64dSAndroid Build Coastguard Worker mScriptConvolve = ScriptIntrinsicConvolve5x5.create(mRS, 171*90c8c64dSAndroid Build Coastguard Worker Element.U8_4(mRS)); 172*90c8c64dSAndroid Build Coastguard Worker mScriptMatrix = ScriptIntrinsicColorMatrix.create(mRS, 173*90c8c64dSAndroid Build Coastguard Worker Element.U8_4(mRS)); 174*90c8c64dSAndroid Build Coastguard Worker } 175*90c8c64dSAndroid Build Coastguard Worker performFilter(Allocation inAllocation, Allocation outAllocation, Bitmap bitmapOut, float value)176*90c8c64dSAndroid Build Coastguard Worker private void performFilter(Allocation inAllocation, 177*90c8c64dSAndroid Build Coastguard Worker Allocation outAllocation, Bitmap bitmapOut, float value) { 178*90c8c64dSAndroid Build Coastguard Worker switch (mFilterMode) { 179*90c8c64dSAndroid Build Coastguard Worker case MODE_BLUR: 180*90c8c64dSAndroid Build Coastguard Worker /* 181*90c8c64dSAndroid Build Coastguard Worker * Set blur kernel size 182*90c8c64dSAndroid Build Coastguard Worker */ 183*90c8c64dSAndroid Build Coastguard Worker mScriptBlur.setRadius(value); 184*90c8c64dSAndroid Build Coastguard Worker 185*90c8c64dSAndroid Build Coastguard Worker /* 186*90c8c64dSAndroid Build Coastguard Worker * Invoke filter kernel 187*90c8c64dSAndroid Build Coastguard Worker */ 188*90c8c64dSAndroid Build Coastguard Worker mScriptBlur.setInput(inAllocation); 189*90c8c64dSAndroid Build Coastguard Worker mScriptBlur.forEach(outAllocation); 190*90c8c64dSAndroid Build Coastguard Worker break; 191*90c8c64dSAndroid Build Coastguard Worker case MODE_CONVOLVE: { 192*90c8c64dSAndroid Build Coastguard Worker float f1 = value; 193*90c8c64dSAndroid Build Coastguard Worker float f2 = 1.0f - f1; 194*90c8c64dSAndroid Build Coastguard Worker 195*90c8c64dSAndroid Build Coastguard Worker // Emboss filter kernel 196*90c8c64dSAndroid Build Coastguard Worker float coefficients[] = {-f1 * 2, 0, -f1, 0, 0, 0, -f2 * 2, -f2, 0, 197*90c8c64dSAndroid Build Coastguard Worker 0, -f1, -f2, 1, f2, f1, 0, 0, f2, f2 * 2, 0, 0, 0, f1, 0, 198*90c8c64dSAndroid Build Coastguard Worker f1 * 2,}; 199*90c8c64dSAndroid Build Coastguard Worker /* 200*90c8c64dSAndroid Build Coastguard Worker * Set kernel parameter 201*90c8c64dSAndroid Build Coastguard Worker */ 202*90c8c64dSAndroid Build Coastguard Worker mScriptConvolve.setCoefficients(coefficients); 203*90c8c64dSAndroid Build Coastguard Worker 204*90c8c64dSAndroid Build Coastguard Worker /* 205*90c8c64dSAndroid Build Coastguard Worker * Invoke filter kernel 206*90c8c64dSAndroid Build Coastguard Worker */ 207*90c8c64dSAndroid Build Coastguard Worker mScriptConvolve.setInput(inAllocation); 208*90c8c64dSAndroid Build Coastguard Worker mScriptConvolve.forEach(outAllocation); 209*90c8c64dSAndroid Build Coastguard Worker break; 210*90c8c64dSAndroid Build Coastguard Worker } 211*90c8c64dSAndroid Build Coastguard Worker case MODE_COLORMATRIX: { 212*90c8c64dSAndroid Build Coastguard Worker /* 213*90c8c64dSAndroid Build Coastguard Worker * Set HUE rotation matrix 214*90c8c64dSAndroid Build Coastguard Worker * The matrix below performs a combined operation of, 215*90c8c64dSAndroid Build Coastguard Worker * RGB->HSV transform * HUE rotation * HSV->RGB transform 216*90c8c64dSAndroid Build Coastguard Worker */ 217*90c8c64dSAndroid Build Coastguard Worker float cos = (float) Math.cos((double) value); 218*90c8c64dSAndroid Build Coastguard Worker float sin = (float) Math.sin((double) value); 219*90c8c64dSAndroid Build Coastguard Worker Matrix3f mat = new Matrix3f(); 220*90c8c64dSAndroid Build Coastguard Worker mat.set(0, 0, (float) (.299 + .701 * cos + .168 * sin)); 221*90c8c64dSAndroid Build Coastguard Worker mat.set(1, 0, (float) (.587 - .587 * cos + .330 * sin)); 222*90c8c64dSAndroid Build Coastguard Worker mat.set(2, 0, (float) (.114 - .114 * cos - .497 * sin)); 223*90c8c64dSAndroid Build Coastguard Worker mat.set(0, 1, (float) (.299 - .299 * cos - .328 * sin)); 224*90c8c64dSAndroid Build Coastguard Worker mat.set(1, 1, (float) (.587 + .413 * cos + .035 * sin)); 225*90c8c64dSAndroid Build Coastguard Worker mat.set(2, 1, (float) (.114 - .114 * cos + .292 * sin)); 226*90c8c64dSAndroid Build Coastguard Worker mat.set(0, 2, (float) (.299 - .3 * cos + 1.25 * sin)); 227*90c8c64dSAndroid Build Coastguard Worker mat.set(1, 2, (float) (.587 - .588 * cos - 1.05 * sin)); 228*90c8c64dSAndroid Build Coastguard Worker mat.set(2, 2, (float) (.114 + .886 * cos - .203 * sin)); 229*90c8c64dSAndroid Build Coastguard Worker mScriptMatrix.setColorMatrix(mat); 230*90c8c64dSAndroid Build Coastguard Worker 231*90c8c64dSAndroid Build Coastguard Worker /* 232*90c8c64dSAndroid Build Coastguard Worker * Invoke filter kernel 233*90c8c64dSAndroid Build Coastguard Worker */ 234*90c8c64dSAndroid Build Coastguard Worker mScriptMatrix.forEach(inAllocation, outAllocation); 235*90c8c64dSAndroid Build Coastguard Worker } 236*90c8c64dSAndroid Build Coastguard Worker break; 237*90c8c64dSAndroid Build Coastguard Worker } 238*90c8c64dSAndroid Build Coastguard Worker 239*90c8c64dSAndroid Build Coastguard Worker /* 240*90c8c64dSAndroid Build Coastguard Worker * Copy to bitmap and invalidate image view 241*90c8c64dSAndroid Build Coastguard Worker */ 242*90c8c64dSAndroid Build Coastguard Worker outAllocation.copyTo(bitmapOut); 243*90c8c64dSAndroid Build Coastguard Worker } 244*90c8c64dSAndroid Build Coastguard Worker 245*90c8c64dSAndroid Build Coastguard Worker /* 246*90c8c64dSAndroid Build Coastguard Worker Convert seekBar progress parameter (0-100 in range) to parameter for each intrinsic filter. 247*90c8c64dSAndroid Build Coastguard Worker (e.g. 1.0-25.0 in Blur filter) 248*90c8c64dSAndroid Build Coastguard Worker */ getFilterParameter(int i)249*90c8c64dSAndroid Build Coastguard Worker private float getFilterParameter(int i) { 250*90c8c64dSAndroid Build Coastguard Worker float f = 0.f; 251*90c8c64dSAndroid Build Coastguard Worker switch (mFilterMode) { 252*90c8c64dSAndroid Build Coastguard Worker case MODE_BLUR: { 253*90c8c64dSAndroid Build Coastguard Worker final float max = 25.0f; 254*90c8c64dSAndroid Build Coastguard Worker final float min = 1.f; 255*90c8c64dSAndroid Build Coastguard Worker f = (float) ((max - min) * (i / 100.0) + min); 256*90c8c64dSAndroid Build Coastguard Worker } 257*90c8c64dSAndroid Build Coastguard Worker break; 258*90c8c64dSAndroid Build Coastguard Worker case MODE_CONVOLVE: { 259*90c8c64dSAndroid Build Coastguard Worker final float max = 2.f; 260*90c8c64dSAndroid Build Coastguard Worker final float min = 0.f; 261*90c8c64dSAndroid Build Coastguard Worker f = (float) ((max - min) * (i / 100.0) + min); 262*90c8c64dSAndroid Build Coastguard Worker } 263*90c8c64dSAndroid Build Coastguard Worker break; 264*90c8c64dSAndroid Build Coastguard Worker case MODE_COLORMATRIX: { 265*90c8c64dSAndroid Build Coastguard Worker final float max = (float) Math.PI; 266*90c8c64dSAndroid Build Coastguard Worker final float min = (float) -Math.PI; 267*90c8c64dSAndroid Build Coastguard Worker f = (float) ((max - min) * (i / 100.0) + min); 268*90c8c64dSAndroid Build Coastguard Worker } 269*90c8c64dSAndroid Build Coastguard Worker break; 270*90c8c64dSAndroid Build Coastguard Worker } 271*90c8c64dSAndroid Build Coastguard Worker return f; 272*90c8c64dSAndroid Build Coastguard Worker 273*90c8c64dSAndroid Build Coastguard Worker } 274*90c8c64dSAndroid Build Coastguard Worker 275*90c8c64dSAndroid Build Coastguard Worker /* 276*90c8c64dSAndroid Build Coastguard Worker * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering. 277*90c8c64dSAndroid Build Coastguard Worker * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread. 278*90c8c64dSAndroid Build Coastguard Worker * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI. 279*90c8c64dSAndroid Build Coastguard Worker */ 280*90c8c64dSAndroid Build Coastguard Worker private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> { 281*90c8c64dSAndroid Build Coastguard Worker Boolean issued = false; 282*90c8c64dSAndroid Build Coastguard Worker doInBackground(Float... values)283*90c8c64dSAndroid Build Coastguard Worker protected Integer doInBackground(Float... values) { 284*90c8c64dSAndroid Build Coastguard Worker int index = -1; 285*90c8c64dSAndroid Build Coastguard Worker if (isCancelled() == false) { 286*90c8c64dSAndroid Build Coastguard Worker issued = true; 287*90c8c64dSAndroid Build Coastguard Worker index = mCurrentBitmap; 288*90c8c64dSAndroid Build Coastguard Worker 289*90c8c64dSAndroid Build Coastguard Worker performFilter(mInAllocation, mOutAllocations[index], mBitmapsOut[index], values[0]); 290*90c8c64dSAndroid Build Coastguard Worker mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS; 291*90c8c64dSAndroid Build Coastguard Worker } 292*90c8c64dSAndroid Build Coastguard Worker return index; 293*90c8c64dSAndroid Build Coastguard Worker } 294*90c8c64dSAndroid Build Coastguard Worker updateView(Integer result)295*90c8c64dSAndroid Build Coastguard Worker void updateView(Integer result) { 296*90c8c64dSAndroid Build Coastguard Worker if (result != -1) { 297*90c8c64dSAndroid Build Coastguard Worker // Request UI update 298*90c8c64dSAndroid Build Coastguard Worker mImageView.setImageBitmap(mBitmapsOut[result]); 299*90c8c64dSAndroid Build Coastguard Worker mImageView.invalidate(); 300*90c8c64dSAndroid Build Coastguard Worker } 301*90c8c64dSAndroid Build Coastguard Worker } 302*90c8c64dSAndroid Build Coastguard Worker onPostExecute(Integer result)303*90c8c64dSAndroid Build Coastguard Worker protected void onPostExecute(Integer result) { 304*90c8c64dSAndroid Build Coastguard Worker updateView(result); 305*90c8c64dSAndroid Build Coastguard Worker } 306*90c8c64dSAndroid Build Coastguard Worker onCancelled(Integer result)307*90c8c64dSAndroid Build Coastguard Worker protected void onCancelled(Integer result) { 308*90c8c64dSAndroid Build Coastguard Worker if (issued) { 309*90c8c64dSAndroid Build Coastguard Worker updateView(result); 310*90c8c64dSAndroid Build Coastguard Worker } 311*90c8c64dSAndroid Build Coastguard Worker } 312*90c8c64dSAndroid Build Coastguard Worker } 313*90c8c64dSAndroid Build Coastguard Worker 314*90c8c64dSAndroid Build Coastguard Worker /* 315*90c8c64dSAndroid Build Coastguard Worker Invoke AsynchTask and cancel previous task. 316*90c8c64dSAndroid Build Coastguard Worker When AsyncTasks are piled up (typically in slow device with heavy kernel), 317*90c8c64dSAndroid Build Coastguard Worker Only the latest (and already started) task invokes RenderScript operation. 318*90c8c64dSAndroid Build Coastguard Worker */ updateImage(int progress)319*90c8c64dSAndroid Build Coastguard Worker private void updateImage(int progress) { 320*90c8c64dSAndroid Build Coastguard Worker float f = getFilterParameter(progress); 321*90c8c64dSAndroid Build Coastguard Worker 322*90c8c64dSAndroid Build Coastguard Worker if (mLatestTask != null) 323*90c8c64dSAndroid Build Coastguard Worker mLatestTask.cancel(false); 324*90c8c64dSAndroid Build Coastguard Worker mLatestTask = new RenderScriptTask(); 325*90c8c64dSAndroid Build Coastguard Worker 326*90c8c64dSAndroid Build Coastguard Worker mLatestTask.execute(f); 327*90c8c64dSAndroid Build Coastguard Worker } 328*90c8c64dSAndroid Build Coastguard Worker 329*90c8c64dSAndroid Build Coastguard Worker /* 330*90c8c64dSAndroid Build Coastguard Worker Helper to load Bitmap from resource 331*90c8c64dSAndroid Build Coastguard Worker */ loadBitmap(int resource)332*90c8c64dSAndroid Build Coastguard Worker private Bitmap loadBitmap(int resource) { 333*90c8c64dSAndroid Build Coastguard Worker final BitmapFactory.Options options = new BitmapFactory.Options(); 334*90c8c64dSAndroid Build Coastguard Worker options.inPreferredConfig = Bitmap.Config.ARGB_8888; 335*90c8c64dSAndroid Build Coastguard Worker return BitmapFactory.decodeResource(getResources(), resource, options); 336*90c8c64dSAndroid Build Coastguard Worker } 337*90c8c64dSAndroid Build Coastguard Worker 338*90c8c64dSAndroid Build Coastguard Worker /* 339*90c8c64dSAndroid Build Coastguard Worker Create thumbNail for UI. It invokes RenderScript kernel synchronously in UI-thread, 340*90c8c64dSAndroid Build Coastguard Worker which is OK for small thumbnail (but not ideal). 341*90c8c64dSAndroid Build Coastguard Worker */ createThumbnail()342*90c8c64dSAndroid Build Coastguard Worker private void createThumbnail() { 343*90c8c64dSAndroid Build Coastguard Worker int width = 72; 344*90c8c64dSAndroid Build Coastguard Worker int height = 96; 345*90c8c64dSAndroid Build Coastguard Worker float scale = getResources().getDisplayMetrics().density; 346*90c8c64dSAndroid Build Coastguard Worker int pixelsWidth = (int) (width * scale + 0.5f); 347*90c8c64dSAndroid Build Coastguard Worker int pixelsHeight = (int) (height * scale + 0.5f); 348*90c8c64dSAndroid Build Coastguard Worker 349*90c8c64dSAndroid Build Coastguard Worker //Temporary image 350*90c8c64dSAndroid Build Coastguard Worker Bitmap tempBitmap = Bitmap.createScaledBitmap(mBitmapIn, pixelsWidth, pixelsHeight, false); 351*90c8c64dSAndroid Build Coastguard Worker Allocation inAllocation = Allocation.createFromBitmap(mRS, tempBitmap); 352*90c8c64dSAndroid Build Coastguard Worker 353*90c8c64dSAndroid Build Coastguard Worker //Create thumbnail with each RS intrinsic and set it to radio buttons 354*90c8c64dSAndroid Build Coastguard Worker int[] modes = {MODE_BLUR, MODE_CONVOLVE, MODE_COLORMATRIX}; 355*90c8c64dSAndroid Build Coastguard Worker int[] ids = {R.id.radio0, R.id.radio1, R.id.radio2}; 356*90c8c64dSAndroid Build Coastguard Worker int[] parameter = {50, 100, 25}; 357*90c8c64dSAndroid Build Coastguard Worker for (int mode : modes) { 358*90c8c64dSAndroid Build Coastguard Worker mFilterMode = mode; 359*90c8c64dSAndroid Build Coastguard Worker float f = getFilterParameter(parameter[mode]); 360*90c8c64dSAndroid Build Coastguard Worker 361*90c8c64dSAndroid Build Coastguard Worker Bitmap destBitpmap = Bitmap.createBitmap(tempBitmap.getWidth(), 362*90c8c64dSAndroid Build Coastguard Worker tempBitmap.getHeight(), tempBitmap.getConfig()); 363*90c8c64dSAndroid Build Coastguard Worker Allocation outAllocation = Allocation.createFromBitmap(mRS, destBitpmap); 364*90c8c64dSAndroid Build Coastguard Worker performFilter(inAllocation, outAllocation, destBitpmap, f); 365*90c8c64dSAndroid Build Coastguard Worker 366*90c8c64dSAndroid Build Coastguard Worker ThumbnailRadioButton button = (ThumbnailRadioButton) findViewById(ids[mode]); 367*90c8c64dSAndroid Build Coastguard Worker button.setThumbnail(destBitpmap); 368*90c8c64dSAndroid Build Coastguard Worker } 369*90c8c64dSAndroid Build Coastguard Worker } 370*90c8c64dSAndroid Build Coastguard Worker } 371