OSDN Git Service

Fix up photo editing, and few other tweaks to contact editing.
authorJeff Hamilton <jham@android.com>
Fri, 9 Oct 2009 00:46:26 +0000 (19:46 -0500)
committerJeff Hamilton <jham@android.com>
Fri, 9 Oct 2009 04:33:58 +0000 (23:33 -0500)
- When tapping a photo you're given a choice to replace, remove, or use as primary
- Fix an issue where the secondary group would show when it shouldn't
- Tweak the size of the color bar per Chris
- Format phone numbers when typing them
- Fix a display issue with contacts that didn't fill the height of the screen
- If a contact is read-only and doesn't have a photo don't offer the option to add one

Bugs: 2163109 & 2163519
Change-Id: I700622d9dfdbcaa81e5b577fd5b2a38d708374aa

res/layout/item_contact_editor.xml
res/values-es-rUS/strings.xml
res/values/strings.xml
src/com/android/contacts/ui/EditContactActivity.java
src/com/android/contacts/ui/widget/ContactEditorView.java
src/com/android/contacts/ui/widget/GenericEditorView.java
src/com/android/contacts/ui/widget/PhotoEditorView.java

index c40352d..76f063e 100644 (file)
@@ -25,7 +25,7 @@
     <!-- Left side color bar -->
     <ImageView
         android:id="@+id/color_bar"
-        android:layout_width="5dip"
+        android:layout_width="4dip"
         android:layout_height="fill_parent"
     />
 
 
         <View android:id="@+id/head_secondary_divider"
             android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
+            android:layout_height="1px"
             android:background="?android:attr/listDivider" />
 
         <TextView
index 0cc1605..940cb34 100644 (file)
     <string name="send_to_voicemail_view" msgid="9124400414311776864">"Las llamadas se envían directamente a un correo de voz."</string>
     <string name="default_ringtone" msgid="9099988849649827972">"Predeterminado"</string>
     <string name="addPicture" msgid="1594679312161537678">"Agregar ícono"</string>
+    <string name="changePicture">Cambiar icono</string>
     <string name="removePicture" msgid="3041230993155966350">"Eliminar ícono"</string>
     <string name="noContacts" msgid="8579310973261953559">"No hay contactos."</string>
     <string name="noMatchingContacts" msgid="4266283206853990471">"No se encontraron contactos coincidentes."</string>
index 4e311f9..e37c118 100644 (file)
     <!-- The button/menu item that allows you to add a picture to a contact -->
     <string name="addPicture">Add icon</string>
 
+    <!-- The button/menu item that allows you to change an existing contact picture -->
+    <string name="changePicture">Change icon</string>
+
     <!-- The menu item that allows you to remove a picture from a contact -->
     <string name="removePicture">Remove icon</string>
 
index 3b06a48..5621ef2 100644 (file)
@@ -26,9 +26,11 @@ import com.android.contacts.model.EntityModifier;
 import com.android.contacts.model.EntitySet;
 import com.android.contacts.model.GoogleSource;
 import com.android.contacts.model.Sources;
+import com.android.contacts.model.ContactsSource.EditType;
 import com.android.contacts.model.Editor.EditorListener;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.ui.widget.ContactEditorView;
+import com.android.contacts.ui.widget.PhotoEditorView;
 import com.android.contacts.util.EmptyService;
 import com.android.contacts.util.WeakAsyncTask;
 import com.google.android.collect.Lists;
