1 /* 2 * Copyright (C) 2009 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.contacts.editor; 18 19 import com.android.contacts.R; 20 import com.android.contacts.model.DataKind; 21 import com.android.contacts.model.EntityDelta; 22 import com.android.contacts.model.EntityDelta.ValuesDelta; 23 24 import android.content.Context; 25 import android.graphics.Bitmap; 26 import android.graphics.BitmapFactory; 27 import android.provider.ContactsContract.CommonDataKinds.Photo; 28 import android.util.AttributeSet; 29 import android.util.Log; 30 import android.view.View; 31 import android.widget.FrameLayout; 32 import android.widget.ImageView; 33 34 import java.io.ByteArrayOutputStream; 35 import java.io.IOException; 36 37 /** 38 * Simple editor for {@link Photo}. 39 */ 40 public class PhotoEditorView extends FrameLayout implements Editor { 41 private static final String TAG = "PhotoEditorView"; 42 43 private ImageView mPhotoImageView; 44 private View mFrameView; 45 46 private ValuesDelta mEntry; 47 private EditorListener mListener; 48 49 private boolean mHasSetPhoto = false; 50 private boolean mReadOnly; 51 52 public PhotoEditorView(Context context) { 53 super(context); 54 } 55 56 public PhotoEditorView(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 } 59 60 @Override 61 public void setEnabled(boolean enabled) { 62 super.setEnabled(enabled); 63 mFrameView.setEnabled(enabled); 64 } 65 66 /** {@inheritDoc} */ 67 @Override 68 protected void onFinishInflate() { 69 super.onFinishInflate(); 70 mPhotoImageView = (ImageView) findViewById(R.id.photo); 71 mFrameView = findViewById(R.id.frame); 72 mFrameView.setOnClickListener(new OnClickListener() { 73 @Override 74 public void onClick(View v) { 75 if (mListener != null) { 76 mListener.onRequest(EditorListener.REQUEST_PICK_PHOTO); 77 } 78 } 79 }); 80 } 81 82 /** {@inheritDoc} */ 83 @Override 84 public void onFieldChanged(String column, String value) { 85 throw new UnsupportedOperationException("Photos don't support direct field changes"); 86 } 87 88 /** {@inheritDoc} */ 89 @Override 90 public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly, 91 ViewIdGenerator vig) { 92 mEntry = values; 93 mReadOnly = readOnly; 94 95 setId(vig.getId(state, kind, values, 0)); 96 97 if (values != null) { 98 // Try decoding photo if actual entry 99 final byte[] photoBytes = values.getAsByteArray(Photo.PHOTO); 100 if (photoBytes != null) { 101 final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0, 102 photoBytes.length); 103 104 mPhotoImageView.setImageBitmap(photo); 105 mFrameView.setEnabled(isEnabled()); 106 mHasSetPhoto = true; 107 mEntry.setFromTemplate(false); 108 } else { 109 resetDefault(); 110 } 111 } else { 112 resetDefault(); 113 } 114 } 115 116 /** 117 * Return true if a valid {@link Photo} has been set. 118 */ 119 public boolean hasSetPhoto() { 120 return mHasSetPhoto; 121 } 122 123 /** 124 * Assign the given {@link Bitmap} as the new value, updating UI and 125 * readying for persisting through {@link ValuesDelta}. 126 */ 127 public void setPhotoBitmap(Bitmap photo) { 128 if (photo == null) { 129 // Clear any existing photo and return 130 mEntry.put(Photo.PHOTO, (byte[])null); 131 resetDefault(); 132 return; 133 } 134 135 final int size = photo.getWidth() * photo.getHeight() * 4; 136 final ByteArrayOutputStream out = new ByteArrayOutputStream(size); 137 138 try { 139 photo.compress(Bitmap.CompressFormat.PNG, 100, out); 140 out.flush(); 141 out.close(); 142 143 mEntry.put(Photo.PHOTO, out.toByteArray()); 144 mPhotoImageView.setImageBitmap(photo); 145 mFrameView.setEnabled(isEnabled()); 146 mHasSetPhoto = true; 147 mEntry.setFromTemplate(false); 148 149 // When the user chooses a new photo mark it as super primary 150 mEntry.put(Photo.IS_SUPER_PRIMARY, 1); 151 } catch (IOException e) { 152 Log.w(TAG, "Unable to serialize photo: " + e.toString()); 153 } 154 } 155 156 /** 157 * Set the super primary bit on the photo. 158 */ 159 public void setSuperPrimary(boolean superPrimary) { 160 mEntry.put(Photo.IS_SUPER_PRIMARY, superPrimary ? 1 : 0); 161 } 162 163 protected void resetDefault() { 164 // Invalid photo, show default "add photo" place-holder 165 mPhotoImageView.setImageResource(R.drawable.ic_contact_picture_holo_light); 166 mFrameView.setEnabled(!mReadOnly && isEnabled()); 167 mHasSetPhoto = false; 168 mEntry.setFromTemplate(true); 169 } 170 171 /** {@inheritDoc} */ 172 @Override 173 public void setEditorListener(EditorListener listener) { 174 mListener = listener; 175 } 176 177 @Override 178 public void setDeletable(boolean deletable) { 179 // Photo is not deletable 180 } 181 182 @Override 183 public boolean isEmpty() { 184 return !mHasSetPhoto; 185 } 186 187 @Override 188 public void deleteEditor() { 189 // Photo is not deletable 190 } 191 192 @Override 193 public void clearAllFields() { 194 resetDefault(); 195 } 196 } 197