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