ImageRecord.java revision 40d9a0cd0a37d184ee737b2d7138a39e4292ce3e
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 17package com.android.apps.tag.record; 18 19import com.android.apps.tag.R; 20import com.google.common.base.Preconditions; 21 22import android.app.Activity; 23import android.content.Context; 24import android.content.Intent; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.database.Cursor; 28import android.graphics.Bitmap; 29import android.graphics.BitmapFactory; 30import android.media.ThumbnailUtils; 31import android.net.Uri; 32import android.nfc.NdefRecord; 33import android.os.Parcel; 34import android.os.Parcelable; 35import android.provider.MediaStore; 36import android.provider.OpenableColumns; 37import android.view.LayoutInflater; 38import android.view.View; 39import android.view.ViewGroup; 40import android.widget.ImageView; 41import android.widget.TextView; 42import android.widget.Toast; 43 44import java.io.ByteArrayOutputStream; 45import java.util.List; 46 47/** 48 * A NdefRecord corresponding to an image type. 49 */ 50public 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} 245