1package com.android.testingcamera;
2
3import java.io.File;
4import java.io.FileOutputStream;
5import java.io.IOException;
6
7import android.graphics.Bitmap;
8import android.graphics.BitmapFactory;
9import android.media.ExifInterface;
10import android.media.MediaScannerConnection.OnScanCompletedListener;
11import android.net.Uri;
12import android.os.AsyncTask;
13import android.os.Bundle;
14import android.app.DialogFragment;
15import android.content.Intent;
16import android.text.method.ScrollingMovementMethod;
17import android.view.LayoutInflater;
18import android.view.View;
19import android.view.View.OnClickListener;
20import android.view.ViewGroup;
21import android.widget.Button;
22import android.widget.ImageView;
23import android.widget.TextView;
24
25class 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
39    public SnapshotDialogFragment() {
40        // Empty constructor required for DialogFragment
41    }
42
43    @Override
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
117    public void updateImage(byte[] image) {
118        mJpegImage = image;
119    }
120
121    private String getAttrib(ExifInterface exif, String tag) {
122        String attribute = exif.getAttribute(tag);
123        return (attribute == null) ? "???" : attribute;
124    }
125
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
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
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
254    public synchronized void onScanCompleted(String path, Uri uri) {
255        mSavedUri = uri;
256        if (mViewWhenReady) viewFile();
257    }
258}
259