First pass on photo support for compact contact editor

Only updates the primary photo for now.

Bug 19124091

Change-Id: I1886888b4cf249da4c483d570b9db6e05564518a
diff --git a/res/layout/compact_contact_editor_fragment.xml b/res/layout/compact_contact_editor_fragment.xml
index 6eb32a7..ae3eb59 100644
--- a/res/layout/compact_contact_editor_fragment.xml
+++ b/res/layout/compact_contact_editor_fragment.xml
@@ -29,6 +29,22 @@
             android:orientation="vertical"
             android:visibility="invisible">
 
+        <!-- TODO: remove hard coded dimensions when we have a split screen layout in landscape -->
+        <com.android.contacts.editor.CompactHeaderView
+                android:id="@+id/header"
+                android:layout_width="@dimen/detail_contact_photo_expanded_size"
+                android:layout_height="@dimen/detail_contact_photo_expanded_size"
+                android:layout_gravity="center_horizontal"
+                android:orientation="vertical">
+
+            <ImageView android:id="@+id/photo"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:clickable="true"
+                    android:scaleType="centerCrop"/>
+
+        </com.android.contacts.editor.CompactHeaderView>
+
         <LinearLayout
                 android:id="@+id/names"
                 android:layout_width="match_parent"
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 425f7ce..c93f873 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -19,9 +19,18 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.R;
 import com.android.contacts.activities.CompactContactEditorActivity;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.detail.PhotoSelectionHandler;
+import com.android.contacts.util.ContactPhotoUtils;
 
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -30,12 +39,91 @@
 import android.widget.LinearLayout;
 import android.widget.Toast;
 
+import java.io.FileNotFoundException;
+
 /**
  * Contact editor with only the most important fields displayed initially.
  */
 public class CompactContactEditorFragment extends ContactEditorBaseFragment implements
         CompactRawContactsEditorView.Listener {
 
+    private static final String KEY_PHOTO_URI = "photo_uri";
+    private static final String KEY_PHOTO_RAW_CONTACT_ID = "photo_raw_contact_id";
+    private static final String KEY_UPDATED_PHOTOS = "updated_photos";
+
+    /**
+     * Displays a PopupWindow with photo edit options.
+     */
+    final class PhotoHandler extends PhotoSelectionHandler {
+
+        /**
+         * Receiver of photo edit option callbacks.
+         */
+        private final class PhotoListener extends PhotoActionListener {
+            @Override
+            public void onRemovePictureChosen() {
+                getContent().setPhoto(/* bitmap =*/ null);
+                mUpdatedPhotos.remove(String.valueOf(mPhotoRawContactId));
+            }
+
+            @Override
+            public void onPhotoSelected(Uri uri) throws FileNotFoundException {
+                final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(getActivity(), uri);
+                if (bitmap == null || bitmap.getHeight() <= 0 || bitmap.getWidth() <= 0) {
+                    Log.w(TAG, "Invalid photo selected");
+                }
+                getContent().setPhoto(bitmap);
+                mUpdatedPhotos.putParcelable(String.valueOf(mPhotoRawContactId), uri);
+            }
+
+            @Override
+            public Uri getCurrentPhotoUri() {
+                return mPhotoUri;
+            }
+
+            @Override
+            public void onPhotoSelectionDismissed() {
+            }
+        }
+
+        private PhotoListener mPhotoListener;
+
+        public PhotoHandler(Context context, View changeAnchorView, int photoMode,
+                boolean isDirectoryContact, RawContactDeltaList state) {
+            super(context, changeAnchorView, photoMode, isDirectoryContact, state);
+            mPhotoListener = new PhotoListener();
+        }
+
+        @Override
+        public PhotoActionListener getListener() {
+            return mPhotoListener;
+        }
+
+        @Override
+        protected void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) {
+            mPhotoUri = photoUri;
+            mStatus = Status.SUB_ACTIVITY;
+
+            CompactContactEditorFragment.this.startActivityForResult(intent, requestCode);
+        }
+    }
+
+    private PhotoHandler mPhotoHandler;
+    private Uri mPhotoUri;
+    private long mPhotoRawContactId;
+    private Bundle mUpdatedPhotos = new Bundle();
+
+    @Override
+    public void onCreate(Bundle savedState) {
+        super.onCreate(savedState);
+
+        if (savedState != null) {
+            mPhotoUri = savedState.getParcelable(KEY_PHOTO_URI);
+            mPhotoRawContactId = savedState.getLong(KEY_PHOTO_RAW_CONTACT_ID);
+            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
+        }
+    }
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
         setHasOptionsMenu(true);
