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 71 public RawContactReadOnlyEditorView(Context context) { 72 super(context); 73 } 74 75 public RawContactReadOnlyEditorView(Context context, AttributeSet attrs) { 76 super(context, attrs); 77 } 78 79 80 /** {@inheritDoc} */ 81 @Override 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 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 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 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 252 public long getRawContactId() { 253 return mRawContactId; 254 } 255 256 @Override 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