f15f9b59679263ffb35a529c3e54ca46bfe7b89d
[android/platform/packages/apps/Tag.git] / src / com / android / apps / tag / record / ImageRecord.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.apps.tag.record;
18
19 import com.android.apps.tag.R;
20 import com.google.common.base.Preconditions;
21
22 import android.app.Activity;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.database.Cursor;
28 import android.graphics.Bitmap;
29 import android.graphics.BitmapFactory;
30 import android.media.ThumbnailUtils;
31 import android.net.Uri;
32 import android.nfc.NdefRecord;
33 import android.os.Parcel;
34 import android.os.Parcelable;
35 import android.provider.MediaStore;
36 import android.provider.OpenableColumns;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.widget.ImageView;
41 import android.widget.TextView;
42 import android.widget.Toast;
43
44 import java.io.ByteArrayOutputStream;
45 import java.util.List;
46
47 /**
48  * A NdefRecord corresponding to an image type.
49  */
50 public class ImageRecord extends ParsedNdefRecord {
51
52     public static final String RECORD_TYPE = "ImageRecord";
53
54     private final Bitmap mBitmap;
55
56     private ImageRecord(Bitmap bitmap) {
57         mBitmap = Preconditions.checkNotNull(bitmap);
58     }
59
60     @Override
61     public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent, int offset) {
62         ImageView image = (ImageView) inflater.inflate(R.layout.tag_image, parent, false);
63         image.setImageBitmap(mBitmap);
64         return image;
65     }
66
67     /**
68      * Returns a view in a list of record types for adding new records to a message.
69      */
70     public static View getAddView(Context context, LayoutInflater inflater, ViewGroup parent) {
71         ViewGroup root = (ViewGroup) inflater.inflate(
72                 R.layout.tag_add_record_list_item, parent, false);
73
74         // Determine which Activity can retrieve images.
75         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
76         intent.addCategory(Intent.CATEGORY_OPENABLE);
77         intent.setType("image/*");
78
79         PackageManager pm = context.getPackageManager();
80         List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
81         if (activities.isEmpty()) {
82             return null;
83         }
84
85         ResolveInfo info = activities.get(0);
86         ((ImageView) root.findViewById(R.id.image)).setImageDrawable(info.loadIcon(pm));
87         ((TextView) root.findViewById(R.id.text)).setText(context.getString(R.string.photo));
88
89         root.setTag(new ImageRecordEditInfo(intent));
90         return root;
91     }
92
93     public static ImageRecord parse(NdefRecord record) {
94         MimeRecord underlyingRecord = MimeRecord.parse(record);
95         Preconditions.checkArgument(underlyingRecord.getMimeType().startsWith("image/"));
96
97         // Try to ensure it's a legal, valid image
98         byte[] content = underlyingRecord.getContent();
99         Bitmap bitmap = BitmapFactory.decodeByteArray(content, 0, content.length);
100         if (bitmap == null) {
101             throw new IllegalArgumentException("not a valid image file");
102         }
103         return new ImageRecord(bitmap);
104     }
105
106     public static boolean isImage(NdefRecord record) {
107         try {
108             parse(record);
109             return true;
110         } catch (IllegalArgumentException e) {
111             return false;
112         }
113     }
114
115     public static NdefRecord newImageRecord(Bitmap bitmap) {
116         ByteArrayOutputStream out = new ByteArrayOutputStream();
117         bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
118         byte[] content = out.toByteArray();
119         return MimeRecord.newMimeRecord("image/jpeg", content);
120     }
121
122     private static class ImageRecordEditInfo extends RecordEditInfo {
123         private final Intent mIntent;
124         private String mCurrentPath;
125         private Bitmap mCachedValue;
126
127         public static final int MAX_IMAGE_SIZE = 128;
128
129         public ImageRecordEditInfo(Intent intent) {
130             super(RECORD_TYPE);
131             mIntent = intent;
132             mCurrentPath = "";
133         }
134
135         protected ImageRecordEditInfo(Parcel parcel) {
136             super(parcel);
137             mIntent = parcel.readParcelable(null);
138             mCurrentPath = parcel.readString();
139         }
140
141         @Override
142         public Intent getPickIntent() {
143             return mIntent;
144         }
145
146         @Override
147         public NdefRecord getValue() {
148             return ImageRecord.newImageRecord(getValueInternal());
149         }
150
151         private Bitmap getValueInternal() {
152             if (mCachedValue == null) {
153                 Bitmap original = BitmapFactory.decodeFile(mCurrentPath);
154                 int width = original.getWidth();
155                 int height = original.getHeight();
156                 int major = (width > height) ? width : height;
157                 if (major > MAX_IMAGE_SIZE) {
158                     double scale = 1.0 * MAX_IMAGE_SIZE / major;
159                     width *= scale;
160                     height *= scale;
161                 }
162                 mCachedValue = ThumbnailUtils.extractThumbnail(original, width, height);
163             }
164             return mCachedValue;
165         }
166
167         @Override
168         public void handlePickResult(Context context, Intent data) {
169             Cursor cursor = null;
170             mCachedValue = null;
171
172             try {
173                 String[] projection = { MediaStore.Images.Media.DATA, OpenableColumns.SIZE };
174                 cursor = context.getContentResolver().query(
175                         data.getData(), projection, null, null, null);
176
177                 if (cursor == null) {
178                     Toast.makeText(
179                             context,
180                             context.getResources().getString(R.string.bad_photo),
181                             Toast.LENGTH_LONG).show();
182                     throw new IllegalArgumentException("Selected image could not be loaded");
183                 }
184
185                 cursor.moveToFirst();
186                 int size = cursor.getInt(1);
187                 mCurrentPath = cursor.getString(0);
188
189                 // TODO: enforce a size limit. May be tricky.
190
191             } finally {
192                 if (cursor != null) {
193                     cursor.close();
194                 }
195             }
196         }
197
198         @Override
199         public View getEditView(
200                 Activity activity, LayoutInflater inflater,
201                 ViewGroup parent, EditCallbacks callbacks) {
202             View result = buildEditView(
203                     activity, inflater, R.layout.tag_edit_image, parent, callbacks);
204             ((ImageView) result.findViewById(R.id.image)).setImageBitmap(getValueInternal());
205             result.setOnClickListener(this);
206             return result;
207         }
208
209         @Override
210         public void writeToParcel(Parcel out, int flags) {
211             super.writeToParcel(out, flags);
212             out.writeParcelable(mIntent, flags);
213             out.writeString(mCurrentPath);
214         }
215
216         @SuppressWarnings("unused")
217         public static final Parcelable.Creator<ImageRecordEditInfo> CREATOR =
218                 new Parcelable.Creator<ImageRecordEditInfo>() {
219             @Override
220             public ImageRecordEditInfo createFromParcel(Parcel in) {
221                 return new ImageRecordEditInfo(in);
222             }
223
224             @Override
225             public ImageRecordEditInfo[] newArray(int size) {
226                 return new ImageRecordEditInfo[size];
227             }
228         };
229
230         @Override
231         public int describeContents() {
232             return 0;
233         }
234
235         @Override
236         public void onClick(View target) {
237             if (this == target.getTag()) {
238                 mCallbacks.startPickForRecord(this, mIntent);
239             } else {
240                 super.onClick(target);
241             }
242         }
243     }
244 }