package com.android.testingcamera; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import android.Manifest; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.ExifInterface; import android.media.MediaScannerConnection.OnScanCompletedListener; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.app.DialogFragment; import android.content.Intent; import android.text.method.ScrollingMovementMethod; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; public class SnapshotDialogFragment extends DialogFragment implements OnScanCompletedListener{ private ImageView mInfoImage; private TextView mInfoText; private Button mOkButton; private Button mSaveButton; private Button mSaveAndViewButton; private byte[] mJpegImage; private boolean mSaved = false; private boolean mViewWhenReady = false; private Uri mSavedUri = null; public SnapshotDialogFragment() { // Empty constructor required for DialogFragment } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_snapshot, container); mOkButton = (Button) view.findViewById(R.id.snapshot_ok); mOkButton.setOnClickListener(mOkButtonListener); mSaveButton = (Button) view.findViewById(R.id.snapshot_save); mSaveButton.setOnClickListener(mSaveButtonListener); mSaveAndViewButton = (Button) view.findViewById(R.id.snapshot_view); mSaveAndViewButton.setOnClickListener(mSaveAndViewButtonListener); mInfoImage = (ImageView) view.findViewById(R.id.snapshot_image); mInfoText= (TextView) view.findViewById(R.id.snapshot_text); mInfoText.setMovementMethod(new ScrollingMovementMethod()); if (mJpegImage != null) { new AsyncTask() { @Override protected Bitmap doInBackground(byte[]... params) { byte[] jpegImage = params[0]; BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(jpegImage, 0, jpegImage.length, opts); // Keep image at less than 1 MP. if (opts.outWidth > 1024 || opts.outHeight > 1024) { int scaleFactorX = opts.outWidth / 1024 + 1; int scaleFactorY = opts.outHeight / 1024 + 1; int scaleFactor = scaleFactorX > scaleFactorY ? scaleFactorX : scaleFactorY; opts.inSampleSize = scaleFactor; } opts.inJustDecodeBounds = false; Bitmap img = BitmapFactory.decodeByteArray(jpegImage, 0, jpegImage.length, opts); return img; } @Override protected void onPostExecute(Bitmap img) { mInfoImage.setImageBitmap(img); } }.execute(mJpegImage); } getDialog().setTitle("Snapshot result"); return view; } public OnClickListener mOkButtonListener = new OnClickListener() { @Override public void onClick(View v) { dismiss(); } }; public OnClickListener mSaveButtonListener = new OnClickListener() { @Override public void onClick(View v) { saveFile(); } }; public OnClickListener mSaveAndViewButtonListener = new OnClickListener() { @Override public void onClick(View v) { saveFile(); viewFile(); } }; public void updateImage(byte[] image) { mJpegImage = image; } public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { TestingCamera parent = (TestingCamera) getActivity(); if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { parent.log("Storage write permission granted"); saveFile(); } else { parent.log("Denied storage write permission; cannot save"); } } private String getAttrib(ExifInterface exif, String tag) { String attribute = exif.getAttribute(tag); return (attribute == null) ? "???" : attribute; } private void saveFile() { if (!mSaved) { TestingCamera parent = (TestingCamera) getActivity(); parent.log("Saving image"); if (parent.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { parent.log("Requesting storage write permission"); parent.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, parent.PERMISSIONS_REQUEST_SNAPSHOT); return; } File targetFile = parent.getOutputMediaFile(TestingCamera.MEDIA_TYPE_IMAGE); if (targetFile == null) { parent.logE("Unable to create file name"); return; } parent.logIndent(1); parent.log("File name: " + targetFile.toString()); try { FileOutputStream out = new FileOutputStream(targetFile); out.write(mJpegImage); out.close(); mSaved = true; parent.notifyMediaScannerOfFile(targetFile, this); updateExif(targetFile); } catch (IOException e) { parent.logE("Unable to save file: " + e.getMessage()); } parent.logIndent(-1); } } private void updateExif(File targetFile) { ((TestingCamera) getActivity()).log("Extracting EXIF"); try { ExifInterface exif = new ExifInterface(targetFile.toString()); String aperture = getAttrib(exif, ExifInterface.TAG_APERTURE); String dateTime = getAttrib(exif, ExifInterface.TAG_DATETIME); String exposureTime = getAttrib(exif, ExifInterface.TAG_EXPOSURE_TIME); int flash = exif.getAttributeInt(ExifInterface.TAG_FLASH, 0); double focalLength = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, 0); double gpsAltitude = exif.getAltitude(Double.NaN); String gpsDatestamp = getAttrib(exif, ExifInterface.TAG_GPS_DATESTAMP); float[] gpsCoords = new float[2]; if (!exif.getLatLong(gpsCoords)) { gpsCoords[0] = Float.NaN; gpsCoords[1] = Float.NaN; } String gpsProcessingMethod = getAttrib(exif, ExifInterface.TAG_GPS_PROCESSING_METHOD); String gpsTimestamp = getAttrib(exif, ExifInterface.TAG_GPS_TIMESTAMP); int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0); int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0); String iso = getAttrib(exif, ExifInterface.TAG_ISO); String make = getAttrib(exif, ExifInterface.TAG_MAKE); String model = getAttrib(exif, ExifInterface.TAG_MODEL); int orientationVal = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); int whiteBalance = exif.getAttributeInt(ExifInterface.TAG_WHITE_BALANCE, 0); final String[] orientationStrings= new String[] { "UNDEFINED", "NORMAL", "FLIP_HORIZONTAL", "ROTATE_180", "FLIP_VERTICAL", "TRANSPOSE", "ROTATE_90", "TRANSVERSE", "ROTATE_270" }; if (orientationVal >= orientationStrings.length) { orientationVal = 0; } String orientation = orientationStrings[orientationVal]; StringBuilder exifInfo = new StringBuilder(); exifInfo.append("EXIF information for "). append(targetFile.toString()).append("\n\n"); exifInfo.append("Size: "). append(width).append(" x ").append(height).append("\n"); exifInfo.append("Make: "). append(make).append("\n"); exifInfo.append("Model: "). append(model).append("\n"); exifInfo.append("Orientation: "). append(orientation).append("\n"); exifInfo.append("Aperture: "). append(aperture).append("\n"); exifInfo.append("Focal length: "). append(focalLength).append("\n"); exifInfo.append("Exposure time: "). append(exposureTime).append("\n"); exifInfo.append("ISO: "). append(iso).append("\n"); exifInfo.append("Flash: "). append(flash).append("\n"); exifInfo.append("White balance: "). append(whiteBalance).append("\n"); exifInfo.append("Date/Time: "). append(dateTime).append("\n"); exifInfo.append("GPS altitude: "). append(gpsAltitude).append("\n"); exifInfo.append("GPS latitude: "). append(gpsCoords[0]).append("\n"); exifInfo.append("GPS longitude: "). append(gpsCoords[1]).append("\n"); exifInfo.append("GPS datestamp: "). append(gpsDatestamp).append("\n"); exifInfo.append("GPS timestamp: "). append(gpsTimestamp).append("\n"); exifInfo.append("GPS processing method: "). append(gpsProcessingMethod).append("\n"); mInfoText.setText(exifInfo.toString()); } catch (IOException e) { ((TestingCamera) getActivity()).logE("Unable to extract EXIF: " + e.getMessage()); } } private synchronized void viewFile() { if (!mSaved) return; if (mSavedUri != null) { ((TestingCamera) getActivity()).log("Viewing file"); mViewWhenReady = false; getActivity().startActivity(new Intent(Intent.ACTION_VIEW, mSavedUri)); } else { mViewWhenReady = true; } } @Override public synchronized void onScanCompleted(String path, Uri uri) { mSavedUri = uri; if (mViewWhenReady) viewFile(); } }