@@ -47,10 +135,22 @@
     }
 
     @Override
+    public void onSaveInstanceState(Bundle outState) {
+        outState.putParcelable(KEY_PHOTO_URI, mPhotoUri);
+        outState.putLong(KEY_PHOTO_RAW_CONTACT_ID, mPhotoRawContactId);
+        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (mStatus == Status.SUB_ACTIVITY) {
             mStatus = Status.EDITING;
         }
+        if (mPhotoHandler != null
+                && mPhotoHandler.handlePhotoActivityResult(requestCode, resultCode, data)) {
+            return;
+        }
         super.onActivityResult(requestCode, resultCode, data);
     }
 
@@ -60,12 +160,16 @@
             return;
         }
 
-        CompactRawContactsEditorView editorView = (CompactRawContactsEditorView) mContent;
+        final CompactRawContactsEditorView editorView = getContent();
         editorView.setListener(this);
         editorView.setState(mState, mViewIdGenerator);
         editorView.setEnabled(isEnabled());
         editorView.setVisibility(View.VISIBLE);
 
+        mPhotoHandler = createPhotoHandler();
+        mPhotoRawContactId = editorView.getPhotoRawContactId();
+        editorView.setPhotoHandler(mPhotoHandler);
+
         invalidateOptionsMenu();
     }
 
@@ -91,6 +195,35 @@
         return true;
     }
 
+    private PhotoHandler createPhotoHandler() {
+        // To determine the options that are available to the user to update their photo
+        // (i.e. the photo mode), check if any of the writable raw contacts has a photo set
+        Integer photoMode = null;
+        boolean hasWritableAccountType = false;
+        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+        for (RawContactDelta rawContactDelta : mState) {
+            if (!rawContactDelta.isVisible()) {
+                continue;
+            }
+            final AccountType accountType = rawContactDelta.getAccountType(accountTypes);
+            if (accountType.areContactsWritable()) {
+                hasWritableAccountType = true;
+                if (getContent().isWritablePhotoSet()) {
+                    photoMode = PhotoActionPopup.Modes.WRITE_ABLE_PHOTO;
+                    break;
+                }
+            }
+        }
+        // If the mode was not set, base it on whether we saw a writable contact or not
+        if (photoMode == null) {
+            photoMode = hasWritableAccountType
+                    ? PhotoActionPopup.Modes.NO_PHOTO : PhotoActionPopup.Modes.READ_ONLY_PHOTO;
+        }
+
+        return new PhotoHandler(getActivity(), getContent().getPhotoPopupAnchorView(),
+                photoMode, /* isDirectoryContact =*/ false, mState);
+    }
+
     @Override
     protected void setGroupMetaData() {
         // The compact editor does not support groups.
@@ -103,7 +236,7 @@
                 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                 ((Activity) mContext).getClass(),
                 CompactContactEditorActivity.ACTION_SAVE_COMPLETED,
-                /* updatedPhotos =*/ new Bundle());
+                mUpdatedPhotos);
         mContext.startService(intent);
 
         return true;
@@ -122,4 +255,8 @@
     public void onExpandEditor() {
         Toast.makeText(mContext, "Not yet implemented", Toast.LENGTH_SHORT).show();
     }
+
+    private CompactRawContactsEditorView getContent() {
+        return (CompactRawContactsEditorView) mContent;
+    }
 }
