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