@@ -81,6 +83,7 @@ import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.List;
 
 /**
  * Activity for editing or inserting a contact.
@@ -344,19 +347,9 @@ public final class EditContactActivity extends Activity
 
             ContactEditorView editor = (ContactEditorView) inflater.inflate(
                     R.layout.item_contact_editor, mContent, false);
-            editor.getPhotoEditor().setEditorListener(new EditorListener() {
-
-                public void onDeleted(Editor editor) {
-                }
-
-                public void onRequest(int request) {
-                    if (!hasValidState()) return;
-
-                    if (request == EditorListener.REQUEST_PICK_PHOTO) {
-                        doPickPhotoAction(rawContactId);
-                    }
-                }
-            });
+            PhotoEditorView photoEditor = editor.getPhotoEditor();
+            photoEditor.setEditorListener(new PhotoListener(rawContactId, source.readOnly,
+                    photoEditor));
 
             mContent.addView(editor);
             editor.setState(entity, source);
@@ -366,6 +359,107 @@ public final class EditContactActivity extends Activity
         mContent.setVisibility(View.VISIBLE);
     }
 
+    /**
+     * Class that listens to requests coming from photo editors
+     */
+    private class PhotoListener implements EditorListener, DialogInterface.OnClickListener {
+        private long mRawContactId;
+        private boolean mReadOnly;
+        private PhotoEditorView mEditor;
+
+        public PhotoListener(long rawContactId, boolean readOnly, PhotoEditorView editor) {
+            mRawContactId = rawContactId;
+            mReadOnly = readOnly;
+            mEditor = editor;
+        }
+
+        public void onDeleted(Editor editor) {
+            // Do nothing
+        }
+
+        public void onRequest(int request) {
+            if (!hasValidState()) return;
+
+            if (request == EditorListener.REQUEST_PICK_PHOTO) {
+                if (mEditor.hasSetPhoto()) {
+                    // There is an existing photo, offer to remove, replace, or promoto to primary
+                    createPhotoDialog().show();
+                } else if (!mReadOnly) {
+                    // No photo set and not read-only, try to set the photo
+                    doPickPhotoAction(mRawContactId);
+                }
+            }
+        }
+
+        /**
+         * Prepare dialog for picking a new {@link EditType} or entering a
+         * custom label. This dialog is limited to the valid types as determined
+         * by {@link EntityModifier}.
+         */
+        public Dialog createPhotoDialog() {
+            Context context = EditContactActivity.this;
+
+            // Wrap our context to inflate list items using correct theme
+            final Context dialogContext = new ContextThemeWrapper(context,
+                    android.R.style.Theme_Light);
+
+            String[] choices;
+            if (mReadOnly) {
+                choices = new String[1];
+                choices[0] = getString(R.string.use_photo_as_primary);
+            } else {
+                choices = new String[3];
+                choices[0] = getString(R.string.use_photo_as_primary);
+                choices[1] = getString(R.string.removePicture);
+                choices[2] = getString(R.string.changePicture);
+            }
+            final ListAdapter adapter = new ArrayAdapter<String>(dialogContext,
+                    android.R.layout.simple_list_item_1, choices);
+
+            final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);
+            builder.setTitle(R.string.attachToContact);
+            builder.setSingleChoiceItems(adapter, -1, this);
+            return builder.create();
+        }
+
+        /**
+         * Called when something in the dialog is clicked
+         */
+        public void onClick(DialogInterface dialog, int which) {
+            dialog.dismiss();
+
+            switch (which) {
+                case 0:
+                    // Set the photo as super primary
+                    mEditor.setSuperPrimary(true);
+
+                    // And set all other photos as not super primary
+                    int count = mContent.getChildCount();
+                    for (int i = 0; i < count; i++) {
+                        View childView = mContent.getChildAt(i);
+                        if (childView instanceof ContactEditorView) {
+                            ContactEditorView editor = (ContactEditorView) childView;
+                            PhotoEditorView photoEditor = editor.getPhotoEditor();
+                            if (!photoEditor.equals(mEditor)) {
+                                photoEditor.setSuperPrimary(false);
+                            }
+                        }
+                    }
+                    break;
+
+                case 1:
+                    // Remove the photo
+                    mEditor.setPhotoBitmap(null);
+                    break;
+
+                case 2:
+                    // Pick a new photo for the contact
+                    doPickPhotoAction(mRawContactId);
+                    break;
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     public void onClick(View view) {
         switch (view.getId()) {
index 8bd8e4c..53d1faf 100644 (file)
@@ -63,12 +63,14 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
     private TextView mReadOnlyName;
 
     private PhotoEditorView mPhoto;
+    private View mPhotoStub;
     private GenericEditorView mName;
 
     private boolean mHasPhotoEditor = false;
 
     private ViewGroup mGeneral;
     private ViewGroup mSecondary;
+    private boolean mSecondaryVisible;
 
     private TextView mSecondaryHeader;
 
@@ -100,6 +102,7 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
                 Context.LAYOUT_INFLATER_SERVICE);
 
         mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo);
+        mPhotoStub = findViewById(R.id.stub_photo);
 
         final int photoSize = getResources().getDimensionPixelSize(R.dimen.edit_photo_size);
 
@@ -171,6 +174,7 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
         mSecondary.setVisibility(makeVisible ? View.VISIBLE : View.GONE);
         mSecondaryHeader.setCompoundDrawablesWithIntrinsicBounds(makeVisible ? mSecondaryOpen
                 : mSecondaryClosed, null, null, null);
+        mSecondaryVisible = makeVisible;
     }
 
     /**
@@ -218,16 +222,12 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
         // Show and hide the appropriate views
         if (readOnly) {
             mGeneral.setVisibility(View.GONE);
-            mSecondary.setVisibility(View.GONE);
-            mSecondaryHeader.setVisibility(View.GONE);
             mName.setVisibility(View.GONE);
             mReadOnly.setVisibility(View.VISIBLE);
             mReadOnly.setText(mContext.getString(R.string.contact_read_only, accountType));
             mReadOnlyName.setVisibility(View.VISIBLE);
         } else {
             mGeneral.setVisibility(View.VISIBLE);
-            mSecondary.setVisibility(View.VISIBLE);
-            mSecondaryHeader.setVisibility(View.VISIBLE);
             mName.setVisibility(View.VISIBLE);
             mReadOnly.setVisibility(View.GONE);
             mReadOnlyName.setVisibility(View.GONE);
@@ -252,6 +252,11 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
                 // Handle special case editor for photos
                 final ValuesDelta primary = state.getPrimaryEntry(mimeType);
                 mPhoto.setValues(kind, primary, state, source.readOnly);
+                if (readOnly && !mPhoto.hasSetPhoto()) {
+                    mPhotoStub.setVisibility(View.GONE);
+                } else {
+                    mPhotoStub.setVisibility(View.VISIBLE);
+                }
             } else if (!readOnly) {
                 // Otherwise use generic section-based editors
                 if (kind.fieldList == null) continue;
@@ -263,9 +268,20 @@ public class ContactEditorView extends LinearLayout implements OnClickListener {
                 parent.addView(section);
             }
         }
-        final int secondaryVisibility = mSecondary.getChildCount() > 0 ? View.VISIBLE : View.GONE;
-        mSecondary.setVisibility(secondaryVisibility);
-        mSecondaryHeader.setVisibility(secondaryVisibility);
+
+        if (!readOnly && mSecondary.getChildCount() > 0) {
+            // There exist secondary elements, show the header and honor mSecondaryVisible
+            mSecondaryHeader.setVisibility(View.VISIBLE);
+            if (mSecondaryVisible) {
+                mSecondary.setVisibility(View.VISIBLE);
+            } else {
+                mSecondary.setVisibility(View.GONE);
+            }
+        } else {
+            // There are no secondary elements, hide the whole thing
+            mSecondaryHeader.setVisibility(View.GONE);
+            mSecondary.setVisibility(View.GONE);
+        }
     }
 
     /**
index 8b50551..e1fdd71 100644 (file)
@@ -31,8 +31,9 @@ import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Entity;
+import android.telephony.PhoneNumberFormattingTextWatcher;
 import android.text.Editable;
-import android.text.TextUtils;
+import android.text.InputType;
 import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.ContextThemeWrapper;
@@ -200,7 +201,11 @@ public class GenericEditorView extends RelativeLayout implements Editor, View.On
             if (field.titleRes > 0) {
                 fieldView.setHint(field.titleRes);
             }
-            fieldView.setInputType(field.inputType);
+            int inputType = field.inputType;
+            fieldView.setInputType(inputType);
+            if (inputType == InputType.TYPE_CLASS_PHONE) {
+                fieldView.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
+            }
             fieldView.setMinLines(field.minLines);
 
             // Read current value from state
index 7dfe3d7..f117091 100644 (file)
@@ -45,6 +45,7 @@ public class PhotoEditorView extends ImageView implements Editor, OnClickListene
     private EditorListener mListener;
 
     private boolean mHasSetPhoto = false;
+    private boolean mReadOnly;
 
     public PhotoEditorView(Context context) {
         super(context);
@@ -76,6 +77,7 @@ public class PhotoEditorView extends ImageView implements Editor, OnClickListene
     /** {@inheritDoc} */
     public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly) {
         mEntry = values;
+        mReadOnly = readOnly;
         if (values != null) {
             // Try decoding photo if actual entry
             final byte[] photoBytes = values.getAsByteArray(Photo.PHOTO);
@@ -85,7 +87,7 @@ public class PhotoEditorView extends ImageView implements Editor, OnClickListene
 
                 setScaleType(ImageView.ScaleType.CENTER_CROP);
                 setImageBitmap(photo);
-               setEnabled(!readOnly);
+                setEnabled(true);
                 mHasSetPhoto = true;
                 mEntry.setFromTemplate(false);
             } else {
@@ -125,17 +127,34 @@ public class PhotoEditorView extends ImageView implements Editor, OnClickListene
 
             mEntry.put(Photo.PHOTO, out.toByteArray());
             setImageBitmap(photo);
+            setEnabled(true);
             mHasSetPhoto = true;
             mEntry.setFromTemplate(false);
+
+            // When the user chooses a new photo mark it as super primary
+            mEntry.put(Photo.IS_SUPER_PRIMARY, 1);
         } catch (IOException e) {
             Log.w(TAG, "Unable to serialize photo: " + e.toString());
         }
     }
 
+    /**
+     * Set the super primary bit on the photo.
+     */
+    public void setSuperPrimary(boolean superPrimary) {
+        mEntry.put(Photo.IS_SUPER_PRIMARY, superPrimary ? 1 : 0);
+    }
+
     protected void resetDefault() {
         // Invalid photo, show default "add photo" place-holder
         setScaleType(ImageView.ScaleType.CENTER);
-        setImageResource(R.drawable.ic_menu_add_picture);
+        if (mReadOnly) {
+            setImageResource(R.drawable.ic_contact_picture);
+            setEnabled(false);
+        } else {
+            setImageResource(R.drawable.ic_menu_add_picture);
+            setEnabled(true);
+        }
         mHasSetPhoto = false;
         mEntry.setFromTemplate(true);
     }