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>