Make use of the device camera to take a photo go display as thumbnail a single-photo gallery. Also, support saving the photo
In this lab you will use the device camera to take a photo.
The following figures provide an outline.




We will add two activities:
Modify manifest file: add following snippets.
    <activity
        android:name=".activities.ResidenceCameraActivity"
        android:label="@string/app_name">
        <meta-data android:name="android.support.PARENT_ACTIVITY"
                   android:value=".activities.ResidencePagerActivity"/>
    </activity>
    <activity
        android:name=".activities.ResidenceGalleryActivity"
        android:label="@string/app_name">
        <meta-data android:name="android.support.PARENT_ACTIVITY"
                   android:value=".activities.ResidencePagerActivity"/>
    </activity>
It is necessary to modify the layout file by replacing the legacy Map button with a Camera button and a thumnail placeholder.

Here is the replacement code:
           <!-- Show Map Button -->          
           <LinearLayout
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="40"
             android:orientation="horizontal" >                        
             <ImageButton 
                android:id="@+id/camera_button"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:scaleType="centerInside"
                android:layout_marginTop="16dp"
                android:src="@android:drawable/ic_menu_camera"/>  
              <ImageView 
                android:id="@+id/myrent_imageView"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:scaleType="centerInside"
                android:background="@android:color/darker_gray"
                android:cropToPadding="true"
                android:layout_marginTop="16dp"/>        
            </LinearLayout>
As you can see, the code is located immediately following the Show Map Button comment.
<!--- Camera button and thumbnail placeholder -->
Note that the two new widgets are wrapped in a LinearLayout with horizontal orientation.
Next we add a layout for the Camera activity:
File: /res/layout/residence_photo.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="org.wit.myrent.ResidenceCameraActivity" >
    <ImageView
        android:id="@+id/residenceImage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/takePhoto"
        android:layout_alignLeft="@+id/residenceImage"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic_launcher" />
    <Button
        android:id="@+id/takePhoto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/residenceImage"
        android:layout_alignParentBottom="true"
        android:text="@string/take_photo" />
    <Button
        android:id="@+id/savePhoto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/takePhoto"
        android:layout_alignRight="@+id/residenceImage"
        android:layout_alignTop="@+id/takePhoto"
        android:text="@string/save_photo" />
</RelativeLayout>

The model Residence class requires a new field to represent the photo filename:
public String photo;
private static final String JSON_PHOTO = "photo";  
Initialize the new Photo field in the constructors:
Default:
public Residence()
{
  ...
  photo = "photo";
}
public Residence(JSONObject json) throws JSONException
{
  ...
  photo = json.getString(JSON_PHOTO); 
}  
Add the following statement to the method toJSON:
public JSONObject toJSON() throws JSONException
{
  ...
  json.put(JSON_PHOTO , photo);
}
  We will now add a helper class, CameraHelper.
These methods have been obtained from Android Programming by Hardy & Phillips.
File: org.wit.android.helpers.CameraHelper.java
package org.wit.android.helpers;
import java.util.List;
import org.wit.myrent.models.Residence;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera.Size;
import android.view.Display;
import android.widget.ImageView;
public class CameraHelper
{
  /**
   * Render the photo on the ImageView
   */
  public static void showPhoto(Activity activity, Residence res, ImageView photoView)
  { 
    String path = activity.getFileStreamPath(res.photo).getAbsolutePath();
    BitmapDrawable b = getScaledDrawable(activity, path);
    if (b != null)
      photoView.setImageDrawable(b);
  }
  /**
   * Get a BitmapDrawable from a local file that is scaled down to fit the
   * current Window size.
   */
  @SuppressWarnings("deprecation")
  public static BitmapDrawable getScaledDrawable(Activity a, String path)
  {
    Display display = a.getWindowManager().getDefaultDisplay();
    float destWidth = display.getWidth();
    float destHeight = display.getHeight();
    // read in the dimensions of the image on disk
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);
    float srcWidth = options.outWidth;
    float srcHeight = options.outHeight;
    int inSampleSize = 1;
    if (srcHeight > destHeight || srcWidth > destWidth)
    {
      if (srcWidth > srcHeight)
      {
        inSampleSize = Math.round((float) srcHeight / (float) destHeight);
      }
      else
      {
        inSampleSize = Math.round((float) srcWidth / (float) destWidth);
      }
    }
    options = new BitmapFactory.Options();
    options.inSampleSize = inSampleSize;
    Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    return new BitmapDrawable(a.getResources(), bitmap);
  }
}
  Create a new activity ResidenceCameraActivity in the package org.wit.myrent.activities.
