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