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.text.TextUtils;
29 import android.util.AttributeSet;
30 import android.util.Pair;
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.compat.PhoneNumberUtilsCompat;
42 import com.android.contacts.common.model.RawContactModifier;
43 import com.android.contacts.common.model.RawContactDelta;
44 import com.android.contacts.common.model.ValuesDelta;
45 import com.android.contacts.common.model.account.AccountType;
46 import com.android.contacts.common.model.account.AccountWithDataSet;
47 import com.android.contacts.common.model.dataitem.DataKind;
48 
49 import java.util.ArrayList;
50 
51 /**
52  * Custom view that displays external contacts in the edit screen.
53  */
54 public 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 TextView mAccountHeaderTypeTextView;
63     private TextView mAccountHeaderNameTextView;
64     private ImageView mAccountIconImageView;
65 
66     private String mAccountName;
67     private String mAccountType;
68     private String mDataSet;
69     private long mRawContactId = -1;
70 
RawContactReadOnlyEditorView(Context context)71     public RawContactReadOnlyEditorView(Context context) {
72         super(context);
73     }
74 
RawContactReadOnlyEditorView(Context context, AttributeSet attrs)75     public RawContactReadOnlyEditorView(Context context, AttributeSet attrs) {
76         super(context, attrs);
77     }
78 
79 
80     /** {@inheritDoc} */
81     @Override
onFinishInflate()82     protected void onFinishInflate() {
83         super.onFinishInflate();
84 
85         mInflater = (LayoutInflater)getContext().getSystemService(
86                 Context.LAYOUT_INFLATER_SERVICE);
87 
88         mName = (TextView) findViewById(R.id.read_only_name);
89         mEditExternallyButton = (Button) findViewById(R.id.button_edit_externally);
90         mEditExternallyButton.setOnClickListener(this);
91         mGeneral = (ViewGroup)findViewById(R.id.sect_general);
92 
93         mAccountHeaderTypeTextView = (TextView) findViewById(R.id.account_type);
94         mAccountHeaderNameTextView = (TextView) findViewById(R.id.account_name);
95         mAccountIconImageView = (ImageView) findViewById(android.R.id.icon);
96     }
97 
98     /**
99      * Set the internal state for this view, given a current
100      * {@link RawContactDelta} state and the {@link AccountType} that
101      * apply to that state.
102      */
103     @Override
setState(RawContactDelta state, AccountType type, ViewIdGenerator vig, boolean isProfile)104     public void setState(RawContactDelta state, AccountType type, ViewIdGenerator vig,
105             boolean isProfile) {
106         // Remove any existing sections
107         mGeneral.removeAllViews();
108 
109         // Bail if invalid state or source
110         if (state == null || type == null) return;
111 
112         // Make sure we have StructuredName
113         RawContactModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
114 
115         // Fill in the header info
116         mAccountName = state.getAccountName();
117         mAccountType = state.getAccountType();
118         mDataSet = state.getDataSet();
119 
120         final Pair<String,String> accountInfo = isProfile
121                 ? EditorUiUtils.getLocalAccountInfo(getContext(), state.getAccountName(), type)
122                 : EditorUiUtils.getAccountInfo(getContext(), state.getAccountName(), type);
123         if (accountInfo.first == null) {
124             // Hide this view so the other text view will be centered vertically
125             mAccountHeaderNameTextView.setVisibility(View.GONE);
126         } else {
127             mAccountHeaderNameTextView.setVisibility(View.VISIBLE);
128             mAccountHeaderNameTextView.setText(accountInfo.first);
129         }
130         mAccountHeaderTypeTextView.setText(accountInfo.second);
131         updateAccountHeaderContentDescription();
132 
133         mAccountIconImageView.setImageDrawable(state.getRawContactAccountType(getContext())
134                 .getDisplayIcon(getContext()));
135 
136         // TODO: Expose data set in the UI somehow?
137 
138         mRawContactId = state.getRawContactId();
139 
140         ValuesDelta primary;
141 
142         // Photo
143         DataKind kind = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
144         if (kind != null) {
145             RawContactModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
146             boolean hasPhotoEditor = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null;
147             setHasPhotoEditor(hasPhotoEditor);
148             primary = state.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
149             getPhotoEditor().setValues(kind, primary, state, !type.areContactsWritable(), vig);
150         }
151 
152         // Name
153         primary = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
154         mName.setText(primary != null ? primary.getAsString(StructuredName.DISPLAY_NAME) :
155                 getContext().getString(R.string.missing_name));
156 
157         if (type.getEditContactActivityClassName() != null) {
158             mEditExternallyButton.setVisibility(View.VISIBLE);
159         } else {
160             mEditExternallyButton.setVisibility(View.GONE);
161         }
162 
163         final Resources res = getContext().getResources();
164         // Phones
165         final ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
166         final Drawable phoneDrawable = getResources().getDrawable(R.drawable.ic_phone_24dp);
167         final String phoneContentDescription = res.getString(R.string.header_phone_entry);
168         if (phones != null) {
169             boolean isFirstPhoneBound = true;
170             for (ValuesDelta phone : phones) {
171                 final String phoneNumber = phone.getPhoneNumber();
172                 if (TextUtils.isEmpty(phoneNumber)) {
173                     continue;
174                 }
175                 final String formattedNumber = PhoneNumberUtilsCompat.formatNumber(
176                         phoneNumber, phone.getPhoneNormalizedNumber(),
177                         GeoUtil.getCurrentCountryIso(getContext()));
178                 CharSequence phoneType = null;
179                 if (phone.hasPhoneType()) {
180                     phoneType = Phone.getTypeLabel(
181                             res, phone.getPhoneType(), phone.getPhoneLabel());
182                 }
183                 bindData(phoneDrawable, phoneContentDescription, formattedNumber, phoneType,
184                         isFirstPhoneBound, true);
185                 isFirstPhoneBound = false;
186             }
187         }
188 
189         // Emails
190         final ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
191         final Drawable emailDrawable = getResources().getDrawable(R.drawable.ic_email_24dp);
192         final String emailContentDescription = res.getString(R.string.header_email_entry);
193         if (emails != null) {
194             boolean isFirstEmailBound = true;
195             for (ValuesDelta email : emails) {
196                 final String emailAddress = email.getEmailData();
197                 if (TextUtils.isEmpty(emailAddress)) {
198                     continue;
199                 }
200                 CharSequence emailType = null;
201                 if (email.hasEmailType()) {
202                     emailType = Email.getTypeLabel(
203                             res, email.getEmailType(), email.getEmailLabel());
204                 }
205                 bindData(emailDrawable, emailContentDescription, emailAddress, emailType,
206                         isFirstEmailBound);
207                 isFirstEmailBound = false;
208             }
209         }
210 
211         // Hide mGeneral if it's empty
212         if (mGeneral.getChildCount() > 0) {
213             mGeneral.setVisibility(View.VISIBLE);
214         } else {
215             mGeneral.setVisibility(View.GONE);
216         }
217     }
218 
bindData(Drawable icon, String iconContentDescription, CharSequence data, CharSequence type, boolean isFirstEntry)219     private void bindData(Drawable icon, String iconContentDescription, CharSequence data,
220             CharSequence type, boolean isFirstEntry) {
221         bindData(icon, iconContentDescription, data, type, isFirstEntry, false);
222     }
223 
bindData(Drawable icon, String iconContentDescription, CharSequence data, CharSequence type, boolean isFirstEntry, boolean forceLTR)224     private void bindData(Drawable icon, String iconContentDescription, CharSequence data,
225             CharSequence type, boolean isFirstEntry, boolean forceLTR) {
226         final View field = mInflater.inflate(R.layout.item_read_only_field, mGeneral, false);
227         if (isFirstEntry) {
228             final ImageView imageView = (ImageView) field.findViewById(R.id.kind_icon);
229             imageView.setImageDrawable(icon);
230             imageView.setContentDescription(iconContentDescription);
231         } else {
232             final ImageView imageView = (ImageView) field.findViewById(R.id.kind_icon);
233             imageView.setVisibility(View.INVISIBLE);
234             imageView.setContentDescription(null);
235         }
236         final TextView dataView = (TextView) field.findViewById(R.id.data);
237         dataView.setText(data);
238         if (forceLTR) {
239             dataView.setTextDirection(View.TEXT_DIRECTION_LTR);
240         }
241         final TextView typeView = (TextView) field.findViewById(R.id.type);
242         if (!TextUtils.isEmpty(type)) {
243             typeView.setText(type);
244         } else {
245             typeView.setVisibility(View.GONE);
246         }
247 
248         mGeneral.addView(field);
249     }
250 
251     @Override
getRawContactId()252     public long getRawContactId() {
253         return mRawContactId;
254     }
255 
256     @Override
onClick(View v)257     public void onClick(View v) {
258         if (v.getId() == R.id.button_edit_externally) {
259             if (mListener != null) {
260                 mListener.onExternalEditorRequest(
261                         new AccountWithDataSet(mAccountName, mAccountType, mDataSet),
262                         ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactId));
263             }
264         }
265     }
266 }
267