package org.wit.myrent.activities;
import org.wit.myrent.R;
import android.app.Activity;
import android.os.Bundle;
public class ResidenceCameraActivity extends Activity
{
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.residence_photo);
  }
}
Introduce and wire up the Up button so that it behaves similarly to the back button. We can do this by invoking Activity.onBackPressed
getActionBar().setDisplayHomeAsUpEnabled(true);
  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
    case android.R.id.home  : onBackPressed();
                              return true;
    default                 : return super.onOptionsItemSelected(item);
    }
  }
Add an import statement for MenuItem:
import android.view.MenuItem;
There are two buttons in the view: Take Photo and Save Photo.
  private Button    savePhoto;
  private Button    takePhoto;
Import the Button class:
import android.widget.Button;
Add an ImageView field in which the photo will be displayed.
  private ImageView residenceImage;
Import the ImageView class:
import android.widget.ImageView;
Bind the widget instances to their respective layout elements. The following code which should be added to onCreate does this:
    residenceImage  = (ImageView) findViewById(R.id.residenceImage);
    savePhoto       = (Button)findViewById(R.id.savePhoto);
    takePhoto       = (Button)findViewById(R.id.takePhoto);
Set the default state of the save photo button to disabled. We will only enable this once a photo has been taken.
    savePhoto.setEnabled(false);
Implement an OnClickListener interface:
public class ResidenceCameraActivity extends Activity implements OnClickListener
Import the listener interface:
import android.view.View.OnClickListener;
Add the listener method skeleton:
  @Override
  public void onClick(View v)
  {
    // TODO Auto-generated method stub
  }
Register listeners to respond to clicking the buttons:
    savePhoto.setOnClickListener(this);
    takePhoto.setOnClickListener(this);
In onClick method respond to clicking the buttons. For convenience we will locate most of the necessary code, as shown below, in two private methods:
  @Override
  public void onClick(View v)
  {
    switch(v.getId())
    {
    case R.id.takePhoto     : onTakePhotoClicked(v);                              
                              break;
    case R.id.savePhoto     : onPictureTaken(residencePhoto);    
                              break;                   
    }
  }
The approach we adopt is to use an implicit Intent to make use of the device camera (which we assume is available). Here is the implementation of onTakePhotoClicked:
  public void onTakePhotoClicked(View v)
  {
    Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(cameraIntent,CAMERA_RESULT);
    savePhoto.setEnabled(true);
  }
This requires an import statement for the Intent class:
import android.content.Intent;
Also necessary is a definition of the constant CAMERA_RESULT. The value 5 has been chosen arbitrarily.
  private static  final int     CAMERA_RESULT = 5;
Next we define the method onPictureTaken. We are chosing the png format as this is the only format acceptable to the helper method writeBitMap.
private void onPictureTaken(Bitmap data)
  {
    String filename = UUID.randomUUID().toString() + ".png";
    if(writeBitmap(this, filename, data) == true)
    {
      Intent intent = new Intent();
      intent.putExtra(EXTRA_PHOTO_FILENAME, filename);
      setResult(Activity.RESULT_OK, intent);      
    }
    else
    {
      setResult(Activity.RESULT_CANCELED);
    }
    finish();
  }
This requires these import statements:
import android.graphics.Bitmap;
import java.util.UUID;
import static org.wit.android.helpers.FileIOHelper.writeBitmap;
We must also define the string EXTRA_PHOTO_FILENAME. Note that the arguments in Intent.putExtra comprise key-value pairs, the first argument always being a String.
  public static   final String  EXTRA_PHOTO_FILENAME = "org.wit.myrent.photo.filename";
A further instance variable is required to hold the picture in bitmap form:
  private Bitmap    residencePhoto;
We retrieve the photo taken by the device camera in the onActivityResult method:
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data)
  {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode)
    {
    case ResidenceCameraActivity.CAMERA_RESULT    : processImage(data);
                                                    break;                                               
    }
  }
For convenience, we have located the code in a private method, processImage:
  private void processImage(Intent data)
  {
    residencePhoto = (Bitmap) data.getExtras().get("data");
    if(residencePhoto == null)
    {
      Toast.makeText(this, "Attempt to take photo did not succeed", Toast.LENGTH_SHORT).show();
    }
    residenceImage.setImageBitmap(residencePhoto);
  }
