CarouselView.java revision c0bb8af58ae15674178f2db240283719918c6f28
1/*
2 * Copyright (C) 2010 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
17package com.android.ex.carousel;
18
19import com.android.ex.carousel.CarouselRS.CarouselCallback;
20
21import android.content.Context;
22import android.content.res.Resources;
23import android.content.res.TypedArray;
24import android.graphics.Bitmap;
25import android.graphics.Rect;
26import android.graphics.Bitmap.Config;
27import android.renderscript.FileA3D;
28import android.renderscript.Mesh;
29import android.renderscript.RSSurfaceView;
30import android.renderscript.RenderScriptGL;
31import android.util.AttributeSet;
32import android.util.Log;
33import android.view.MotionEvent;
34import android.view.SurfaceHolder;
35
36public abstract class CarouselView extends RSSurfaceView {
37    private static final boolean USE_DEPTH_BUFFER = true;
38    private final int DEFAULT_SLOT_COUNT = 10;
39    private final Bitmap DEFAULT_BITMAP = Bitmap.createBitmap(1, 1, Config.RGB_565);
40    private final float DEFAULT_RADIUS = 20.0f;
41    private final float DEFAULT_SWAY_SENSITIVITY = 0.0f;
42    private final float DEFAULT_FRICTION_COEFFICIENT = 10.0f;
43    private final float DEFAULT_DRAG_FACTOR = 0.25f;
44    private static final String TAG = "CarouselView";
45    private CarouselRS mRenderScript;
46    private RenderScriptGL mRS;
47    private Context mContext;
48    private boolean mTracking;
49
50    // These are meant to shadow the state of the renderer in case the surface changes.
51    private Bitmap mDefaultBitmap;
52    private Bitmap mLoadingBitmap;
53    private Bitmap mBackgroundBitmap;
54    private Mesh mDefaultGeometry;
55    private Mesh mLoadingGeometry;
56    private int mCardCount = 0;
57    private int mVisibleSlots = 0;
58    private float mStartAngle;
59    private float mRadius = DEFAULT_RADIUS;
60    private float mCardRotation = 0.0f;
61    private float mSwaySensitivity = DEFAULT_SWAY_SENSITIVITY;
62    private float mFrictionCoefficient = DEFAULT_FRICTION_COEFFICIENT;
63    private float mDragFactor = DEFAULT_DRAG_FACTOR;
64    private int mSlotCount = DEFAULT_SLOT_COUNT;
65    private float mEye[] = { 20.6829f, 2.77081f, 16.7314f };
66    private float mAt[] = { 14.7255f, -3.40001f, -1.30184f };
67    private float mUp[] = { 0.0f, 1.0f, 0.0f };
68
69    public static class Info {
70        public Info(int _resId) { resId = _resId; }
71        public int resId; // resource for renderscript resource (e.g. R.raw.carousel)
72    }
73
74    public abstract Info getRenderScriptInfo();
75
76    public CarouselView(Context context) {
77        this(context, null);
78    }
79
80    /**
81     * Constructor used when this widget is created from a layout file.
82     */
83    public CarouselView(Context context, AttributeSet attrs) {
84        super(context, attrs);
85        mContext = context;
86        boolean useDepthBuffer = true;
87        ensureRenderScript();
88        // TODO: add parameters to layout
89    }
90
91    private void ensureRenderScript() {
92        mRS = createRenderScript(USE_DEPTH_BUFFER);
93        mRenderScript = new CarouselRS();
94        mRenderScript.init(mRS, getResources(), getRenderScriptInfo().resId);
95    }
96
97    @Override
98    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
99        super.surfaceChanged(holder, format, w, h);
100        //mRS.contextSetSurface(w, h, holder.getSurface());
101        mRenderScript.init(mRS, getResources(), getRenderScriptInfo().resId);
102        setSlotCount(mSlotCount);
103        createCards(mCardCount);
104        setVisibleSlots(mVisibleSlots);
105        setCallback(mCarouselCallback);
106        setDefaultBitmap(mDefaultBitmap);
107        setLoadingBitmap(mLoadingBitmap);
108        setDefaultGeometry(mDefaultGeometry);
109        setLoadingGeometry(mLoadingGeometry);
110        setBackgroundBitmap(mBackgroundBitmap);
111        setStartAngle(mStartAngle);
112        setRadius(mRadius);
113        setCardRotation(mCardRotation);
114        setSwaySensitivity(mSwaySensitivity);
115        setFrictionCoefficient(mFrictionCoefficient);
116        setDragFactor(mDragFactor);
117        setLookAt(mEye, mAt, mUp);
118    }
119
120    /**
121     * Loads geometry from a resource id.
122     *
123     * @param resId
124     * @return the loaded mesh or null if it cannot be loaded
125     */
126    public Mesh loadGeometry(int resId) {
127        Resources res = mContext.getResources();
128        FileA3D model = FileA3D.createFromResource(mRS, res, resId);
129        FileA3D.IndexEntry entry = model.getIndexEntry(0);
130        if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
131            return null;
132        }
133        return (Mesh) entry.getObject();
134    }
135
136    /**
137     * Load A3D file from resource.  If resId == 0, will clear geometry for this item.
138     * @param n
139     * @param resId
140     */
141    public void setGeometryForItem(int n, Mesh mesh) {
142        if (mRenderScript != null) {
143            mRenderScript.setGeometry(n, mesh);
144        }
145    }
146
147    public void setSlotCount(int n) {
148        mSlotCount = n;
149        if (mRenderScript != null) {
150            mRenderScript.setSlotCount(n);
151        }
152    }
153
154    public void setVisibleSlots(int n) {
155        mVisibleSlots = n;
156        if (mRenderScript != null) {
157            mRenderScript.setVisibleSlots(n);
158        }
159    }
160
161    public void createCards(int n) {
162        mCardCount = n;
163        if (mRenderScript != null) {
164            mRenderScript.createCards(n);
165        }
166    }
167
168    public void setTextureForItem(int n, Bitmap bitmap) {
169        // Also check against mRS, to handle the case where the result is being delivered by a
170        // background thread but the sender no longer exists.
171        if (mRenderScript != null && mRS != null) {
172            Log.v(TAG, "setTextureForItem(" + n + ")");
173            mRenderScript.setTexture(n, bitmap);
174            Log.v(TAG, "done");
175        }
176    }
177
178    public void setDefaultBitmap(Bitmap bitmap) {
179        mDefaultBitmap = bitmap;
180        if (mRenderScript != null) {
181            mRenderScript.setDefaultBitmap(bitmap);
182        }
183    }
184
185    public void setLoadingBitmap(Bitmap bitmap) {
186        mLoadingBitmap = bitmap;
187        if (mRenderScript != null) {
188            mRenderScript.setLoadingBitmap(bitmap);
189        }
190    }
191
192    public void setBackgroundBitmap(Bitmap bitmap) {
193        mBackgroundBitmap = bitmap;
194        if (mRenderScript != null) {
195            mRenderScript.setBackgroundTexture(bitmap);
196        }
197    }
198
199    public void setDefaultGeometry(Mesh mesh) {
200        mDefaultGeometry = mesh;
201        if (mRenderScript != null) {
202            mRenderScript.setDefaultGeometry(mesh);
203        }
204    }
205
206    public void setLoadingGeometry(Mesh mesh) {
207        mLoadingGeometry = mesh;
208        if (mRenderScript != null) {
209            mRenderScript.setLoadingGeometry(mesh);
210        }
211    }
212
213    public void setCallback(CarouselCallback callback)
214    {
215        mCarouselCallback = callback;
216        if (mRenderScript != null) {
217            mRenderScript.setCallback(callback);
218        }
219    }
220
221    public void setStartAngle(float angle)
222    {
223        mStartAngle = angle;
224        if (mRenderScript != null) {
225            mRenderScript.setStartAngle(angle);
226        }
227    }
228
229    public void setRadius(float radius) {
230        mRadius = radius;
231        if (mRenderScript != null) {
232            mRenderScript.setRadius(radius);
233        }
234    }
235
236    public void setCardRotation(float cardRotation) {
237        mCardRotation = cardRotation;
238        if (mRenderScript != null) {
239            mRenderScript.setCardRotation(cardRotation);
240        }
241    }
242
243    public void setSwaySensitivity(float swaySensitivity) {
244        mSwaySensitivity = swaySensitivity;
245        if (mRenderScript != null) {
246            mRenderScript.setSwaySensitivity(swaySensitivity);
247        }
248    }
249
250    public void setFrictionCoefficient(float frictionCoefficient) {
251        mFrictionCoefficient = frictionCoefficient;
252        if (mRenderScript != null) {
253            mRenderScript.setFrictionCoefficient(frictionCoefficient);
254        }
255    }
256
257    public void setDragFactor(float dragFactor) {
258        mDragFactor = dragFactor;
259        if (mRenderScript != null) {
260            mRenderScript.setDragFactor(dragFactor);
261        }
262    }
263
264    public void setLookAt(float[] eye, float[] at, float[] up) {
265        mEye = eye;
266        mAt = at;
267        mUp = up;
268        if (mRenderScript != null) {
269            mRenderScript.setLookAt(eye, at, up);
270        }
271    }
272
273    @Override
274    protected void onDetachedFromWindow() {
275        super.onDetachedFromWindow();
276        if(mRS != null) {
277            mRS = null;
278            destroyRenderScript();
279        }
280    }
281
282    @Override
283    protected void onAttachedToWindow() {
284        super.onAttachedToWindow();
285        ensureRenderScript();
286    }
287
288    @Override
289    public boolean onTouchEvent(MotionEvent event) {
290        final int action = event.getAction();
291        final float x = event.getX();
292        final float y = event.getY();
293
294        if (mRenderScript == null) {
295            return true;
296        }
297
298        switch (action) {
299            case MotionEvent.ACTION_DOWN:
300                mTracking = true;
301                mRenderScript.doStart(x, y);
302                break;
303
304            case MotionEvent.ACTION_MOVE:
305                if (mTracking) {
306                    mRenderScript.doMotion(x, y);
307                }
308                break;
309
310            case MotionEvent.ACTION_UP:
311                mRenderScript.doStop(x, y);
312                mTracking = false;
313                break;
314        }
315
316        return true;
317    }
318
319    private final CarouselCallback DEBUG_CALLBACK = new CarouselCallback() {
320        public void onAnimationStarted() {
321            Log.v(TAG, "onAnimationStarted()");
322        }
323
324        public void onAnimationFinished() {
325            Log.v(TAG, "onAnimationFinished()");
326        }
327
328        public void onCardSelected(int n) {
329            Log.v(TAG, "onCardSelected(" + n + ")");
330        }
331
332        public void onRequestGeometry(int n) {
333            Log.v(TAG, "onRequestGeometry(" + n + ")");
334        }
335
336        public void onInvalidateGeometry(int n) {
337            Log.v(TAG, "onInvalidateGeometry(" + n + ")");
338        }
339
340        public void onRequestTexture(final int n) {
341            Log.v(TAG, "onRequestTexture(" + n + ")");
342        }
343
344        public void onInvalidateTexture(int n) {
345            Log.v(TAG, "onInvalidateTexture(" + n + ")");
346        }
347
348    };
349
350    private CarouselCallback mCarouselCallback = DEBUG_CALLBACK;
351}
352