Deleting, editing, and sharing photos in LabActivity

Our second activity, LabActivity, needs to do the following:

All of this functionality relies on standard Android library classes, notably the Intent class. Intents are the means by which activities communicate with each other. An activity receives an intent from its parent (the activity that created it) and may receive intents from its children (activities it created) as they finish. The communicating activities may be in different applications. An intent may contain key-value pairs called extras.

LabActivity declares several public constants that are used by it and CameraActivity. These constants relate to images' metadata and to the extra keys that are used when CameraActivity and LabActivity communicate via intents. LabActivity also has member variables that are used to store the URI and path values, extracted from the extras. The onCreate() method does the work of extracting these values and setting up an image view that shows the PNG file. The implementation is as follows:

public class LabActivity extends Activity {

  public static final String PHOTO_MIME_TYPE = "image/png";

  public static final String EXTRA_PHOTO_URI =
    "com.nummist.secondsight.LabActivity.extra.PHOTO_URI";
  public static final String EXTRA_PHOTO_DATA_PATH =
    "com.nummist.secondsight.LabActivity.extra.PHOTO_DATA_PATH";

  private Uri mUri;
  private String mDataPath;

  @Override
  protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final Intent intent = getIntent();
    mUri = intent.getParcelableExtra(EXTRA_PHOTO_URI);
    mDataPath = intent.getStringExtra(EXTRA_PHOTO_DATA_PATH);

    final ImageView imageView = new ImageView(this);
    imageView.setImageURI(mUri);

    setContentView(imageView);
  }

The menu logic is simpler in LabActivity than in CameraActivity. All the menu actions of LabActivity result in a dialog or chooser being shown, and since a dialog or chooser blocks the rest of the user interface, we do not have to worry about blocking conflicting input ourselves. We just load the menu's resource file in onCreateOptionsMenu() and call a helper method for each possible action in onOptionsItemSelected(). The implementation is as follows:

  @Override
  public boolean onCreateOptionsMenu(final Menu menu) {
    getMenuInflater().inflate(R.menu.activity_lab, menu);
    return true;
  }

  @Override
  public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_delete:
      deletePhoto();
      return true;
    case R.id.menu_edit:
      editPhoto();
      return true;
    case R.id.menu_share:
      sharePhoto();
       return true;
    default:
      return super.onOptionsItemSelected(item);
    }
  }
}

Let's examine the menu actions' helper methods one-by-one, starting with deletePhoto(). Most of this method's implementation is the boilerplate code to set up a confirmation dialog. The dialog's confirmation button has an onClick() callback that deletes the image from the MediaStore and finishes the activity. The implementation of deletePhoto() is as follows:

  /*
  * Show a confirmation dialog. On confirmation, the photo is
  * deleted and the activity finishes.
  */
  private void deletePhoto() {
    final AlertDialog.Builder alert = new AlertDialog.Builder(
      LabActivity.this);
    alert.setTitle(R.string.photo_delete_prompt_title);
    alert.setMessage(R.string.photo_delete_prompt_message);
    alert.setCancelable(false);
    alert.setPositiveButton(R.string.delete,
      new DialogInterface.OnClickListener() {
        @Override
          public void onClick(final DialogInterface dialog,
            final int which) {
            getContentResolver().delete(
              Images.Media.EXTERNAL_CONTENT_URI,
                MediaStore.MediaColumns.DATA + "=?",
                  new String[] { mDataPath });
            finish();
          }
        });
    alert.setNegativeButton(android.R.string.cancel, null);
    alert.show();
  }

The next helper method, editPhoto(), sets up an intent and starts a chooser for that intent, using the Intent.createChooser() method. The user may cancel this chooser or use it to select an activity. If an activity is selected, editPhoto() starts it. The implementation is as follows:

  /*
  * Show a chooser so that the user may pick an app for editing
  * the photo.
  */
  private void editPhoto() {
    final Intent intent = new Intent(Intent.ACTION_EDIT);
    intent.setDataAndType(mUri, PHOTO_MIME_TYPE);
    startActivity(Intent.createChooser(intent,
      getString(R.string.photo_edit_chooser_title)));
  }

The last helper method, sharePhoto(), is similar to editPhoto(), though the intent is configured differently. The implementation is as follows:

  /*
  * Show a chooser so that the user may pick an app for sending
  * the photo.
  */
  private void sharePhoto() {
    final Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setType(PHOTO_MIME_TYPE);
    intent.putExtra(Intent.EXTRA_STREAM, mUri);
    intent.putExtra(Intent.EXTRA_SUBJECT,
      getString(R.string.photo_send_extra_subject));
    intent.putExtra(Intent.EXTRA_TEXT,
      getString(R.string.photo_send_extra_text));
    startActivity(Intent.createChooser(intent,
      getString(R.string.photo_send_chooser_title)));
  }
}

That's the last functionality we need for a basic photo capture and sharing application. Now, we should be able to build and run Second Sight.