diff --git a/src/com/android/contacts/editor/CompactHeaderView.java b/src/com/android/contacts/editor/CompactHeaderView.java
new file mode 100644
index 0000000..f1b37cf
--- /dev/null
+++ b/src/com/android/contacts/editor/CompactHeaderView.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.editor;
+
+import com.android.contacts.R;
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageProvider;
+import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.ContactsUtils;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
+import com.android.contacts.util.ContactPhotoUtils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.DisplayPhoto;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+/**
+ * Displays the primary photo.
+ */
+public class CompactHeaderView extends LinearLayout implements View.OnClickListener {
+
+    private static final String TAG = CompactContactEditorFragment.TAG;
+
+    private ContactPhotoManager mContactPhotoManager;
+    private PhotoHandler mPhotoHandler;
+
+    private ValuesDelta mValuesDelta;
+    private boolean mReadOnly;
+    private boolean mIsPhotoSet;
+
+    private ImageView mPhotoImageView;
+
+    public CompactHeaderView(Context context) {
+        super(context);
+    }
+
+    public CompactHeaderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mContactPhotoManager = ContactPhotoManager.getInstance(getContext());
+
+        mPhotoImageView = (ImageView) findViewById(R.id.photo);
+        mPhotoImageView.setOnClickListener(this);
+    }
+
+    public void setValues(DataKind dataKind, ValuesDelta valuesDelta,
+            RawContactDelta rawContactDelta, boolean readOnly, ViewIdGenerator viewIdGenerator) {
+        mValuesDelta = valuesDelta;
+        mReadOnly = readOnly;
+
+        setId(viewIdGenerator.getId(rawContactDelta, dataKind, valuesDelta, /* viewIndex =*/ 0));
+
+        if (valuesDelta == null) {
+            setDefaultPhoto();
+            return;
+        }
+        final byte[] bytes = valuesDelta.getAsByteArray(Photo.PHOTO);
+        if (bytes == null) {
+            setDefaultPhoto();
+            return;
+        }
+        final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, /* offset =*/ 0, bytes.length);
+        mPhotoImageView.setImageBitmap(bitmap);
+        mIsPhotoSet = true;
+        mValuesDelta.setFromTemplate(false);
+
+        // Check if we can update to the full size photo immediately
+        if (valuesDelta.getAfter() == null || valuesDelta.getAfter().get(Photo.PHOTO) == null) {
+            // If the user hasn't updated the PHOTO value, then PHOTO_FILE_ID may contain
+            // a reference to a larger version of PHOTO that we can bind to the UI.
+            // Otherwise, we need to wait for a call to #setFullSizedPhoto() to update
+            // our full sized image.
+            final Integer fileId = valuesDelta.getAsInteger(Photo.PHOTO_FILE_ID);
+            if (fileId != null) {
+                final Uri photoUri = DisplayPhoto.CONTENT_URI.buildUpon()
+                        .appendPath(fileId.toString()).build();
+                setFullSizedPhoto(photoUri);
+            }
+        }
+    }
+
+    /**
+     * Set the {@link PhotoHandler} to forward clicks (i.e. requests to edit the photo) to.
+     */
+    public void setPhotoHandler(PhotoHandler photoHandler) {
+        mPhotoHandler = photoHandler;
+    }
+
+    /**
+     * Whether a writable {@link Photo} has been set.
+     */
+    public boolean isWritablePhotoSet() {
+        return mIsPhotoSet && !mReadOnly;
+    }
+
+    /**
+     * Returns the View to anchor the PopupWindow with photo edit options to.
+     */
+    public View getPhotoPopupAnchorView() {
+        return mPhotoImageView;
+    }
+
+    /**
+     * Set the given {@link Bitmap} as the photo in the underlying {@link ValuesDelta}
+     * and bind a thumbnail to the UI.
+     */
+    public void setPhoto(Bitmap bitmap) {
+        if (mReadOnly) {
+            Log.w(TAG, "Attempted to set read only photo. Aborting");
+            return;
+        }
+        if (bitmap == null) {
+            mValuesDelta.put(ContactsContract.CommonDataKinds.Photo.PHOTO, (byte[]) null);
+            setDefaultPhoto();
+            return;
+        }
+
+        final int thumbnailSize = ContactsUtils.getThumbnailSize(getContext());
+        final Bitmap scaledBitmap = Bitmap.createScaledBitmap(
+                bitmap, thumbnailSize, thumbnailSize, /* filter =*/ false);
+
+        mPhotoImageView.setImageBitmap(scaledBitmap);
+        mIsPhotoSet = true;
+        mValuesDelta.setFromTemplate(false);
+
+        // When the user chooses a new photo mark it as super primary
+        mValuesDelta.setSuperPrimary(true);
+
+        // Even though high-res photos cannot be saved by passing them via
+        // an EntityDeltaList (since they cause the Bundle size limit to be
+        // exceeded), we still pass a low-res thumbnail. This simplifies
+        // code all over the place, because we don't have to test whether
+        // there is a change in EITHER the delta-list OR a changed photo...
+        // this way, there is always a change in the delta-list.
+        final byte[] compressed = ContactPhotoUtils.compressBitmap(scaledBitmap);
+        if (compressed != null) {
+            mValuesDelta.setPhoto(compressed);
+        }
+    }
+
+    /**
+     * Show the default "add photo" place holder.
+     */
+    private void setDefaultPhoto() {
+        mPhotoImageView.setImageDrawable(ContactPhotoManager.getDefaultAvatarDrawableForContact(
+                getResources(), /* hires =*/ false, /* defaultImageRequest =*/ null));
+        mIsPhotoSet = false;
+        mValuesDelta.setFromTemplate(true);
+    }
+
+    /**
+     * Bind the photo at the given Uri to the UI but do not set the photo on the underlying
+     * {@link ValuesDelta}.
+     */
+    public void setFullSizedPhoto(Uri photoUri) {
+        if (photoUri != null) {
+            final DefaultImageProvider fallbackToPreviousImage = new DefaultImageProvider() {
+                @Override
+                public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
+                        DefaultImageRequest defaultImageRequest) {
+                    // Before we finish setting the full sized image, don't change the current
+                    // image that is set in any way.
+                }
+            };
+            mContactPhotoManager.loadPhoto(mPhotoImageView, photoUri,
+                    mPhotoImageView.getWidth(), /* darkTheme =*/ false, /* isCircular =*/ false,
+                    /* defaultImageRequest =*/ null, fallbackToPreviousImage);
+        }
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (mPhotoHandler != null) {
+            mPhotoHandler.onClick(view);
+        }
+    }
+}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 363fe8b..72cf650 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -25,13 +25,15 @@
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountType.EditField;
 import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
 
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -69,6 +71,7 @@
     private LayoutInflater mLayoutInflater;
     private ViewIdGenerator mViewIdGenerator;
 
