1/* 2 * Copyright (C) 2011 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 */ 16package com.android.contacts.common.list; 17 18import android.content.Context; 19import android.graphics.Rect; 20import android.net.Uri; 21import android.text.TextUtils; 22import android.util.AttributeSet; 23import android.util.Log; 24import android.view.View; 25import android.widget.FrameLayout; 26import android.widget.ImageView; 27import android.widget.QuickContactBadge; 28import android.widget.TextView; 29 30import com.android.contacts.common.ContactPhotoManager; 31import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; 32import com.android.contacts.common.MoreContactUtils; 33import com.android.contacts.common.R; 34 35/** 36 * A ContactTile displays a contact's picture and name 37 */ 38public abstract class ContactTileView extends FrameLayout { 39 private final static String TAG = ContactTileView.class.getSimpleName(); 40 41 private Uri mLookupUri; 42 private ImageView mPhoto; 43 private QuickContactBadge mQuickContact; 44 private TextView mName; 45 private TextView mStatus; 46 private TextView mPhoneLabel; 47 private TextView mPhoneNumber; 48 private ContactPhotoManager mPhotoManager = null; 49 private View mPushState; 50 private View mHorizontalDivider; 51 protected Listener mListener; 52 53 public ContactTileView(Context context, AttributeSet attrs) { 54 super(context, attrs); 55 } 56 57 @Override 58 protected void onFinishInflate() { 59 super.onFinishInflate(); 60 mName = (TextView) findViewById(R.id.contact_tile_name); 61 62 mQuickContact = (QuickContactBadge) findViewById(R.id.contact_tile_quick); 63 mPhoto = (ImageView) findViewById(R.id.contact_tile_image); 64 mStatus = (TextView) findViewById(R.id.contact_tile_status); 65 mPhoneLabel = (TextView) findViewById(R.id.contact_tile_phone_type); 66 mPhoneNumber = (TextView) findViewById(R.id.contact_tile_phone_number); 67 mPushState = findViewById(R.id.contact_tile_push_state); 68 mHorizontalDivider = findViewById(R.id.contact_tile_horizontal_divider); 69 70 OnClickListener listener = createClickListener(); 71 setOnClickListener(listener); 72 } 73 74 protected OnClickListener createClickListener() { 75 return new OnClickListener() { 76 @Override 77 public void onClick(View v) { 78 if (mListener == null) return; 79 mListener.onContactSelected( 80 getLookupUri(), 81 MoreContactUtils.getTargetRectFromView(ContactTileView.this)); 82 } 83 }; 84 } 85 86 public void setPhotoManager(ContactPhotoManager photoManager) { 87 mPhotoManager = photoManager; 88 } 89 90 /** 91 * Populates the data members to be displayed from the 92 * fields in {@link com.android.contacts.common.list.ContactEntry} 93 */ 94 public void loadFromContact(ContactEntry entry) { 95 96 if (entry != null) { 97 mName.setText(getNameForView(entry.name)); 98 mLookupUri = entry.lookupUri; 99 100 if (mStatus != null) { 101 if (entry.status == null) { 102 mStatus.setVisibility(View.GONE); 103 } else { 104 mStatus.setText(entry.status); 105 mStatus.setCompoundDrawablesWithIntrinsicBounds(entry.presenceIcon, 106 null, null, null); 107 mStatus.setVisibility(View.VISIBLE); 108 } 109 } 110 111 if (mPhoneLabel != null) { 112 if (TextUtils.isEmpty(entry.phoneLabel)) { 113 mPhoneLabel.setVisibility(View.GONE); 114 } else { 115 mPhoneLabel.setVisibility(View.VISIBLE); 116 mPhoneLabel.setText(entry.phoneLabel); 117 } 118 } 119 120 if (mPhoneNumber != null) { 121 // TODO: Format number correctly 122 mPhoneNumber.setText(entry.phoneNumber); 123 } 124 125 setVisibility(View.VISIBLE); 126 127 if (mPhotoManager != null) { 128 DefaultImageRequest request = getDefaultImageRequest(entry.name, entry.lookupKey); 129 configureViewForImage(entry.photoUri == null); 130 if (mPhoto != null) { 131 mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(), 132 isDarkTheme(), isContactPhotoCircular(), request); 133 134 if (mQuickContact != null) { 135 mQuickContact.assignContactUri(mLookupUri); 136 } 137 } else if (mQuickContact != null) { 138 mQuickContact.assignContactUri(mLookupUri); 139 mPhotoManager.loadPhoto(mQuickContact, entry.photoUri, 140 getApproximateImageSize(), isDarkTheme(), isContactPhotoCircular(), 141 request); 142 } 143 } else { 144 Log.w(TAG, "contactPhotoManager not set"); 145 } 146 147 if (mPushState != null) { 148 mPushState.setContentDescription(entry.name); 149 } else if (mQuickContact != null) { 150 mQuickContact.setContentDescription(entry.name); 151 } 152 } else { 153 setVisibility(View.INVISIBLE); 154 } 155 } 156 157 public void setListener(Listener listener) { 158 mListener = listener; 159 } 160 161 public void setHorizontalDividerVisibility(int visibility) { 162 if (mHorizontalDivider != null) mHorizontalDivider.setVisibility(visibility); 163 } 164 165 public Uri getLookupUri() { 166 return mLookupUri; 167 } 168 169 protected QuickContactBadge getQuickContact() { 170 return mQuickContact; 171 } 172 173 protected View getPhotoView() { 174 return mPhoto; 175 } 176 177 /** 178 * Returns the string that should actually be displayed as the contact's name. Subclasses 179 * can override this to return formatted versions of the name - i.e. first name only. 180 */ 181 protected String getNameForView(String name) { 182 return name; 183 } 184 185 /** 186 * Implemented by subclasses to estimate the size of the picture. This can return -1 if only 187 * a thumbnail is shown anyway 188 */ 189 protected abstract int getApproximateImageSize(); 190 191 protected abstract boolean isDarkTheme(); 192 193 /** 194 * Implemented by subclasses to reconfigure the view's layout and subviews, based on whether 195 * or not the contact has a user-defined photo. 196 * 197 * @param isDefaultImage True if the contact does not have a user-defined contact photo 198 * (which means a default contact image will be applied by the {@link ContactPhotoManager} 199 */ 200 protected void configureViewForImage(boolean isDefaultImage) { 201 // No-op by default. 202 } 203 204 /** 205 * Implemented by subclasses to allow them to return a {@link DefaultImageRequest} with the 206 * various image parameters defined to match their own layouts. 207 * 208 * @param displayName The display name of the contact 209 * @param lookupKey The lookup key of the contact 210 * @return A {@link DefaultImageRequest} object with each field configured by the subclass 211 * as desired, or {@code null}. 212 */ 213 protected DefaultImageRequest getDefaultImageRequest(String displayName, String lookupKey) { 214 return new DefaultImageRequest(displayName, lookupKey, isContactPhotoCircular()); 215 } 216 217 /** 218 * Whether contact photo should be displayed as a circular image. Implemented by subclasses 219 * so they can change which drawables to fetch. 220 */ 221 protected boolean isContactPhotoCircular() { 222 return true; 223 } 224 225 public interface Listener { 226 /** 227 * Notification that the contact was selected; no specific action is dictated. 228 */ 229 void onContactSelected(Uri contactLookupUri, Rect viewRect); 230 /** 231 * Notification that the specified number is to be called. 232 */ 233 void onCallNumberDirectly(String phoneNumber); 234 /** 235 * @return The width of each tile. This doesn't have to be a precise number (e.g. paddings 236 * can be ignored), but is used to load the correct picture size from the database 237 */ 238 int getApproximateTileWidth(); 239 } 240} 241