Using a Camera Intent

The next step is to actually take the picture. This is the easy part: You get to use an implicit intent again.

Start by stashing the location of the photo file. (You will use it a few more times, so this will save a bit of work.)

Listing 16.7  Grabbing photo file location (CrimeFragment.java)

private Crime mCrime;
private File mPhotoFile;
private EditText mTitleField;
...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    UUID crimeId = (UUID) getArguments().getSerializable(ARG_CRIME_ID);
    mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
    mPhotoFile = CrimeLab.get(getActivity()).getPhotoFile(mCrime);
}

Next you will hook up the camera button to actually take the picture. The camera intent is defined in MediaStore, Android’s lord and master of all things media related. You will send an intent with an action of MediaStore.ACTION_IMAGE_CAPTURE, and Android will fire up a camera activity and take a picture for you.

But hold that thought for one minute.

Firing the intent

Now you are ready to fire the camera intent. The action you want is called ACTION_IMAGE_CAPTURE, and it is defined in the MediaStore class. MediaStore defines the public interfaces used in Android for interacting with common media – images, videos, and music. This includes the image capture intent, which fires up the camera.

By default, ACTION_IMAGE_CAPTURE will dutifully fire up the camera application and take a picture, but it will not be a full-resolution picture. Instead, it will take a small-resolution thumbnail picture and stick it inside the Intent object returned in onActivityResult(…).

For a full-resolution output, you need to tell it where to save the image on the filesystem. This can be done by passing a Uri pointing to where you want to save the file in MediaStore.EXTRA_OUTPUT. This Uri will point at a location serviced by FileProvider.

Write an implicit intent to ask for a new picture to be taken into the location saved in mPhotoFile. Add code to ensure that the button is disabled if there is no camera app or if there is no location at which to save the photo. (To determine whether there is a camera app available, you will query PackageManager for activities that respond to your camera implicit intent. Querying the PackageManager is discussed in more detail in the section called Checking for responding activities in Chapter 15.)

Listing 16.8  Firing a camera intent (CrimeFragment.java)

private static final int REQUEST_DATE = 0;
private static final int REQUEST_CONTACT = 1;
private static final int REQUEST_PHOTO= 2;
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    ...
    mPhotoButton = (ImageButton) v.findViewById(R.id.crime_camera);
    final Intent captureImage = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    boolean canTakePhoto = mPhotoFile != null &&
            captureImage.resolveActivity(packageManager) != null;
    mPhotoButton.setEnabled(canTakePhoto);

    mPhotoButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Uri uri = FileProvider.getUriForFile(getActivity(),
                    "com.bignerdranch.android.criminalintent.fileprovider",
                    mPhotoFile);
            captureImage.putExtra(MediaStore.EXTRA_OUTPUT, uri);

            List<ResolveInfo> cameraActivities = getActivity()
                    .getPackageManager().queryIntentActivities(captureImage,
                            PackageManager.MATCH_DEFAULT_ONLY);

            for (ResolveInfo activity : cameraActivities) {
                getActivity().grantUriPermission(activity.activityInfo.packageName,
                        uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            }

            startActivityForResult(captureImage, REQUEST_PHOTO);
        }
    });

    mPhotoView = (ImageView) v.findViewById(R.id.crime_photo);

    return v;
}

Calling FileProvider.getUriForFile(…) translates your local filepath into a Uri the camera app can see. To actually write to it, though, you need to grant the camera app permission. To do this, you grant the Intent.FLAG_GRANT_WRITE_URI_PERMISSION flag to every activity your cameraImage intent can resolve to. That grants them all a write permission specifically for this one Uri. Adding the android:grantUriPermissions attribute in your provider declaration was necessary to open this bit of functionality. Later, you will revoke this permission to close up that gap in your armor again.

Run CriminalIntent and press the camera button to run your camera app (Figure 16.4).

Figure 16.4  [Insert your camera app here]

Screenshot shows Camera app in Android.  The screen shows a set of three objects in a Camera with a tick mark at the center and a layout button on the left.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.84.155