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.app.Activity;
20
import android.graphics.Bitmap;
21
import android.graphics.BitmapFactory;
22
import android.os.AsyncTask;
23
import android.os.Bundle;
24
import android.widget.ImageView;
25
import android.widget.SeekBar;
26
import android.widget.SeekBar.OnSeekBarChangeListener;
27
import android.support.v8.renderscript.*;
28
29
public class MainActivity extends Activity {
30
/* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
31
Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
32
Investigating a root cause.
33
*/
34
private final int NUM_BITMAPS = 3;
35
private int mCurrentBitmap = 0;
36
private Bitmap mBitmapIn;
37
private Bitmap[] mBitmapsOut;
38
private ImageView mImageView;
39
40
private RenderScript mRS;
41
private Allocation mInAllocation;
42
private Allocation[] mOutAllocations;
43
private ScriptC_saturation mScript;
44
45
@Override
46
protected void onCreate(Bundle savedInstanceState) {
47
super.onCreate(savedInstanceState);
48
49
setContentView(R.layout.main_layout);
50
51
/*
52
* Initialize UI
53
*/
54
mBitmapIn = loadBitmap(R.drawable.data);
55
mBitmapsOut = new Bitmap[NUM_BITMAPS];
56
for (int i = 0; i < NUM_BITMAPS; ++i) {
57
mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
58
mBitmapIn.getHeight(), mBitmapIn.getConfig());
59
}
60
61
mImageView = (ImageView) findViewById(R.id.imageView);
62
mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
63
mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
64
65
SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
66
seekbar.setProgress(50);
67
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
68
public void onProgressChanged(SeekBar seekBar, int progress,
69
boolean fromUser) {
70
float max = 2.0f;
71
float min = 0.0f;
72
float f = (float) ((max - min) * (progress / 100.0) + min);
73
updateImage(f);
74
}
75
76
@Override
77
public void onStartTrackingTouch(SeekBar seekBar) {
78
}
79
80
@Override
81
public void onStopTrackingTouch(SeekBar seekBar) {
82
}
83
});
84
85
/*
86
* Create renderScript
87
*/
88
createScript();
89
90
/*
91
* Invoke renderScript kernel and update imageView
92
*/
93
updateImage(1.0f);
94
}
95
96
/*
97
* Initialize RenderScript
98
* In the sample, it creates RenderScript kernel that performs saturation manipulation.
99
*/
100
private void createScript() {
101
//Initialize RS
102
mRS = RenderScript.create(this);
103
104
//Allocate buffers
105
mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
106
mOutAllocations = new Allocation[NUM_BITMAPS];
107
for (int i = 0; i < NUM_BITMAPS; ++i) {
108
mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
109
}
110
111
//Load script
112
mScript = new ScriptC_saturation(mRS);
113
}
114
115
/*
116
* In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
117
* After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
118
* Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
119
*/
120
private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
121
Boolean issued = false;
122
123
protected Integer doInBackground(Float... values) {
124
int index = -1;
125
if (isCancelled() == false) {
126
issued = true;
127
index = mCurrentBitmap;
128
129
/*
130
* Set global variable in RS
131
*/
132
mScript.set_saturationValue(values[0]);
133
134
/*
135
* Invoke saturation filter kernel
136
*/
137
mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
138
139
/*
140
* Copy to bitmap and invalidate image view
141
*/
142
mOutAllocations[index].copyTo(mBitmapsOut[index]);
143
mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
144
}
145
return index;
146
}
147
148
void updateView(Integer result) {
149
if (result != -1) {
150
// Request UI update
151
mImageView.setImageBitmap(mBitmapsOut[result]);
152
mImageView.invalidate();
153
}
154
}
155
156
protected void onPostExecute(Integer result) {
157
updateView(result);
158
}
159
160
protected void onCancelled(Integer result) {
161
if (issued) {
162
updateView(result);
163
}
164
}
165
}
166
167
RenderScriptTask currentTask = null;
168
169
/*
170
Invoke AsynchTask and cancel previous task.
171
When AsyncTasks are piled up (typically in slow device with heavy kernel),
172
Only the latest (and already started) task invokes RenderScript operation.
173
*/
174
private void updateImage(final float f) {
175
if (currentTask != null)
176
currentTask.cancel(false);
177
currentTask = new RenderScriptTask();
178
currentTask.execute(f);
179
}
180
181
/*
182
Helper to load Bitmap from resource
183
*/
184
private Bitmap loadBitmap(int resource) {
185
final BitmapFactory.Options options = new BitmapFactory.Options();
186
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
187
return BitmapFactory.decodeResource(getResources(), resource, options);
188
}
189
190
}