+    private CompactHeaderView mHeader;
     private ViewGroup mNames;
     private ViewGroup mPhoneticNames;
     private ViewGroup mNicknames;
@@ -77,6 +80,9 @@
     private ViewGroup mOther;
     private View mMoreFields;
 
+    // TODO: remove this after we handle account selection for photos
+    private long mPhotoRawContactId;
+
     public CompactRawContactsEditorView(Context context) {
         super(context);
     }
@@ -100,6 +106,7 @@
         mLayoutInflater = (LayoutInflater)
                 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
+        mHeader = (CompactHeaderView) findViewById(R.id.header);
         mNames = (LinearLayout) findViewById(R.id.names);
         mPhoneticNames = (LinearLayout) findViewById(R.id.phonetic_names);
         mNicknames = (LinearLayout) findViewById(R.id.nicknames);
@@ -138,6 +145,43 @@
         }
     }
 
+    /**
+     * Pass through to {@link CompactHeaderView#setPhotoHandler}.
+     */
+    public void setPhotoHandler(PhotoHandler photoHandler) {
+        mHeader.setPhotoHandler(photoHandler);
+    }
+
+    /**
+     * Pass through to {@link CompactHeaderView#setPhoto}.
+     */
+    public void setPhoto(Bitmap bitmap) {
+        mHeader.setPhoto(bitmap);
+    }
+
+    /**
+     * Pass through to {@link CompactHeaderView#isWritablePhotoSet}.
+     */
+    public boolean isWritablePhotoSet() {
+        return mHeader.isWritablePhotoSet();
+    }
+
+    /**
+     * Pass through to {@link CompactHeaderView#getPhotoPopupAnchorView}.
+     */
+    public View getPhotoPopupAnchorView() {
+        return mHeader.getPhotoPopupAnchorView();
+    }
+
+
+    /**
+     * Get the raw contact ID for the CompactHeaderView photo.
+     */
+    // TODO: remove me once we support multiple accounts
+    public long getPhotoRawContactId() {
+        return mPhotoRawContactId;
+    }
+
     public void setState(RawContactDeltaList rawContactDeltas, ViewIdGenerator viewIdGenerator) {
         mNames.removeAllViews();
         mPhoneticNames.removeAllViews();
@@ -154,24 +198,48 @@
         setId(mViewIdGenerator.getId(rawContactDeltas.get(0), /* dataKind =*/ null,
                 /* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
 
-        addEditorViews(rawContactDeltas, viewIdGenerator);
+        addHeaderView(rawContactDeltas, viewIdGenerator);
+        addEditorViews(rawContactDeltas);
         removeExtraEmptyTextFields(mNames);
         removeExtraEmptyTextFields(mPhoneNumbers);
         removeExtraEmptyTextFields(mEmails);
     }
 
-    private void addEditorViews(RawContactDeltaList rawContactDeltas,
+    private void addHeaderView(RawContactDeltaList rawContactDeltas,
             ViewIdGenerator viewIdGenerator) {
         for (RawContactDelta rawContactDelta : rawContactDeltas) {
             if (!rawContactDelta.isVisible()) {
                 continue;
             }
-            setId(viewIdGenerator.getId(
-                    rawContactDelta, null, null, ViewIdGenerator.NO_VIEW_INDEX));
-
             final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
 
-            // Make sure we have a StructuredName
+            // Make sure we have a photo
+            RawContactModifier.ensureKindExists(
+                    rawContactDelta, accountType, Photo.CONTENT_ITEM_TYPE);
+
+            final DataKind dataKind = accountType.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
+            if (dataKind != null) {
+                final String mimeType = dataKind.mimeType;
+                if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+                    mPhotoRawContactId = rawContactDelta.getRawContactId();
+                    final ValuesDelta valuesDelta = rawContactDelta.getSuperPrimaryEntry(
+                            mimeType, /* forceSelection =*/ true);
+                    mHeader.setValues(dataKind, valuesDelta, rawContactDelta,
+                            /* readOnly =*/ !dataKind.editable, viewIdGenerator);
+                    return;
+                }
+            }
+        }
+    }
+
+    private void addEditorViews(RawContactDeltaList rawContactDeltas) {
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            if (!rawContactDelta.isVisible()) {
+                continue;
+            }
+            final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+
+            // Make sure we have a structured name
             RawContactModifier.ensureKindExists(
                     rawContactDelta, accountType, StructuredName.CONTENT_ITEM_TYPE);
 
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 03ac880..a1e4554 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -23,7 +23,6 @@
 import com.android.contacts.GroupMetaDataLoader;
 import com.android.contacts.R;
 import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
-import com.android.contacts.activities.ContactEditorActivity;
 import com.android.contacts.activities.ContactEditorBaseActivity;
 import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
 import com.android.contacts.common.model.AccountTypeManager;
@@ -93,7 +92,7 @@
         AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
         CancelEditDialogFragment.Listener {
 
-    protected static final String TAG = "ContactEditor";
+    static final String TAG = "ContactEditor";
 
     protected static final int LOADER_DATA = 1;
     protected static final int LOADER_GROUPS = 2;
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 5bc868a..c87be34 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -469,7 +469,7 @@
     private void setPhoto(long rawContact, Bitmap photo, Uri photoUri) {
         BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
 
-        if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) {
+        if (photo == null || photo.getHeight() <= 0 || photo.getWidth() <= 0) {
             // This is unexpected.
             Log.w(TAG, "Invalid bitmap passed to setPhoto()");
         }