1 package com.android.testingcamera; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 7 import android.Manifest; 8 import android.content.pm.PackageManager; 9 import android.graphics.Bitmap; 10 import android.graphics.BitmapFactory; 11 import android.media.ExifInterface; 12 import android.media.MediaScannerConnection.OnScanCompletedListener; 13 import android.net.Uri; 14 import android.os.AsyncTask; 15 import android.os.Bundle; 16 import android.app.DialogFragment; 17 import android.content.Intent; 18 import android.text.method.ScrollingMovementMethod; 19 import android.view.LayoutInflater; 20 import android.view.View; 21 import android.view.View.OnClickListener; 22 import android.view.ViewGroup; 23 import android.widget.Button; 24 import android.widget.ImageView; 25 import android.widget.TextView; 26 27 public class SnapshotDialogFragment extends DialogFragment 28 implements OnScanCompletedListener{ 29 30 private ImageView mInfoImage; 31 private TextView mInfoText; 32 private Button mOkButton; 33 private Button mSaveButton; 34 private Button mSaveAndViewButton; 35 36 private byte[] mJpegImage; 37 private boolean mSaved = false; 38 private boolean mViewWhenReady = false; 39 private Uri mSavedUri = null; 40 SnapshotDialogFragment()41 public SnapshotDialogFragment() { 42 // Empty constructor required for DialogFragment 43 } 44 45 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)46 public View onCreateView(LayoutInflater inflater, ViewGroup container, 47 Bundle savedInstanceState) { 48 View view = inflater.inflate(R.layout.fragment_snapshot, container); 49 50 mOkButton = (Button) view.findViewById(R.id.snapshot_ok); 51 mOkButton.setOnClickListener(mOkButtonListener); 52 53 mSaveButton = (Button) view.findViewById(R.id.snapshot_save); 54 mSaveButton.setOnClickListener(mSaveButtonListener); 55 56 mSaveAndViewButton = (Button) view.findViewById(R.id.snapshot_view); 57 mSaveAndViewButton.setOnClickListener(mSaveAndViewButtonListener); 58 59 mInfoImage = (ImageView) view.findViewById(R.id.snapshot_image); 60 mInfoText= (TextView) view.findViewById(R.id.snapshot_text); 61 mInfoText.setMovementMethod(new ScrollingMovementMethod()); 62 63 if (mJpegImage != null) { 64 new AsyncTask<byte[], Integer, Bitmap>() { 65 @Override 66 protected Bitmap doInBackground(byte[]... params) { 67 byte[] jpegImage = params[0]; 68 BitmapFactory.Options opts = new BitmapFactory.Options(); 69 opts.inJustDecodeBounds = true; 70 BitmapFactory.decodeByteArray(jpegImage, 0, 71 jpegImage.length, opts); 72 // Keep image at less than 1 MP. 73 if (opts.outWidth > 1024 || opts.outHeight > 1024) { 74 int scaleFactorX = opts.outWidth / 1024 + 1; 75 int scaleFactorY = opts.outHeight / 1024 + 1; 76 int scaleFactor = scaleFactorX > scaleFactorY ? 77 scaleFactorX : scaleFactorY; 78 opts.inSampleSize = scaleFactor; 79 } 80 opts.inJustDecodeBounds = false; 81 Bitmap img = BitmapFactory.decodeByteArray(jpegImage, 0, 82 jpegImage.length, opts); 83 return img; 84 } 85 86 @Override 87 protected void onPostExecute(Bitmap img) { 88 mInfoImage.setImageBitmap(img); 89 } 90 }.execute(mJpegImage); 91 } 92 93 getDialog().setTitle("Snapshot result"); 94 return view; 95 } 96 97 public OnClickListener mOkButtonListener = new OnClickListener() { 98 @Override 99 public void onClick(View v) { 100 dismiss(); 101 } 102 }; 103 104 public OnClickListener mSaveButtonListener = new OnClickListener() { 105 @Override 106 public void onClick(View v) { 107 saveFile(); 108 } 109 }; 110 111 public OnClickListener mSaveAndViewButtonListener = new OnClickListener() { 112 @Override 113 public void onClick(View v) { 114 saveFile(); 115 viewFile(); 116 } 117 }; 118 updateImage(byte[] image)119 public void updateImage(byte[] image) { 120 mJpegImage = image; 121 } 122 onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)123 public void onRequestPermissionsResult(int requestCode, String[] permissions, 124 int[] grantResults) { 125 TestingCamera parent = (TestingCamera) getActivity(); 126 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 127 parent.log("Storage write permission granted"); 128 saveFile(); 129 } else { 130 parent.log("Denied storage write permission; cannot save"); 131 } 132 } 133 getAttrib(ExifInterface exif, String tag)134 private String getAttrib(ExifInterface exif, String tag) { 135 String attribute = exif.getAttribute(tag); 136 return (attribute == null) ? "???" : attribute; 137 } 138 saveFile()139 private void saveFile() { 140 if (!mSaved) { 141 TestingCamera parent = (TestingCamera) getActivity(); 142 parent.log("Saving image"); 143 144 if (parent.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) 145 != PackageManager.PERMISSION_GRANTED) { 146 parent.log("Requesting storage write permission"); 147 parent.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 148 parent.PERMISSIONS_REQUEST_SNAPSHOT); 149 return; 150 } 151 152 File targetFile = parent.getOutputMediaFile(TestingCamera.MEDIA_TYPE_IMAGE); 153 if (targetFile == null) { 154 parent.logE("Unable to create file name"); 155 return; 156 } 157 parent.logIndent(1); 158 parent.log("File name: " + targetFile.toString()); 159 try { 160 FileOutputStream out = new FileOutputStream(targetFile); 161 out.write(mJpegImage); 162 out.close(); 163 mSaved = true; 164 parent.notifyMediaScannerOfFile(targetFile, this); 165 updateExif(targetFile); 166 } catch (IOException e) { 167 parent.logE("Unable to save file: " + e.getMessage()); 168 } 169 parent.logIndent(-1); 170 } 171 } 172 updateExif(File targetFile)173 private void updateExif(File targetFile) { 174 ((TestingCamera) getActivity()).log("Extracting EXIF"); 175 try { 176 ExifInterface exif = new ExifInterface(targetFile.toString()); 177 178 String aperture = getAttrib(exif, ExifInterface.TAG_APERTURE); 179 180 String dateTime = getAttrib(exif, ExifInterface.TAG_DATETIME); 181 String exposureTime = getAttrib(exif, ExifInterface.TAG_EXPOSURE_TIME); 182 int flash = exif.getAttributeInt(ExifInterface.TAG_FLASH, 0); 183 double focalLength = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, 0); 184 185 double gpsAltitude = exif.getAltitude(Double.NaN); 186 String gpsDatestamp = getAttrib(exif, ExifInterface.TAG_GPS_DATESTAMP); 187 float[] gpsCoords = new float[2]; 188 if (!exif.getLatLong(gpsCoords)) { 189 gpsCoords[0] = Float.NaN; 190 gpsCoords[1] = Float.NaN; 191 } 192 String gpsProcessingMethod = getAttrib(exif, ExifInterface.TAG_GPS_PROCESSING_METHOD); 193 String gpsTimestamp = getAttrib(exif, ExifInterface.TAG_GPS_TIMESTAMP); 194 195 int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0); 196 int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0); 197 String iso = getAttrib(exif, ExifInterface.TAG_ISO); 198 String make = getAttrib(exif, ExifInterface.TAG_MAKE); 199 String model = getAttrib(exif, ExifInterface.TAG_MODEL); 200 int orientationVal = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); 201 int whiteBalance = exif.getAttributeInt(ExifInterface.TAG_WHITE_BALANCE, 0); 202 203 final String[] orientationStrings= new String[] { 204 "UNDEFINED", 205 "NORMAL", 206 "FLIP_HORIZONTAL", 207 "ROTATE_180", 208 "FLIP_VERTICAL", 209 "TRANSPOSE", 210 "ROTATE_90", 211 "TRANSVERSE", 212 "ROTATE_270" 213 }; 214 if (orientationVal >= orientationStrings.length) { 215 orientationVal = 0; 216 } 217 String orientation = orientationStrings[orientationVal]; 218 219 StringBuilder exifInfo = new StringBuilder(); 220 exifInfo.append("EXIF information for "). 221 append(targetFile.toString()).append("\n\n"); 222 exifInfo.append("Size: "). 223 append(width).append(" x ").append(height).append("\n"); 224 exifInfo.append("Make: "). 225 append(make).append("\n"); 226 exifInfo.append("Model: "). 227 append(model).append("\n"); 228 exifInfo.append("Orientation: "). 229 append(orientation).append("\n"); 230 exifInfo.append("Aperture: "). 231 append(aperture).append("\n"); 232 exifInfo.append("Focal length: "). 233 append(focalLength).append("\n"); 234 exifInfo.append("Exposure time: "). 235 append(exposureTime).append("\n"); 236 exifInfo.append("ISO: "). 237 append(iso).append("\n"); 238 exifInfo.append("Flash: "). 239 append(flash).append("\n"); 240 exifInfo.append("White balance: "). 241 append(whiteBalance).append("\n"); 242 exifInfo.append("Date/Time: "). 243 append(dateTime).append("\n"); 244 exifInfo.append("GPS altitude: "). 245 append(gpsAltitude).append("\n"); 246 exifInfo.append("GPS latitude: "). 247 append(gpsCoords[0]).append("\n"); 248 exifInfo.append("GPS longitude: "). 249 append(gpsCoords[1]).append("\n"); 250 exifInfo.append("GPS datestamp: "). 251 append(gpsDatestamp).append("\n"); 252 exifInfo.append("GPS timestamp: "). 253 append(gpsTimestamp).append("\n"); 254 exifInfo.append("GPS processing method: "). 255 append(gpsProcessingMethod).append("\n"); 256 mInfoText.setText(exifInfo.toString()); 257 258 } catch (IOException e) { 259 ((TestingCamera) getActivity()).logE("Unable to extract EXIF: " + e.getMessage()); 260 } 261 } 262 viewFile()263 private synchronized void viewFile() { 264 if (!mSaved) return; 265 if (mSavedUri != null) { 266 ((TestingCamera) getActivity()).log("Viewing file"); 267 mViewWhenReady = false; 268 getActivity().startActivity(new Intent(Intent.ACTION_VIEW, mSavedUri)); 269 } else { 270 mViewWhenReady = true; 271 } 272 } 273 274 @Override onScanCompleted(String path, Uri uri)275 public synchronized void onScanCompleted(String path, Uri uri) { 276 mSavedUri = uri; 277 if (mViewWhenReady) viewFile(); 278 } 279 } 280