Ch13 Listings
satya - Saturday, June 13, 2009 10:54:19 AM
Listing 13-1. The 1.5 SDK Renderer Interface
public static interface GLSurfaceView.Renderer
{
void onDrawFrame(GL10 gl);
void onSuraceChanged(GL10 gl, int width, int height);
void onSurfaceCreated(GL10 gl, EGLConfig config);
}
satya - Saturday, June 13, 2009 10:56:04 AM
Listing 13-2. AbstractRenderer Source Code
//filename: AbstractRenderer.java
public abstract class AbstractRenderer
implements GLSurfaceView.Renderer
{
public int[] getConfigSpec() {
int[] configSpec = {
EGL10.EGL_DEPTH_SIZE, 0,
EGL10.EGL_NONE
};
return configSpec;
}
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(.5f, .5f, .5f, 1);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
float ratio = (float) w / h;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 gl)
{
gl.glDisable(GL10.GL_DITHER);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
draw(gl);
}
protected abstract void draw(GL10 gl);
}
satya - Saturday, June 13, 2009 10:59:05 AM
Listing 13-3. SimpleTriangleRenderer Source Code
//filename: SimpleTriangleRenderer.java
public class SimpleTriangleRenderer extends AbstractRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 3;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
public SimpleTriangleRenderer(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-0.5f, -0.5f, 0, // (x1,y1,z1)
0.5f, -0.5f, 0,
0.0f, 0.5f, 0
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2};
for (int i=0;i<3;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
//overridden method
protected void draw(GL10 gl)
{
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, VERTS,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, June 13, 2009 11:00:31 AM
Listing 13-4. OpenGL15TestHarnessActivity Source Code
//filename: OpenGL15TestHarnessActivity.java
public class OpenGL15TestHarnessActivity extends Activity
{
private GLSurfaceView mTestHarness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTestHarness = new GLSurfaceView(this);
mTestHarness.setEGLConfigChooser(false);
mTestHarness.setRenderer(new SimpleTriangleRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
}
@Override
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
}
satya - Saturday, June 13, 2009 11:01:37 AM
Listing 13-5. Invoking an Activity
private void invoke15SimpleTriangle()
{
Intent intent = new Intent(this,OpenGL15TestHarnessActivity.class);
startActivity(intent);
}
satya - Saturday, June 13, 2009 11:01:57 AM
Listing 13-6. Specifying an Activity in the AndroidManifest.xml file
<activity android:name=".OpenGL15TestHarnessActivity"
android:label="OpenGL 15 Test Harness"/>
satya - Saturday, June 13, 2009 11:02:48 AM
Listing 13-7. Specifying Continuous-Rendering Mode
//get a GLSurfaceView
GLSurfaceView openGLView;
//Set the mode to continuous draw mode
openGLView.setRenderingMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
satya - Saturday, June 13, 2009 11:03:44 AM
Listing 13-8. AnimatedTriangleActivity Source Code
//filename: AnimatedTriangleActivity.java
public class AnimatedTriangleActivity extends Activity {
private GLSurfaceView mTestHarness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTestHarness = new GLSurfaceView(this);
mTestHarness.setEGLConfigChooser(false);
mTestHarness.setRenderer(new AnimatedSimpleTriangleRenderer(this));
//mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
}
@Override
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
}
satya - Saturday, June 13, 2009 11:05:41 AM
Listing 13-9. AnimatedSimpleTriangleRenderer Source Code
//filename: AnimatedSimpleTriangleRenderer.java
public class AnimatedSimpleTriangleRenderer extends AbstractRenderer
{
private int scale = 1;
//Number of points or vertices we want to use
private final static int VERTS = 3;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
public AnimatedSimpleTriangleRenderer(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-0.5f, -0.5f, 0, // (x1,y1,z1)
0.5f, -0.5f, 0,
0.0f, 0.5f, 0
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2};
for (int i=0;i<3;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
//overridden method
protected void draw(GL10 gl)
{
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
gl.glRotatef(angle, 0, 0, 1.0f);
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, VERTS,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, June 13, 2009 11:11:37 AM
Listing 13-10. Invoking the Animated Activity
private void invoke15SimpleTriangle()
{
Intent intent = new Intent(this,AnimatedTriangleActivity.class);
startActivity(intent);
}
satya - Saturday, June 13, 2009 11:11:59 AM
Listing 13-11. Registering the New Activity in the AndroidManifest.xml File
<activity android:name=".AnimatedTriangleActivity"
android:label="OpenGL Animated Test Harness"/>
satya - Saturday, June 13, 2009 11:15:26 AM
Listing 13-12. AndroidManifest.xml File for a Live-Folder Definition
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ai.android.livefolders"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".SimpleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- LIVE FOLDERS -->
<activity
android:name=".AllContactsLiveFolderCreatorActivity"
android:label="New live folder "
android:icon="@drawable/icon">
<intent-filter>
<action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<provider android:authorities="com.ai.livefolders.contacts"
android:multiprocess="true"
android:name=".MyContactsProvider" />
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
</manifest>
satya - Saturday, June 13, 2009 11:19:53 AM
Listing 13-13. AllContactsLiveFolderCreatorActivity Source Code
public class AllContactsLiveFolderCreatorActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
final String action = intent.getAction();
if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action))
{
setResult(RESULT_OK,
createLiveFolder(MyContactsProvider.CONTACTS_URI,
"Contacts LF",
R.drawable.icon)
);
} else
{
setResult(RESULT_CANCELED);
}
finish();
}
private Intent createLiveFolder(Uri uri, String name, int icon)
{
final Intent intent = new Intent();
intent.setData(uri);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
Intent.ShortcutIconResource.fromContext(this, icon));
intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
LiveFolders.DISPLAY_MODE_LIST);
return intent;
}
}
satya - Saturday, June 13, 2009 11:30:51 AM
Listing 13-14. MyContactsProvider Source Code
public class MyContactsProvider extends ContentProvider {
public static final String AUTHORITY = "com.ai.livefolders.contacts";
//Uri that goes as input to the live-folder creation
public static final Uri CONTACTS_URI = Uri.parse("content://" +
AUTHORITY + "/contacts" );
//To distinguish this URI
private static final int TYPE_MY_URI = 0;
private static final UriMatcher URI_MATCHER;
static{
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI(AUTHORITY, "contacts", TYPE_MY_URI);
}
@Override
public boolean onCreate() {
return true;
}
@Override
public int bulkInsert(Uri arg0, ContentValues[] values) {
return 0; //nothing to insert
}
//Set of columns needed by a live folder
//This is the live-folder contract
private static final String[] CURSOR_COLUMNS = new String[]
{
BaseColumns._ID,
LiveFolders.NAME,
LiveFolders.DESCRIPTION,
LiveFolders.INTENT,
LiveFolders.ICON_PACKAGE,
LiveFolders.ICON_RESOURCE
};
//In case there are no rows
//use this stand-in as an error message
//Notice it has the same set of columns of a live folder
private static final String[] CURSOR_ERROR_COLUMNS = new String[]
{
BaseColumns._ID,
LiveFolders.NAME,
LiveFolders.DESCRIPTION
};
//The error message row
private static final Object[] ERROR_MESSAGE_ROW =
new Object[]
{
-1, //id
"No contacts found", //name
"Check your contacts database" //description
};
//The error cursor to use
private static MatrixCursor sErrorCursor =
new MatrixCursor(CURSOR_ERROR_COLUMNS);
static
{
sErrorCursor.addRow(ERROR_MESSAGE_ROW);
}
//Columns to be retrieved from the contacts database
private static final String[] CONTACTS_COLUMN_NAMES = new String[]
{
People._ID,
People.DISPLAY_NAME,
People.TIMES_CONTACTED,
People.STARRED
};
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
//Figure out the uri and return error if not matching
int type = URI_MATCHER.match(uri);
if(type == UriMatcher.NO_MATCH)
{
return sErrorCursor;
}
Log.i("ss", "query called");
try
{
MatrixCursor mc = loadNewData(this);
mc.setNotificationUri(getContext().getContentResolver(),
Uri.parse("content://contacts/people/"));
MyCursor wmc = new MyCursor(mc,this);
return wmc;
}
catch (Throwable e)
{
return sErrorCursor;
}
}
public static MatrixCursor loadNewData(ContentProvider cp)
{
MatrixCursor mc = new MatrixCursor(CURSOR_COLUMNS);
Cursor allContacts = null;
try
{
allContacts = cp.getContext().getContentResolver().query(
People.CONTENT_URI,
CONTACTS_COLUMN_NAMES,
null, //row filter
null,
People.DISPLAY_NAME); //order by
while(allContacts.moveToNext())
{
String timesContacted = "Times contacted: "+allContacts.getInt(2);
Object[] rowObject = new Object[]
{
allContacts.getLong(0), //id
allContacts.getString(1), //name
timesContacted, //description
Uri.parse("content://contacts/people/"
+allContacts.getLong(0)), //intent
cp.getContext().getPackageName(), //package
R.drawable.icon //icon
};
mc.addRow(rowObject);
}
return mc;
}
finally
{
allContacts.close();
}
}
@Override
public String getType(Uri uri)
{
//indicates the MIME type for a given URI
//targeted for this wrapper provider
//This usually looks like
// "vnd.android.cursor.dir/vnd.google.note"
return People.CONTENT_TYPE;
}
public Uri insert(Uri uri, ContentValues initialValues) {
throw new UnsupportedOperationException(
"no insert as this is just a wrapper");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException(
"no delete as this is just a wrapper");
}
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs)
{
throw new UnsupportedOperationException(
"no update as this is just a wrapper");
}
}
satya - Saturday, June 13, 2009 11:32:11 AM
Listing 13-15. Columns Needed to Fulfill the Live-Folder Contract
private static final String[] CURSOR_COLUMNS = new String[]
{
BaseColumns._ID,
LiveFolders.NAME,
LiveFolders.DESCRIPTION,
LiveFolders.INTENT,
LiveFolders.ICON_PACKAGE,
LiveFolders.ICON_RESOURCE
};
satya - Saturday, June 13, 2009 11:33:44 AM
Listing 13-16. Registering a URI with a Cursor
MatrixCursor mc = loadNewData(this);
mc.setNotificationUri(getContext().getContentResolver(),
Uri.parse("content://contacts/people/"));
satya - Saturday, June 13, 2009 11:34:10 AM
Listing 13-17. Wrapping a Cursor
MatrixCursor mc = loadNewData(this);
mc.setNotificationUri(getContext().getContentResolver(),
Uri.parse("content://contacts/people/"));
MyCursor wmc = new MyCursor(mc,this);
satya - Saturday, June 13, 2009 11:35:03 AM
Listing 13-18. MyCursor Source Code
public class MyCursor extends BetterCursorWrapper
{
private ContentProvider mcp = null;
public MyCursor(MatrixCursor mc, ContentProvider inCp)
{
super(mc);
mcp = inCp;
}
public boolean requery()
{
MatrixCursor mc = MyContactsProvider.loadNewData(mcp);
this.setInternalCursor(mc);
return super.requery();
}
}
satya - Saturday, June 13, 2009 11:36:25 AM
Listing 13-19. BetterCursorWrapper Source Code
public class BetterCursorWrapper implements CrossProcessCursor
{
//Holds the internal cursor to delegate methods to
protected CrossProcessCursor internalCursor;
//Constructor takes a crossprocesscursor as an input
public BetterCursorWrapper(CrossProcessCursor inCursor)
{
this.setInternalCursor(inCursor);
}
//You can reset in one of the derived class's methods
public void setInternalCursor(CrossProcessCursor inCursor)
{
internalCursor = inCursor;
}
//All delegated methods follow
public void fillWindow(int arg0, CursorWindow arg1) {
internalCursor.fillWindow(arg0, arg1);
}
// ..... other delegated methods
}
satya - Saturday, June 13, 2009 11:45:28 AM
Listing 13-20. SimpleActivity Source Code
public class SimpleActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
satya - Saturday, June 13, 2009 11:48:53 AM
Listing 13-21. Simple XML Layout File
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Live Folder Example"
/>
</LinearLayout>