BasicRenderScript / src / com.example.android.basicrenderscript /

MainActivity.java

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
}