1392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/*
2392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
4392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * you may not use this file except in compliance with the License.
6392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * You may obtain a copy of the License at
7392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
8392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann *
10392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * See the License for the specific language governing permissions and
14392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann * limitations under the License.
15392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
16392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
19392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.app.AlertDialog;
20392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.app.Dialog;
21392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.Context;
22392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.content.DialogInterface;
23a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmannimport android.content.DialogInterface.OnShowListener;
24392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.os.Bundle;
2579c9c5a8f849908d2b141c30af15923ea2b60f5bDaniel Lehmannimport android.os.Handler;
26a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmannimport android.text.Editable;
2711bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikovimport android.text.TextUtils;
28a3e69af03dd35124941a48c3bfaea87468d66863Katherine Kuanimport android.text.TextUtils.TruncateAt;
29e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport android.text.TextWatcher;
30392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.util.AttributeSet;
31a66642330b5c4a62c8b7ce438ccff57c3b017eb1Katherine Kuanimport android.view.Gravity;
322fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.view.LayoutInflater;
33392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.View;
34392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.ViewGroup;
35a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmannimport android.view.WindowManager;
36392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.view.inputmethod.EditorInfo;
372fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.AdapterView;
382fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.AdapterView.OnItemSelectedListener;
392fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.ArrayAdapter;
40a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmannimport android.widget.Button;
41392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmannimport android.widget.EditText;
4212a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuanimport android.widget.ImageView;
4363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuanimport android.widget.LinearLayout;
442fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.Spinner;
452fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikovimport android.widget.TextView;
46392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
47e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
48cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.RawContactDelta;
49cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.ContactsUtils;
50738ff8623dc77dd91a1b9023861e924ba5e4c27eChiao Chengimport com.android.contacts.common.model.ValuesDelta;
51cd321f65f1e50409812976380ad1f0fdb3fa35cbYorke Leeimport com.android.contacts.common.model.RawContactModifier;
52428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.account.AccountType.EditType;
53428f008513d1591cc08fcfe2cf0c9237fb313241Chiao Chengimport com.android.contacts.common.model.dataitem.DataKind;
54e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.DialogManager;
55e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.DialogManager.DialogShowingView;
56e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
5714918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikovimport java.util.List;
5814918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov
59392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann/**
6063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan * Base class for editors that handles labels and values. Uses
61851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu * {@link ValuesDelta} to read any existing {@link RawContact} values, and to
6263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan * correctly write any changes values.
63392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann */
6463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuanpublic abstract class LabeledEditorView extends LinearLayout implements Editor, DialogShowingView {
65392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected static final String DIALOG_ID_KEY = "dialog_id";
66392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int DIALOG_ID_CUSTOM = 1;
67392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
68392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private static final int INPUT_TYPE_CUSTOM = EditorInfo.TYPE_CLASS_TEXT
69392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS;
70392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
712fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private Spinner mLabel;
722fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private EditTypeAdapter mEditTypeAdapter;
7363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    private View mDeleteContainer;
7412a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    private ImageView mDelete;
75392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
76392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DataKind mKind;
77392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private ValuesDelta mEntry;
78851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private RawContactDelta mState;
79392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private boolean mReadOnly;
802591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan    private boolean mWasEmpty = true;
815e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan    private boolean mIsDeletable = true;
822293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    private boolean mIsAttachedToWindow;
83392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
84392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EditType mType;
85392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
86392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
87392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DialogManager mDialogManager = null;
88392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private EditorListener mListener;
8991d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    protected int mMinLineItemHeight;
90392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
912fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    /**
922fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov     * A marker in the spinner adapter of the currently selected custom type.
932fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov     */
942fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    public static final EditType CUSTOM_SELECTION = new EditType(0, 0);
952fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
962fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private OnItemSelectedListener mSpinnerListener = new OnItemSelectedListener() {
972fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
982fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
992fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public void onItemSelected(
1002fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                AdapterView<?> parent, View view, int position, long id) {
1012fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            onTypeSelectionChange(position);
1022fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
1032fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
1042fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
1052fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public void onNothingSelected(AdapterView<?> parent) {
1062fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
1072fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    };
1082fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
109392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context) {
110392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context);
11191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
112392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
113392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
114392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context, AttributeSet attrs) {
115392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs);
11691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
117392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
118392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
119392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public LabeledEditorView(Context context, AttributeSet attrs, int defStyle) {
120392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        super(context, attrs, defStyle);
12191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        init(context);
12291d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
12391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
12491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    private void init(Context context) {
12591d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov        mMinLineItemHeight = context.getResources().getDimensionPixelSize(
12691d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov                R.dimen.editor_min_line_item_height);
127392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
128392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
12963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    /** {@inheritDoc} */
13063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    @Override
13163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    protected void onFinishInflate() {
13202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
13363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mLabel = (Spinner) findViewById(R.id.spinner);
13467713b3e6e3af70020350e2650738389f19c073eDaniel Lehmann        // Turn off the Spinner's own state management. We do this ourselves on rotation
13567713b3e6e3af70020350e2650738389f19c073eDaniel Lehmann        mLabel.setId(View.NO_ID);
13663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mLabel.setOnItemSelectedListener(mSpinnerListener);
13791d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
13812a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mDelete = (ImageView) findViewById(R.id.delete_button);
13963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mDeleteContainer = findViewById(R.id.delete_button_container);
14012a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan        mDeleteContainer.setOnClickListener(new OnClickListener() {
14163ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            @Override
14263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            public void onClick(View v) {
14363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                // defer removal of this button so that the pressed state is visible shortly
14463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                new Handler().post(new Runnable() {
14563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    @Override
14663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    public void run() {
1472293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // Don't do anything if the view is no longer attached to the window
1482293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // (This check is needed because when this {@link Runnable} is executed,
1492293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // we can't guarantee the view is still valid.
1502293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        if (!mIsAttachedToWindow) {
1512293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                            return;
1522293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        }
1532293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // Send the delete request to the listener (which will in turn call
1542293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // deleteEditor() on this view if the deletion is valid - i.e. this is not
1552293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                        // the last {@link Editor} in the section).
15663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                        if (mListener != null) {
1572293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                            mListener.onDeleteRequested(LabeledEditorView.this);
15863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                        }
15963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                    }
16063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan                });
16191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov            }
16263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        });
16391d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
16491d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
1652293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    @Override
1662293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    protected void onAttachedToWindow() {
1672293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        super.onAttachedToWindow();
1682293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // Keep track of when the view is attached or detached from the window, so we know it's
1692293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // safe to remove views (in case the user requests to delete this editor).
1702293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        mIsAttachedToWindow = true;
1712293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    }
1722293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan
1732293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    @Override
1742293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    protected void onDetachedFromWindow() {
1752293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        super.onDetachedFromWindow();
1762293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        mIsAttachedToWindow = false;
1772293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    }
1782293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan
1792293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    @Override
1802293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    public void deleteEditor() {
1812293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // Keep around in model, but mark as deleted
1822293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        mEntry.markDeleted();
1832293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan
1842293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        // Remove the view
185ca87e9c598929b5b6a62da9b80d2114168e24274Daniel Lehmann        EditorAnimator.getInstance().removeEditorView(this);
1862293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan    }
1872293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan
18863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    public boolean isReadOnly() {
18963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        return mReadOnly;
19091d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov    }
19191d8e892d549bbeba721cb434163a83bc99330a9Dmitri Plotnikov
19263ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan    public int getBaseline(int row) {
19363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        if (row == 0 && mLabel != null) {
19463ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            return mLabel.getBaseline();
195392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
19663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        return -1;
197392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
198392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
199392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
200a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan     * Configures the visibility of the type label button and enables or disables it properly.
201392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
202392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void setupLabelButton(boolean shouldExist) {
20363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        if (shouldExist) {
20402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mLabel.setEnabled(!mReadOnly && isEnabled());
20563ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            mLabel.setVisibility(View.VISIBLE);
20663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        } else {
20763ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            mLabel.setVisibility(View.GONE);
208392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
209392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
210392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
211392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
212a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan     * Configures the visibility of the "delete" button and enables or disables it properly.
213392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
2145e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan    private void setupDeleteButton() {
2155e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        if (mIsDeletable) {
21663ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            mDeleteContainer.setVisibility(View.VISIBLE);
21702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mDelete.setEnabled(!mReadOnly && isEnabled());
21863ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        } else {
21963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan            mDeleteContainer.setVisibility(View.GONE);
220392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
221392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
222392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
2235e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan    public void setDeleteButtonVisible(boolean visible) {
2245e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        if (mIsDeletable) {
225a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan            mDeleteContainer.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
2265e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        }
2275e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan    }
2285e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan
229392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onOptionalFieldVisibilityChange() {
230392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mListener != null) {
231392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mListener.onRequest(EditorListener.EDITOR_FORM_CHANGED);
232392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
233392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
234392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
235392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
236392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setEditorListener(EditorListener listener) {
237392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mListener = listener;
238392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
239392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
240392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
241392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setDeletable(boolean deletable) {
2425e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        mIsDeletable = deletable;
2435e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan        setupDeleteButton();
244392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
245392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
246392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
247392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void setEnabled(boolean enabled) {
24802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        super.setEnabled(enabled);
24963ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mLabel.setEnabled(!mReadOnly && enabled);
25063ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mDelete.setEnabled(!mReadOnly && enabled);
251392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
252392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
2532fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    public Spinner getLabel() {
254392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mLabel;
255392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
256392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
25712a93637e406ba7f3da4db8d53cd035c2c1d6e6eKatherine Kuan    public ImageView getDelete() {
258392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mDelete;
259392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
260392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
261392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected DataKind getKind() {
262392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mKind;
263392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
264392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
265392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected ValuesDelta getEntry() {
266392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mEntry;
267392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
268392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
269392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected EditType getType() {
270392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mType;
271392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
272392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
273392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
274392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Build the current label state based on selected {@link EditType} and
275392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * possible custom label string.
276392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
277392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void rebuildLabel() {
2782fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        mEditTypeAdapter = new EditTypeAdapter(mContext);
2792fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        mLabel.setAdapter(mEditTypeAdapter);
2802fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mEditTypeAdapter.hasCustomSelection()) {
2812fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel.setSelection(mEditTypeAdapter.getPosition(CUSTOM_SELECTION));
2822fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        } else {
2832fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mLabel.setSelection(mEditTypeAdapter.getPosition(mType));
284392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
285392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
286392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
287392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
288392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public void onFieldChanged(String column, String value) {
28911bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov        if (!isFieldChanged(column, value)) {
2907d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov            return;
2917d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov        }
2927d4a8dda946f5c013573e4d6601fc14c03156ba6Dmitri Plotnikov
293392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Field changes are saved directly
294e55faef88185628c842e0aa778d883f209323630Katherine Kuan        saveValue(column, value);
295e55faef88185628c842e0aa778d883f209323630Katherine Kuan
296e55faef88185628c842e0aa778d883f209323630Katherine Kuan        // Notify listener if applicable
297e55faef88185628c842e0aa778d883f209323630Katherine Kuan        notifyEditorListener();
298e55faef88185628c842e0aa778d883f209323630Katherine Kuan    }
299e55faef88185628c842e0aa778d883f209323630Katherine Kuan
300e55faef88185628c842e0aa778d883f209323630Katherine Kuan    protected void saveValue(String column, String value) {
301392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mEntry.put(column, value);
302e55faef88185628c842e0aa778d883f209323630Katherine Kuan    }
303e55faef88185628c842e0aa778d883f209323630Katherine Kuan
304e55faef88185628c842e0aa778d883f209323630Katherine Kuan    protected void notifyEditorListener() {
305392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mListener != null) {
306392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mListener.onRequest(EditorListener.FIELD_CHANGED);
307392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
3082591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan
3092591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        boolean isEmpty = isEmpty();
3102591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        if (mWasEmpty != isEmpty) {
3112591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            if (isEmpty) {
31237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (mListener != null) {
31337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    mListener.onRequest(EditorListener.FIELD_TURNED_EMPTY);
31437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
315a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                if (mIsDeletable) mDeleteContainer.setVisibility(View.INVISIBLE);
3162591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            } else {
31737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (mListener != null) {
31837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    mListener.onRequest(EditorListener.FIELD_TURNED_NON_EMPTY);
31937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
3205e330ed98f1c2711b4cd3b375a1c0f76bedaf3e1Katherine Kuan                if (mIsDeletable) mDeleteContainer.setVisibility(View.VISIBLE);
3212591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            }
3222591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan            mWasEmpty = isEmpty;
3232591436971bad3050c85929c8e0c5a8d48111f88Katherine Kuan        }
324392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
325392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
32611bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov    protected boolean isFieldChanged(String column, String value) {
32760b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String dbValue = mEntry.getAsString(column);
32860b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        // nullable fields (e.g. Middle Name) are usually represented as empty columns,
32960b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        // so lets treat null and empty space equivalently here
33060b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String dbValueNoNull = dbValue == null ? "" : dbValue;
33160b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        final String valueNoNull = value == null ? "" : value;
33260b239c24c05233bbf3f7cb45697252e15ec76ccDaniel Lehmann        return !TextUtils.equals(dbValueNoNull, valueNoNull);
33311bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov    }
33411bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov
335392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void rebuildValues() {
336392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setValues(mKind, mEntry, mState, mReadOnly, mViewIdGenerator);
337392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
338392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
339392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
340392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Prepare this editor using the given {@link DataKind} for defining
341392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * structure and {@link ValuesDelta} describing the content to edit.
342392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
343392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
344851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
345392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            ViewIdGenerator vig) {
346392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mKind = kind;
347392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mEntry = entry;
348392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mState = state;
349392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mReadOnly = readOnly;
350392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        mViewIdGenerator = vig;
351392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setId(vig.getId(state, kind, entry, ViewIdGenerator.NO_VIEW_INDEX));
352392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
353392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (!entry.isVisible()) {
354392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            // Hide ourselves entirely if deleted
355392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            setVisibility(View.GONE);
356392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            return;
357392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
358392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setVisibility(View.VISIBLE);
359392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
360392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        // Display label selector if multiple types available
361851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final boolean hasTypes = RawContactModifier.hasEditTypes(kind);
362392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        setupLabelButton(hasTypes);
36363ffb90935d8aec295e4a8f62af6c77dafe1899fKatherine Kuan        mLabel.setEnabled(!readOnly && isEnabled());
364392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (hasTypes) {
365851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            mType = RawContactModifier.getCurrentType(entry, kind);
366392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            rebuildLabel();
367392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
368392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
369392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
370392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public ValuesDelta getValues() {
371392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mEntry;
372392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
373392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
374392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
375392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Prepare dialog for entering a custom label. The input value is trimmed: white spaces before
376392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * and after the input text is removed.
377392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * <p>
378392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * If the final value is empty, this change request is ignored;
379392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * no empty text is allowed in any custom label.
380392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
381392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private Dialog createCustomDialog() {
382eb765ac75178eccf5a44a3410e21a7f88419fd84Adam Powell        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
383a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        final LayoutInflater layoutInflater = LayoutInflater.from(builder.getContext());
384eb765ac75178eccf5a44a3410e21a7f88419fd84Adam Powell        builder.setTitle(R.string.customLabelPickerTitle);
385eb765ac75178eccf5a44a3410e21a7f88419fd84Adam Powell
386a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        final View view = layoutInflater.inflate(R.layout.contact_editor_label_name_dialog, null);
387a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        final EditText editText = (EditText) view.findViewById(R.id.custom_dialog_content);
388a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        editText.setInputType(INPUT_TYPE_CUSTOM);
389a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        editText.setSaveEnabled(true);
390392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
391a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        builder.setView(view);
392a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        editText.requestFocus();
393392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
394392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
395392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            @Override
396392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            public void onClick(DialogInterface dialog, int which) {
397a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann                final String customText = editText.getText().toString().trim();
398392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                if (ContactsUtils.isGraphic(customText)) {
39914918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    final List<EditType> allTypes =
400851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                            RawContactModifier.getValidTypes(mState, mKind, null);
40114918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    mType = null;
40214918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    for (EditType editType : allTypes) {
40314918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                        if (editType.customColumn != null) {
40414918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                            mType = editType;
40514918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                            break;
40614918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                        }
40714918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    }
40814918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov                    if (mType == null) return;
40914918c07e1cb3b5b190bec4cc9106db7adbba29fDmitri Plotnikov
410392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mEntry.put(mKind.typeColumn, mType.rawValue);
411392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    mEntry.put(mType.customColumn, customText);
412392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    rebuildLabel();
413392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    requestFocusForFirstEditField();
414392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                    onLabelRebuilt();
415392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                }
416392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
417392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        });
418392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
419392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        builder.setNegativeButton(android.R.string.cancel, null);
420392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
421a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        final AlertDialog dialog = builder.create();
422a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        dialog.setOnShowListener(new OnShowListener() {
423a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            @Override
424a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            public void onShow(DialogInterface dialogInterface) {
425a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann                updateCustomDialogOkButtonState(dialog, editText);
426a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            }
427a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        });
428a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        editText.addTextChangedListener(new TextWatcher() {
429a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            @Override
430a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            public void onTextChanged(CharSequence s, int start, int before, int count) {
431a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            }
432a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann
433a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            @Override
434a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
435a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            }
436a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann
437a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            @Override
438a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            public void afterTextChanged(Editable s) {
439a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann                updateCustomDialogOkButtonState(dialog, editText);
440a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann            }
441a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        });
442a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        dialog.getWindow().setSoftInputMode(
443a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
444a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann
445a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        return dialog;
446a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann    }
447a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann
448a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann    /* package */ void updateCustomDialogOkButtonState(AlertDialog dialog, EditText editText) {
449a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
450a04dc9c9ed2812af8f4466c2a5225a37d38d250eDaniel Lehmann        okButton.setEnabled(!TextUtils.isEmpty(editText.getText().toString().trim()));
451392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
452392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
453392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /**
454392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     * Called after the label has changed (either chosen from the list or entered in the Dialog)
455392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann     */
456392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected void onLabelRebuilt() {
457392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
458392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4592fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    protected void onTypeSelectionChange(int position) {
4602fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        EditType selected = mEditTypeAdapter.getItem(position);
4612fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        // See if the selection has in fact changed
4622fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mEditTypeAdapter.hasCustomSelection() && selected == CUSTOM_SELECTION) {
4632fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return;
464392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
465392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4662fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (mType == selected && mType.customColumn == null) {
4672fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return;
4682fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
469392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
4702fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        if (selected.customColumn != null) {
4712fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            showDialog(DIALOG_ID_CUSTOM);
4722fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        } else {
4732fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            // User picked type, and we're sure it's ok to actually write the entry.
4742fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mType = selected;
4752fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mEntry.put(mKind.typeColumn, mType.rawValue);
4762fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            rebuildLabel();
4772fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            requestFocusForFirstEditField();
4782fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            onLabelRebuilt();
4792fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
480392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
481392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
482392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    /* package */
483392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    void showDialog(int bundleDialogId) {
484392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        Bundle bundle = new Bundle();
485392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        bundle.putInt(DIALOG_ID_KEY, bundleDialogId);
486392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        getDialogManager().showDialogInView(this, bundle);
487392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
488392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
489392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private DialogManager getDialogManager() {
490392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (mDialogManager == null) {
491392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            Context context = getContext();
492392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            if (!(context instanceof DialogManager.DialogShowingViewActivity)) {
493392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                throw new IllegalStateException(
494392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        "View must be hosted in an Activity that implements " +
495392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                        "DialogManager.DialogShowingViewActivity");
496392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            }
497392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            mDialogManager = ((DialogManager.DialogShowingViewActivity)context).getDialogManager();
498392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
499392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        return mDialogManager;
500392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
501392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
502392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    @Override
503392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    public Dialog createDialog(Bundle bundle) {
504392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        if (bundle == null) throw new IllegalArgumentException("bundle must not be null");
505392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        int dialogId = bundle.getInt(DIALOG_ID_KEY);
506392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        switch (dialogId) {
507392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            case DIALOG_ID_CUSTOM:
508392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                return createCustomDialog();
509392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            default:
510392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                throw new IllegalArgumentException("Invalid dialogId: " + dialogId);
511392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        }
512392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    }
513392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann
514392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    protected abstract void requestFocusForFirstEditField();
5152fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5162fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    private class EditTypeAdapter extends ArrayAdapter<EditType> {
5172fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private final LayoutInflater mInflater;
5182fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private boolean mHasCustomSelection;
519fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan        private int mTextColor;
5202fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5212fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public EditTypeAdapter(Context context) {
5222fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            super(context, 0);
5232fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
524fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan            mTextColor = context.getResources().getColor(R.color.secondary_text_color);
5252fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5264fa9cd0088de76d83803210b39f373cd980fd846Dmitri Plotnikov            if (mType != null && mType.customColumn != null) {
5272fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5282fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                // Use custom label string when present
5292fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                final String customText = mEntry.getAsString(mType.customColumn);
5302fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                if (customText != null) {
5312fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    add(CUSTOM_SELECTION);
5322fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    mHasCustomSelection = true;
5332fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                }
5342fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
5352fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
536851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            addAll(RawContactModifier.getValidTypes(mState, mKind, mType));
5372fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5382fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5392fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public boolean hasCustomSelection() {
5402fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return mHasCustomSelection;
5412fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5422fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5432fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
5442fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public View getView(int position, View convertView, ViewGroup parent) {
5452fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return createViewFromResource(
5462fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    position, convertView, parent, android.R.layout.simple_spinner_item);
5472fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5482fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5492fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        @Override
5502fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        public View getDropDownView(int position, View convertView, ViewGroup parent) {
5512fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            return createViewFromResource(
5522fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                    position, convertView, parent, android.R.layout.simple_spinner_dropdown_item);
5532fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5542fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5552fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        private View createViewFromResource(int position, View convertView, ViewGroup parent,
5562fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                int resource) {
5572fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            TextView textView;
5582fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5592fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            if (convertView == null) {
560fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                textView = (TextView) mInflater.inflate(resource, parent, false);
561fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                textView.setAllCaps(true);
5627d3b91577f84a4f5092d28ed0f3cfe7e0df32696Fabrice Di Meglio                textView.setGravity(Gravity.END | Gravity.CENTER_VERTICAL);
563fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                textView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
564fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                textView.setTextColor(mTextColor);
565a3e69af03dd35124941a48c3bfaea87468d66863Katherine Kuan                textView.setEllipsize(TruncateAt.MIDDLE);
5662fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            } else {
567fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                textView = (TextView) convertView;
5682fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
5692fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov
5702fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            EditType type = getItem(position);
5712fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            String text;
5722fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            if (type == CUSTOM_SELECTION) {
5732fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                text = mEntry.getAsString(mType.customColumn);
5742fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            } else {
5752fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov                text = getContext().getString(type.labelRes);
5762fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov            }
577fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan            textView.setText(text);
578fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan            return textView;
5792fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov        }
5802fcfa499dd44f62dc63636e363522354e13aa20dDmitri Plotnikov    }
581392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann}
582