ImageRecord.java revision ad9a9c83630d87328c8439ac8b8b9a2c800dbd57
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.nfc.NdefRecord; 32import android.os.Parcel; 33import android.os.Parcelable; 34import android.provider.MediaStore; 35import android.provider.OpenableColumns; 36import android.view.LayoutInflater; 37import android.view.View; 38import android.view.ViewGroup; 39import android.widget.ImageView; 40import android.widget.TextView; 41 42import java.io.ByteArrayOutputStream; 43import java.util.List; 44 45/** 46 * A NdefRecord corresponding to an image type. 47 */ 48public class ImageRecord implements ParsedNdefRecord { 49 50 public static final String RECORD_TYPE = "ImageRecord"; 51 52 private final Bitmap mBitmap; 53 54 private ImageRecord(Bitmap bitmap) { 55 mBitmap = Preconditions.checkNotNull(bitmap); 56 } 57 58 @Override 59 public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent) { 60 ImageView image = (ImageView) inflater.inflate(R.layout.tag_image, parent, false); 61 image.setImageBitmap(mBitmap); 62 return image; 63 } 64 65 /** 66 * Returns a view in a list of record types for adding new records to a message. 67 */ 68 public static View getAddView(Context context, LayoutInflater inflater, ViewGroup parent) { 69 ViewGroup root = (ViewGroup) inflater.inflate( 70 R.layout.tag_add_record_list_item, parent, false); 71 72 // Determine which Activity can retrieve images. 73 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 74 intent.addCategory(Intent.CATEGORY_OPENABLE); 75 intent.setType("image/*"); 76 77 PackageManager pm = context.getPackageManager(); 78 List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0); 79 if (activities.isEmpty()) { 80 return null; 81 } 82 83 ResolveInfo info = activities.get(0); 84 ((ImageView) root.findViewById(R.id.image)).setImageDrawable(info.loadIcon(pm)); 85 ((TextView) root.findViewById(R.id.text)).setText(context.getString(R.string.photo)); 86 87 root.setTag(new ImageRecordEditInfo(intent)); 88 return root; 89 } 90 91 public static ImageRecord parse(NdefRecord record) { 92 MimeRecord underlyingRecord = MimeRecord.parse(record); 93 Preconditions.checkArgument(underlyingRecord.getMimeType().startsWith("image/")); 94 95 // Try to ensure it's a legal, valid image 96 byte[] content = underlyingRecord.getContent(); 97 Bitmap bitmap = BitmapFactory.decodeByteArray(content, 0, content.length); 98 if (bitmap == null) { 99 throw new IllegalArgumentException("not a valid image file"); 100 } 101 return new ImageRecord(bitmap); 102 } 103 104 public static boolean isImage(NdefRecord record) { 105 try { 106 parse(record); 107 return true; 108 } catch (IllegalArgumentException e) { 109 return false; 110 } 111 } 112 113 public static NdefRecord newImageRecord(Bitmap bitmap) { 114 ByteArrayOutputStream out = new ByteArrayOutputStream(); 115 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); 116 byte[] content = out.toByteArray(); 117 return MimeRecord.newMimeRecord("image/jpeg", content); 118 } 119 120 private static class ImageRecordEditInfo extends RecordEditInfo { 121 private final Intent mIntent; 122 private String mCurrentPath; 123 private Bitmap mCachedValue; 124 125 public static final int MAX_IMAGE_SIZE = 128; 126 127 public ImageRecordEditInfo(Intent intent) { 128 super(RECORD_TYPE); 129 mIntent = intent; 130 mCurrentPath = ""; 131 } 132 133 protected ImageRecordEditInfo(Parcel parcel) { 134 super(parcel); 135 mIntent = parcel.readParcelable(null); 136 mCurrentPath = parcel.readString(); 137 } 138 139 @Override 140 public Intent getPickIntent() { 141 return mIntent; 142 } 143 144 @Override 145 public NdefRecord getValue() { 146 return ImageRecord.newImageRecord(getValueInternal()); 147 } 148 149 private Bitmap getValueInternal() { 150 if (mCachedValue == null) { 151 Bitmap original = BitmapFactory.decodeFile(mCurrentPath); 152 int width = original.getWidth(); 153 int height = original.getHeight(); 154 int major = (width > height) ? width : height; 155 if (major > MAX_IMAGE_SIZE) { 156 double scale = 1.0 * MAX_IMAGE_SIZE / major; 157 width *= scale; 158 height *= scale; 159 } 160 mCachedValue = ThumbnailUtils.extractThumbnail(original, width, height); 161 } 162 return mCachedValue; 163 } 164 165 @Override 166 public void handlePickResult(Context context, Intent data) { 167 Cursor cursor = null; 168 mCachedValue = null; 169 try { 170 String[] projection = { MediaStore.Images.Media.DATA, OpenableColumns.SIZE }; 171 cursor = context.getContentResolver().query( 172 data.getData(), projection, null, null, null); 173 cursor.moveToFirst(); 174 int size = cursor.getInt(1); 175 mCurrentPath = cursor.getString(0); 176 177 // TODO: enforce a size limit. May be tricky. 178 179 } finally { 180 if (cursor != null) { 181 cursor.close(); 182 } 183 } 184 } 185 186 @Override 187 public View getEditView( 188 Activity activity, LayoutInflater inflater, 189 ViewGroup parent, EditCallbacks callbacks) { 190 View result = buildEditView( 191 activity, inflater, R.layout.tag_edit_image, parent, callbacks); 192 ((ImageView) result.findViewById(R.id.image)).setImageBitmap(getValueInternal()); 193 result.setOnClickListener(this); 194 return result; 195 } 196 197 @Override 198 public void writeToParcel(Parcel out, int flags) { 199 super.writeToParcel(out, flags); 200 out.writeParcelable(mIntent, flags); 201 out.writeString(mCurrentPath); 202 } 203 204 @SuppressWarnings("unused") 205 public static final Parcelable.Creator<ImageRecordEditInfo> CREATOR = 206 new Parcelable.Creator<ImageRecordEditInfo>() { 207 public ImageRecordEditInfo createFromParcel(Parcel in) { 208 return new ImageRecordEditInfo(in); 209 } 210 211 public ImageRecordEditInfo[] newArray(int size) { 212 return new ImageRecordEditInfo[size]; 213 } 214 }; 215 216 @Override 217 public int describeContents() { 218 return 0; 219 } 220 221 @Override 222 public void onClick(View target) { 223 if (this == target.getTag()) { 224 mCallbacks.startPickForRecord(this, mIntent); 225 } else { 226 super.onClick(target); 227 } 228 } 229 } 230} 231