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.net.Uri; 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 import android.widget.Toast; 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 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 { onExternalEditorRequest(AccountWithDataSet account, Uri uri)75 void onExternalEditorRequest(AccountWithDataSet account, Uri uri); 76 } 77 RawContactReadOnlyEditorView(Context context)78 public RawContactReadOnlyEditorView(Context context) { 79 super(context); 80 } 81 RawContactReadOnlyEditorView(Context context, AttributeSet attrs)82 public RawContactReadOnlyEditorView(Context context, AttributeSet attrs) { 83 super(context, attrs); 84 } 85 setListener(Listener listener)86 public void setListener(Listener listener) { 87 mListener = listener; 88 } 89 90 /** {@inheritDoc} */ 91 @Override onFinishInflate()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 setState(RawContactDelta state, AccountType type, ViewIdGenerator vig, boolean isProfile)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 bindData(CharSequence titleText, CharSequence data, CharSequence type, boolean isFirstEntry)250 private void bindData(CharSequence titleText, CharSequence data, CharSequence type, 251 boolean isFirstEntry) { 252 bindData(titleText, data, type, isFirstEntry, false); 253 } 254 bindData(CharSequence titleText, CharSequence data, CharSequence type, boolean isFirstEntry, boolean forceLTR)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 getRawContactId()284 public long getRawContactId() { 285 return mRawContactId; 286 } 287 288 @Override onClick(View v)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