Add prebuilt browseable samples as static files.

Change-Id: Ifb5382223343400882834d2dd9c182c3df602e34
This commit is contained in:
Dirk Dougherty
2013-10-29 20:56:17 -07:00
parent 7165109e6d
commit 4b737b695e
840 changed files with 35304 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.basicmultitouch;
import android.app.Activity;
import android.os.Bundle;
/**
* This is an example of keeping track of individual touches across multiple
* {@link android.view.MotionEvent}s.
* <p>
* This is illustrated by a View ({@link TouchDisplayView}) that responds to
* touch events and draws coloured circles for each pointer, stores the last
* positions of this pointer and draws them. This example shows the relationship
* between MotionEvent indices, pointer identifiers and actions.
*
* @see android.view.MotionEvent
*/
public class MainActivity extends Activity {
TouchDisplayView mView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_mainactivity);
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.basicmultitouch;
/**
* Helper class for crating pools of objects. An example use looks like this:
* <pre>
* public class MyPooledClass {
*
* private static final SynchronizedPool<MyPooledClass> sPool =
* new SynchronizedPool<MyPooledClass>(10);
*
* public static MyPooledClass obtain() {
* MyPooledClass instance = sPool.acquire();
* return (instance != null) ? instance : new MyPooledClass();
* }
*
* public void recycle() {
* // Clear state if needed.
* sPool.release(this);
* }
*
* . . .
* }
* </pre>
*
* @hide
*/
public final class Pools {
/**
* Interface for managing a pool of objects.
*
* @param <T> The pooled type.
*/
public static interface Pool<T> {
/**
* @return An instance from the pool if such, null otherwise.
*/
public T acquire();
/**
* Release an instance to the pool.
*
* @param instance The instance to release.
* @return Whether the instance was put in the pool.
*
* @throws IllegalStateException If the instance is already in the pool.
*/
public boolean release(T instance);
}
private Pools() {
/* do nothing - hiding constructor */
}
/**
* Simple (non-synchronized) pool of objects.
*
* @param <T> The pooled type.
*/
public static class SimplePool<T> implements Pool<T> {
private final Object[] mPool;
private int mPoolSize;
/**
* Creates a new instance.
*
* @param maxPoolSize The max pool size.
*
* @throws IllegalArgumentException If the max pool size is less than zero.
*/
public SimplePool(int maxPoolSize) {
if (maxPoolSize <= 0) {
throw new IllegalArgumentException("The max pool size must be > 0");
}
mPool = new Object[maxPoolSize];
}
@Override
@SuppressWarnings("unchecked")
public T acquire() {
if (mPoolSize > 0) {
final int lastPooledIndex = mPoolSize - 1;
T instance = (T) mPool[lastPooledIndex];
mPool[lastPooledIndex] = null;
mPoolSize--;
return instance;
}
return null;
}
@Override
public boolean release(T instance) {
if (isInPool(instance)) {
throw new IllegalStateException("Already in the pool!");
}
if (mPoolSize < mPool.length) {
mPool[mPoolSize] = instance;
mPoolSize++;
return true;
}
return false;
}
private boolean isInPool(T instance) {
for (int i = 0; i < mPoolSize; i++) {
if (mPool[i] == instance) {
return true;
}
}
return false;
}
}
/**
* Synchronized) pool of objects.
*
* @param <T> The pooled type.
*/
public static class SynchronizedPool<T> extends SimplePool<T> {
private final Object mLock = new Object();
/**
* Creates a new instance.
*
* @param maxPoolSize The max pool size.
*
* @throws IllegalArgumentException If the max pool size is less than zero.
*/
public SynchronizedPool(int maxPoolSize) {
super(maxPoolSize);
}
@Override
public T acquire() {
synchronized (mLock) {
return super.acquire();
}
}
@Override
public boolean release(T element) {
synchronized (mLock) {
return super.release(element);
}
}
}
}

View File