Import the Toast class:
import android.widget.Toast;
  Integrate camera module into ResidenceFragment.
Add imports:
import static org.wit.android.helpers.CameraHelper.showPhoto;
import android.widget.ImageView;
Add a static constant to represent the photo:
private static final int REQUEST_PHOTO = 0;
Create instance variables:
private ImageView cameraButton;
private ImageView photoView;
Invoke the showPhoto method in onStart.
showPhoto(getActivity(), residence, photoView);
Here, for reference, is the refactored onStart method:
  @Override
  public void onStart()
  {
    super.onStart();
    //render google map and set map change listener
    renderMap(MapHelper.latLng(getActivity(), residence.geolocation));
    gmap.setOnCameraChangeListener(this);
    //display thumbnail photo
    showPhoto(getActivity(), residence, photoView);    
  }
In addListeners:
    cameraButton  = (ImageView) v.findViewById(R.id.camera_button);
    photoView     = (ImageView) v.findViewById(R.id.myrent_imageView);
    cameraButton.setOnClickListener(this);
In onActivityResult introduce code to capture the photo filename, save this to the model and invoke a method to display the photo in a thumbnail:
    case REQUEST_PHOTO:
      String filename = data.getStringExtra(ResidenceCameraActivity.EXTRA_PHOTO_FILENAME);
      if (filename != null)
      {
        residence.photo = filename;
        showPhoto(getActivity(), residence, photoView );
      }
      break;
Respond to camera button click: add this code to onClick:
    case R.id.camera_button:           Intent ic = new Intent(getActivity(), ResidenceCameraActivity.class);
                                       startActivityForResult(ic, REQUEST_PHOTO);
                                       break;
  Add a new layout file for the gallery:
File: res/layout/residence_gallery.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/FrameLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="org.wit.myrent.ResidenceCameraActivity" >
    <ImageView
        android:id="@+id/residenceGalleryImage"
        android:layout_width="match_parent"
        android:layout_height="426dp"
        android:src="@drawable/ic_launcher" />
</FrameLayout>
Here is the activity code:
File: org.wit.myrent.activities/ResidenceGalleryActivity.java
package org.wit.myrent.activities;
import java.util.UUID;
import org.wit.myrent.R;
import org.wit.myrent.app.MyRentApp;
import org.wit.myrent.models.Portfolio;
import org.wit.myrent.models.Residence;
import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.ImageView;
import static org.wit.android.helpers.CameraHelper.showPhoto;
public class ResidenceGalleryActivity extends Activity
{
  public static   final String  EXTRA_PHOTO_FILENAME = "org.wit.myrent.photo.filename";
  private ImageView photoView;
  @Override
  protected void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.residence_gallery);
    photoView = (ImageView) findViewById(R.id.residenceGalleryImage);
    getActionBar().setDisplayHomeAsUpEnabled(true);
    showPicture();
  }
  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
    case android.R.id.home  : onBackPressed();
                              return true;
    default                 : return super.onOptionsItemSelected(item);
    }
  }
  private void showPicture()
  {
    UUID resId = (UUID)getIntent().getSerializableExtra(ResidenceFragment.EXTRA_RESIDENCE_ID);
    MyRentApp app = (MyRentApp) getApplication();
    Portfolio portfolio = app.portfolio;
    Residence residence = portfolio.getResidence(resId);
    showPhoto(this, residence,  photoView);
  }
}
The gallery activity is started by a long-press of the thumbnail in the residence fragment. Here are the necessary changes to ResidenceFragment:
public class ResidenceFragment extends SupportMapFragment implements  TextWatcher, 
                                                                      OnCheckedChangeListener,
                                                                      OnClickListener, 
                                                                      DatePickerDialog.OnDateSetListener, 
                                                                      GoogleMap.OnMarkerDragListener,
                                                                      GoogleMap.OnCameraChangeListener,
                                                                      View.OnLongClickListener
    photoView.setOnLongClickListener(this);
  /* ====================== longpress thumbnail ===================================*/
  /*
   * Long press the bitmap image to view photo in single-photo gallery
   */
  @Override
  public boolean onLongClick(View v)
  {
    Intent i = new Intent(getActivity(), ResidenceGalleryActivity.class);
    i.putExtra(EXTRA_RESIDENCE_ID, residence.id);
    startActivity(i);
    return true;
  }
  Test the app as follows: