1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.basicrenderscript; 18 19 import android.graphics.Bitmap; 20 import android.graphics.BitmapFactory; 21 import android.os.AsyncTask; 22 import android.os.Bundle; 23 import android.support.v7.app.AppCompatActivity; 24 import android.support.v8.renderscript.Allocation; 25 import android.support.v8.renderscript.RenderScript; 26 import android.widget.ImageView; 27 import android.widget.SeekBar; 28 import android.widget.SeekBar.OnSeekBarChangeListener; 29 30 public class MainActivity extends AppCompatActivity { 31 32 /** 33 * Number of bitmaps that is used for RenderScript thread and UI thread synchronization. 34 */ 35 private final int NUM_BITMAPS = 2; 36 private int mCurrentBitmap = 0; 37 private Bitmap mBitmapIn; 38 private Bitmap[] mBitmapsOut; 39 private ImageView mImageView; 40 41 private Allocation mInAllocation; 42 private Allocation[] mOutAllocations; 43 private ScriptC_saturation mScript; 44 private RenderScriptTask mCurrentTask; 45 46 @Override 47 protected void onCreate(Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 50 setContentView(R.layout.main_layout); 51 52 // Initialize UI 53 mBitmapIn = loadBitmap(R.drawable.data); 54 mBitmapsOut = new Bitmap[NUM_BITMAPS]; 55 for (int i = 0; i < NUM_BITMAPS; ++i) { 56 mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(), 57 mBitmapIn.getHeight(), mBitmapIn.getConfig()); 58 } 59 60 mImageView = (ImageView) findViewById(R.id.imageView); 61 mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]); 62 mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS; 63 64 SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1); 65 seekbar.setProgress(50); 66 seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 67 public void onProgressChanged(SeekBar seekBar, int progress, 68 boolean fromUser) { 69 float max = 2.0f; 70 float min = 0.0f; 71 float f = (float) ((max - min) * (progress / 100.0) + min); 72 updateImage(f); 73 } 74 75 @Override 76 public void onStartTrackingTouch(SeekBar seekBar) { 77 } 78 79 @Override 80 public void onStopTrackingTouch(SeekBar seekBar) { 81 } 82 }); 83 84 // Create renderScript 85 createScript(); 86 87 // Invoke renderScript kernel and update imageView 88 updateImage(1.0f); 89 } 90 91 /** 92 * Initialize RenderScript. 93 * 94 * <p>In the sample, it creates RenderScript kernel that performs saturation manipulation.</p> 95 */ 96 private void createScript() { 97 // Initialize RS 98 RenderScript rs = RenderScript.create(this); 99 100 // Allocate buffers 101 mInAllocation = Allocation.createFromBitmap(rs, mBitmapIn); 102 mOutAllocations = new Allocation[NUM_BITMAPS]; 103 for (int i = 0; i < NUM_BITMAPS; ++i) { 104 mOutAllocations[i] = Allocation.createFromBitmap(rs, mBitmapsOut[i]); 105 } 106 107 // Load script 108 mScript = new ScriptC_saturation(rs); 109 } 110 111 /* 112 * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering. 113 * After the filtering is done, an operation blocks at Allocation.copyTo() in AsyncTask thread. 114 * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update 115 * ImageView UI. 116 */ 117 private class RenderScriptTask extends AsyncTask<Float, Void, Integer> { 118 Boolean issued = false; 119 120 protected Integer doInBackground(Float... values) { 121 int index = -1; 122 if (!isCancelled()) { 123 issued = true; 124 index = mCurrentBitmap; 125 126 // Set global variable in RS 127 mScript.set_saturationValue(values[0]); 128 129 // Invoke saturation filter kernel 130 mScript.forEach_saturation(mInAllocation, mOutAllocations[index]); 131 132 // Copy to bitmap and invalidate image view 133 mOutAllocations[index].copyTo(mBitmapsOut[index]); 134 mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS; 135 } 136 return index; 137 } 138 139 void updateView(Integer result) { 140 if (result != -1) { 141 // Request UI update 142 mImageView.setImageBitmap(mBitmapsOut[result]); 143 mImageView.invalidate(); 144 } 145 } 146 147 protected void onPostExecute(Integer result) { 148 updateView(result); 149 } 150 151 protected void onCancelled(Integer result) { 152 if (issued) { 153 updateView(result); 154 } 155 } 156 } 157 158 /** 159 * Invoke AsyncTask and cancel previous task. When AsyncTasks are piled up (typically in slow 160 * device with heavy kernel), Only the latest (and already started) task invokes RenderScript 161 * operation. 162 */ 163 private void updateImage(final float f) { 164 if (mCurrentTask != null) { 165 mCurrentTask.cancel(false); 166 } 167 mCurrentTask = new RenderScriptTask(); 168 mCurrentTask.execute(f); 169 } 170 171 /** 172 * Helper to load Bitmap from resource 173 */ 174 private Bitmap loadBitmap(int resource) { 175 final BitmapFactory.Options options = new BitmapFactory.Options(); 176 options.inPreferredConfig = Bitmap.Config.ARGB_8888; 177 return BitmapFactory.decodeResource(getResources(), resource, options); 178 } 179 180 } 181