@@ -0,0 +1,401 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.basicmultitouch;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import com.example.android.basicmultitouch.Pools.SimplePool;
/**
* View that shows touch events and their history. This view demonstrates the
* use of {@link #onTouchEvent(android.view.MotionEvent)} and {@link android.view.MotionEvent}s to keep
* track of touch pointers across events.
*/
public class TouchDisplayView extends View {
// Hold data for active touch pointer IDs
private SparseArray<TouchHistory> mTouches;
// Is there an active touch?
private boolean mHasTouch = false;
/**
* Holds data related to a touch pointer, including its current position,
* pressure and historical positions. Objects are allocated through an
* object pool using {@link #obtain()} and {@link #recycle()} to reuse
* existing objects.
*/
static final class TouchHistory {
// number of historical points to store
public static final int HISTORY_COUNT = 20;
public float x;
public float y;
public float pressure = 0f;
public String label = null;
// current position in history array
public int historyIndex = 0;
public int historyCount = 0;
// arrray of pointer position history
public PointF[] history = new PointF[HISTORY_COUNT];
private static final int MAX_POOL_SIZE = 10;
private static final SimplePool<TouchHistory> sPool =
new SimplePool<TouchHistory>(MAX_POOL_SIZE);
public static TouchHistory obtain(float x, float y, float pressure) {
TouchHistory data = sPool.acquire();
if (data == null) {
data = new TouchHistory();
}
data.setTouch(x, y, pressure);
return data;
}
public TouchHistory() {
// initialise history array
for (int i = 0; i < HISTORY_COUNT; i++) {
history[i] = new PointF();
}
}
public void setTouch(float x, float y, float pressure) {
this.x = x;
this.y = y;
this.pressure = pressure;
}
public void recycle() {
this.historyIndex = 0;
this.historyCount = 0;
sPool.release(this);
}
/**
* Add a point to its history. Overwrites oldest point if the maximum
* number of historical points is already stored.
*
* @param point
*/
public void addHistory(float x, float y) {
PointF p = history[historyIndex];
p.x = x;
p.y = y;
historyIndex = (historyIndex + 1) % history.length;
if (historyCount < HISTORY_COUNT) {
historyCount++;
}
}
}
public TouchDisplayView(Context context, AttributeSet attrs) {
super(context, attrs);
// SparseArray for touch events, indexed by touch id
mTouches = new SparseArray<TouchHistory>(10);
initialisePaint();
}
// BEGIN_INCLUDE(onTouchEvent)
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getAction();
/*
* Switch on the action. The action is extracted from the event by
* applying the MotionEvent.ACTION_MASK. Alternatively a call to
* event.getActionMasked() would yield in the action as well.
*/
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
// first pressed gesture has started
/*
* Only one touch event is stored in the MotionEvent. Extract
* the pointer identifier of this touch from the first index
* within the MotionEvent object.
*/
int id = event.getPointerId(0);
TouchHistory data = TouchHistory.obtain(event.getX(0), event.getY(0),
event.getPressure(0));
data.label = "id: " + 0;
/*
* Store the data under its pointer identifier. The pointer
* number stays consistent for the duration of a gesture,
* accounting for other pointers going up or down.
*/
mTouches.put(id, data);
mHasTouch = true;
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
/*
* A non-primary pointer has gone down, after an event for the
* primary pointer (ACTION_DOWN) has already been received.
*/
/*
* The MotionEvent object contains multiple pointers. Need to
* extract the index at which the data for this particular event
* is stored.
*/
int index = event.getActionIndex();
int id = event.getPointerId(index);
TouchHistory data = TouchHistory.obtain(event.getX(index), event.getY(index),
event.getPressure(index));
data.label = "id: " + id;
/*
* Store the data under its pointer identifier. The index of
* this pointer can change over multiple events, but this
* pointer is always identified by the same identifier for this
* active gesture.
*/
mTouches.put(id, data);
break;
}
case MotionEvent.ACTION_UP: {
/*
* Final pointer has gone up and has ended the last pressed
* gesture.
*/
/*
* Extract the pointer identifier for the only event stored in
* the MotionEvent object and remove it from the list of active
* touches.
*/
int id = event.getPointerId(0);
TouchHistory data = mTouches.get(id);
mTouches.remove(id);
data.recycle();
mHasTouch = false;
break;
}
case MotionEvent.ACTION_POINTER_UP: {
/*
* A non-primary pointer has gone up and other pointers are
* still active.
*/
/*
* The MotionEvent object contains multiple pointers. Need to
* extract the index at which the data for this particular event
* is stored.
*/
int index = event.getActionIndex();
int id = event.getPointerId(index);
TouchHistory data = mTouches.get(id);
mTouches.remove(id);
data.recycle();
break;
}
case MotionEvent.ACTION_MOVE: {
/*
* A change event happened during a pressed gesture. (Between
* ACTION_DOWN and ACTION_UP or ACTION_POINTER_DOWN and
* ACTION_POINTER_UP)
*/
/*
* Loop through all active pointers contained within this event.
* Data for each pointer is stored in a MotionEvent at an index
* (starting from 0 up to the number of active pointers). This
* loop goes through each of these active pointers, extracts its
* data (position and pressure) and updates its stored data. A
* pointer is identified by its pointer number which stays
* constant across touch events as long as it remains active.
* This identifier is used to keep track of a pointer across
* events.
*/
for (int index = 0; index < event.getPointerCount(); index++) {
// get pointer id for data stored at this index
int id = event.getPointerId(index);
// get the data stored externally about this pointer.
TouchHistory data = mTouches.get(id);
// add previous position to history and add new values
data.addHistory(data.x, data.y);
data.setTouch(event.getX(index), event.getY(index),
event.getPressure(index));
}
break;
}
}
// trigger redraw on UI thread
this.postInvalidate();
return true;
}
// END_INCLUDE(onTouchEvent)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Canvas background color depends on whether there is an active touch
if (mHasTouch) {
canvas.drawColor(BACKGROUND_ACTIVE);
} else {
// draw inactive border
canvas.drawRect(mBorderWidth, mBorderWidth, getWidth() - mBorderWidth, getHeight()
- mBorderWidth, mBorderPaint);
}
// loop through all active touches and draw them
for (int i = 0; i < mTouches.size(); i++) {
// get the pointer id and associated data for this index
int id = mTouches.keyAt(i);
TouchHistory data = mTouches.valueAt(i);
// draw the data and its history to the canvas
drawCircle(canvas, id, data);
}
}
/*
* Below are only helper methods and variables required for drawing.
*/
// radius of active touch circle in dp
private static final float CIRCLE_RADIUS_DP = 75f;
// radius of historical circle in dp
private static final float CIRCLE_HISTORICAL_RADIUS_DP = 7f;
// calculated radiuses in px
private float mCircleRadius;
private float mCircleHistoricalRadius;
private Paint mCirclePaint = new Paint();
private Paint mTextPaint = new Paint();
private static final int BACKGROUND_ACTIVE = Color.WHITE;
// inactive border
private static final float INACTIVE_BORDER_DP = 15f;
private static final int INACTIVE_BORDER_COLOR = 0xFFffd060;
private Paint mBorderPaint = new Paint();
private float mBorderWidth;
public final int[] COLORS = {
0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444,
0xFF0099CC, 0xFF9933CC, 0xFF669900, 0xFFFF8800, 0xFFCC0000
};
/**
* Sets up the required {@link android.graphics.Paint} objects for the screen density of this
* device.
*/
private void initialisePaint() {
// Calculate radiuses in px from dp based on screen density
float density = getResources().getDisplayMetrics().density;
mCircleRadius = CIRCLE_RADIUS_DP * density;
mCircleHistoricalRadius = CIRCLE_HISTORICAL_RADIUS_DP * density;
// Setup text paint for circle label
mTextPaint.setTextSize(27f);
mTextPaint.setColor(Color.BLACK);
// Setup paint for inactive border
mBorderWidth = INACTIVE_BORDER_DP * density;
mBorderPaint.setStrokeWidth(mBorderWidth);
mBorderPaint.setColor(INACTIVE_BORDER_COLOR);
mBorderPaint.setStyle(Paint.Style.STROKE);
}
/**
* Draws the data encapsulated by a {@link TouchDisplayView.TouchHistory} object to a canvas.
* A large circle indicates the current position held by the
* {@link TouchDisplayView.TouchHistory} object, while a smaller circle is drawn for each
* entry in its history. The size of the large circle is scaled depending on
* its pressure, clamped to a maximum of <code>1.0</code>.
*
* @param canvas
* @param id
* @param data
*/
protected void drawCircle(Canvas canvas, int id, TouchHistory data) {
// select the color based on the id
int color = COLORS[id % COLORS.length];
mCirclePaint.setColor(color);
/*
* Draw the circle, size scaled to its pressure. Pressure is clamped to
* 1.0 max to ensure proper drawing. (Reported pressure values can
* exceed 1.0, depending on the calibration of the touch screen).
*/
float pressure = Math.min(data.pressure, 1f);
float radius = pressure * mCircleRadius;
canvas.drawCircle(data.x, (data.y) - (radius / 2f), radius,
mCirclePaint);
// draw all historical points with a lower alpha value
mCirclePaint.setAlpha(125);
for (int j = 0; j < data.history.length && j < data.historyCount; j++) {
PointF p = data.history[j];
canvas.drawCircle(p.x, p.y, mCircleHistoricalRadius, mCirclePaint);
}
// draw its label next to the main circle
canvas.drawText(data.label, data.x + radius, data.y
- radius, mTextPaint);
}
}