1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.contacts.editor;
18
19import android.content.ContentUris;
20import android.content.Context;
21import android.content.res.Resources;
22import android.net.Uri;
23import android.provider.ContactsContract.CommonDataKinds.Email;
24import android.provider.ContactsContract.CommonDataKinds.Phone;
25import android.provider.ContactsContract.CommonDataKinds.Photo;
26import android.provider.ContactsContract.CommonDataKinds.StructuredName;
27import android.provider.ContactsContract.RawContacts;
28import android.telephony.PhoneNumberUtils;
29import android.text.TextUtils;
30import android.util.AttributeSet;
31import android.view.LayoutInflater;
32import android.view.View;
33import android.view.View.OnClickListener;
34import android.view.ViewGroup;
35import android.widget.Button;
36import android.widget.ImageView;
37import android.widget.TextView;
38import android.widget.Toast;
39
40import com.android.contacts.R;
41import com.android.contacts.common.GeoUtil;
42import com.android.contacts.common.model.RawContactModifier;
43import com.android.contacts.common.model.RawContactDelta;
44import com.android.contacts.common.model.ValuesDelta;
45import com.android.contacts.common.model.account.AccountType;
46import com.android.contacts.common.model.account.AccountWithDataSet;
47import com.android.contacts.common.model.dataitem.DataKind;
48
49import java.util.ArrayList;
50
51/**
52 * Custom view that displays external contacts in the edit screen.
53 */
54public class RawContactReadOnlyEditorView extends BaseRawContactEditorView
55        implements OnClickListener {
56    private LayoutInflater mInflater;
57
58    private TextView mName;
59    private Button mEditExternallyButton;
60    private ViewGroup mGeneral;
61
62    private View mAccountContainer;
63    private ImageView mAccountIcon;
64    private TextView mAccountTypeTextView;
65    private TextView mAccountNameTextView;
66
67    private String mAccountName;
68    private String mAccountType;
69    private String mDataSet;
70    private long mRawContactId = -1;
71
72    private Listener mListener;
73
74    public interface Listener {
75        void onExternalEditorRequest(AccountWithDataSet account, Uri uri);
76    }
77
78    public RawContactReadOnlyEditorView(Context context) {
79        super(context);
80    }
81
82    public RawContactReadOnlyEditorView(Context context, AttributeSet attrs) {
83        super(context, attrs);
84    }
85
86    public void setListener(Listener listener) {
87        mListener = listener;
88    }
89
90    /** {@inheritDoc} */
91    @Override
92    protected void onFinishInflate() {
93        super.onFinishInflate();
94
95        mInflater = (LayoutInflater)getContext().getSystemService(
96                Context.LAYOUT_INFLATER_SERVICE);
97
98        mName = (TextView) findViewById(R.id.read_only_name);
99        mEditExternallyButton = (Button) findViewById(R.id.button_edit_externally);
100        mEditExternallyButton.setOnClickListener(this);
101        mGeneral = (ViewGroup)findViewById(R.id.sect_general);
102
103        mAccountContainer = findViewById(R.id.account_container);
104        mAccountIcon = (ImageView) findViewById(R.id.account_icon);
105        mAccountTypeTextView = (TextView) findViewById(R.id.account_type);
106        mAccountNameTextView = (TextView) findViewById(R.id.account_name);
107    }
108
109    /**
110     * Set the internal state for this view, given a current
111     * {@link RawContactDelta} state and the {@link AccountType} that
112     * apply to that state.
113     */
114    @Override
115    public void setState(RawContactDelta state, AccountType type, ViewIdGenerator vig,
116            boolean isProfile) {
117        // Remove any existing sections
118        mGeneral.removeAllViews();
119
120        // Bail if invalid state or source
121        if (state == null || type == null) return;
122
123        // Make sure we have StructuredName
124        RawContactModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
125
126        // Fill in the header info
127        mAccountName = state.getAccountName();
128        mAccountType = state.getAccountType();
129        mDataSet = state.getDataSet();
130
131        if (isProfile) {
132            if (TextUtils.isEmpty(mAccountName)) {
133                mAccountNameTextView.setVisibility(View.GONE);
134                mAccountTypeTextView.setText(R.string.local_profile_title);
135            } else {
136                CharSequence accountType = type.getDisplayLabel(mContext);
137                mAccountTypeTextView.setText(mContext.getString(R.string.external_profile_title,
138                        accountType));
139                mAccountNameTextView.setText(mAccountName);
140            }
141        } else {
142            CharSequence accountType = type.getDisplayLabel(mContext);
143            if (TextUtils.isEmpty(accountType)) {
144                accountType = mContext.getString(R.string.account_phone);
145            }
146            if (!TextUtils.isEmpty(mAccountName)) {
147                mAccountNameTextView.setVisibility(View.VISIBLE);
148                mAccountNameTextView.setText(
149                        mContext.getString(R.string.from_account_format, mAccountName));
150            } else {
151                // Hide this view so the other text view will be centered vertically
152                mAccountNameTextView.setVisibility(View.GONE);
153            }
154            mAccountTypeTextView.setText(mContext.getString(R.string.account_type_format,
155                    accountType));
156        }
157        mAccountTypeTextView.setTextColor(mContext.getResources().getColor(
158                R.color.secondary_text_color));
159
160        // TODO: Expose data set in the UI somehow?
161
162        mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
163
164        mRawContactId = state.getRawContactId();
165
166        ValuesDelta primary;
167
168        // Photo
169        DataKind kind = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
170        if (kind != null) {
171            RawContactModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
172            boolean hasPhotoEditor = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null;
173            setHasPhotoEditor(hasPhotoEditor);
174            primary = state.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
175            getPhotoEditor().setValues(kind, primary, state, !type.areContactsWritable(), vig);
176        }
177
178        // Name
179        primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
180        mName.setText(primary != null ? primary.getAsString(StructuredName.DISPLAY_NAME) :
181                mContext.getString(R.string.missing_name));
182
183        if (type.getEditContactActivityClassName() != null) {
184            mAccountContainer.setBackgroundDrawable(null);
185            mAccountContainer.setEnabled(false);
186            mEditExternallyButton.setVisibility(View.VISIBLE);
187        } else {
188            mAccountContainer.setOnClickListener(new OnClickListener() {
189                @Override
190                public void onClick(View v) {
191                    Toast.makeText(mContext, mContext.getString(R.string.contact_read_only),
192                            Toast.LENGTH_SHORT).show();
193                }
194            });
195            mEditExternallyButton.setVisibility(View.GONE);
196        }
197
198        final Resources res = mContext.getResources();
199        // Phones
200        ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
201        if (phones != null) {
202            boolean isFirstPhoneBound = true;
203            for (ValuesDelta phone : phones) {
204                final String phoneNumber = phone.getPhoneNumber();
205                if (TextUtils.isEmpty(phoneNumber)) {
206                    continue;
207                }
208                final String formattedNumber = PhoneNumberUtils.formatNumber(
209                        phoneNumber, phone.getPhoneNormalizedNumber(),
210                        GeoUtil.getCurrentCountryIso(getContext()));
211                CharSequence phoneType = null;
212                if (phone.phoneHasType()) {
213                    phoneType = Phone.getTypeLabel(
214                            res, phone.getPhoneType(), phone.getPhoneLabel());
215                }
216                bindData(mContext.getText(R.string.phoneLabelsGroup), formattedNumber,
217                        phoneType, isFirstPhoneBound, true);
218                isFirstPhoneBound = false;
219            }
220        }
221
222        // Emails
223        ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
224        if (emails != null) {
225            boolean isFirstEmailBound = true;
226            for (ValuesDelta email : emails) {
227                final String emailAddress = email.getEmailData();
228                if (TextUtils.isEmpty(emailAddress)) {
229                    continue;
230                }
231                CharSequence emailType = null;
232                if (email.emailHasType()) {
233                    emailType = Email.getTypeLabel(
234                            res, email.getEmailType(), email.getEmailLabel());
235                }
236                bindData(mContext.getText(R.string.emailLabelsGroup), emailAddress, emailType,
237                        isFirstEmailBound);
238                isFirstEmailBound = false;
239            }
240        }
241
242        // Hide mGeneral if it's empty
243        if (mGeneral.getChildCount() > 0) {
244            mGeneral.setVisibility(View.VISIBLE);
245        } else {
246            mGeneral.setVisibility(View.GONE);
247        }
248    }
249
250    private void bindData(CharSequence titleText, CharSequence data, CharSequence type,
251            boolean isFirstEntry) {
252        bindData(titleText, data, type, isFirstEntry, false);
253    }
254
255    private void bindData(CharSequence titleText, CharSequence data, CharSequence type,
256            boolean isFirstEntry, boolean forceLTR) {
257        final View field = mInflater.inflate(R.layout.item_read_only_field, mGeneral, false);
258        final View divider = field.findViewById(R.id.divider);
259        if (isFirstEntry) {
260            final TextView titleView = (TextView) field.findViewById(R.id.kind_title);
261            titleView.setText(titleText);
262            divider.setVisibility(View.GONE);
263        } else {
264            View titleContainer = field.findViewById(R.id.kind_title_layout);
265            titleContainer.setVisibility(View.GONE);
266            divider.setVisibility(View.VISIBLE);
267        }
268        final TextView dataView = (TextView) field.findViewById(R.id.data);
269        dataView.setText(data);
270        if (forceLTR) {
271            dataView.setTextDirection(View.TEXT_DIRECTION_LTR);
272        }
273        final TextView typeView = (TextView) field.findViewById(R.id.type);
274        if (!TextUtils.isEmpty(type)) {
275            typeView.setText(type);
276        } else {
277            typeView.setVisibility(View.GONE);
278        }
279
280        mGeneral.addView(field);
281    }
282
283    @Override
284    public long getRawContactId() {
285        return mRawContactId;
286    }
287
288    @Override
289    public void onClick(View v) {
290        if (v.getId() == R.id.button_edit_externally) {
291            if (mListener != null) {
292                mListener.onExternalEditorRequest(
293                        new AccountWithDataSet(mAccountName, mAccountType, mDataSet),
294                        ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactId));
295            }
296        }
297    }
298}
299