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 */ 16 package com.android.contacts.common.list; 17 18 import android.content.Context; 19 import android.graphics.Rect; 20 import android.net.Uri; 21 import android.text.TextUtils; 22 import android.util.AttributeSet; 23 import android.util.Log; 24 import android.view.View; 25 import android.widget.FrameLayout; 26 import android.widget.ImageView; 27 import android.widget.QuickContactBadge; 28 import android.widget.TextView; 29 30 import com.android.contacts.common.ContactPhotoManager; 31 import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest; 32 import com.android.contacts.common.MoreContactUtils; 33 import com.android.contacts.common.R; 34 35 /** 36 * A ContactTile displays a contact's picture and name 37 */ 38 public 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)); 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.namePrimary, 129 entry.lookupKey); 130 configureViewForImage(entry.photoUri == null); 131 if (mPhoto != null) { 132 mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(), 133 isDarkTheme(), isContactPhotoCircular(), request); 134 135 if (mQuickContact != null) { 136 mQuickContact.assignContactUri(mLookupUri); 137 } 138 } else if (mQuickContact != null) { 139 mQuickContact.assignContactUri(mLookupUri); 140 mPhotoManager.loadPhoto(mQuickContact, entry.photoUri, 141 getApproximateImageSize(), isDarkTheme(), isContactPhotoCircular(), 142 request); 143 } 144 } else { 145 Log.w(TAG, "contactPhotoManager not set"); 146 } 147 148 if (mPushState != null) { 149 mPushState.setContentDescription(entry.namePrimary); 150 } else if (mQuickContact != null) { 151 mQuickContact.setContentDescription(entry.namePrimary); 152 } 153 } else { 154 setVisibility(View.INVISIBLE); 155 } 156 } 157 158 public void setListener(Listener listener) { 159 mListener = listener; 160 } 161 162 public void setHorizontalDividerVisibility(int visibility) { 163 if (mHorizontalDivider != null) mHorizontalDivider.setVisibility(visibility); 164 } 165 166 public Uri getLookupUri() { 167 return mLookupUri; 168 } 169 170 protected QuickContactBadge getQuickContact() { 171 return mQuickContact; 172 } 173 174 protected View getPhotoView() { 175 return mPhoto; 176 } 177 178 /** 179 * Returns the string that should actually be displayed as the contact's name. Subclasses 180 * can override this to return formatted versions of the name - i.e. first name only. 181 */ 182 protected String getNameForView(ContactEntry contactEntry) { 183 return contactEntry.namePrimary; 184 } 185 186 /** 187 * Implemented by subclasses to estimate the size of the picture. This can return -1 if only 188 * a thumbnail is shown anyway 189 */ 190 protected abstract int getApproximateImageSize(); 191 192 protected abstract boolean isDarkTheme(); 193 194 /** 195 * Implemented by subclasses to reconfigure the view's layout and subviews, based on whether 196 * or not the contact has a user-defined photo. 197 * 198 * @param isDefaultImage True if the contact does not have a user-defined contact photo 199 * (which means a default contact image will be applied by the {@link ContactPhotoManager} 200 */ 201 protected void configureViewForImage(boolean isDefaultImage) { 202 // No-op by default. 203 } 204 205 /** 206 * Implemented by subclasses to allow them to return a {@link DefaultImageRequest} with the 207 * various image parameters defined to match their own layouts. 208 * 209 * @param displayName The display name of the contact 210 * @param lookupKey The lookup key of the contact 211 * @return A {@link DefaultImageRequest} object with each field configured by the subclass 212 * as desired, or {@code null}. 213 */ 214 protected DefaultImageRequest getDefaultImageRequest(String displayName, String lookupKey) { 215 return new DefaultImageRequest(displayName, lookupKey, isContactPhotoCircular()); 216 } 217 218 /** 219 * Whether contact photo should be displayed as a circular image. Implemented by subclasses 220 * so they can change which drawables to fetch. 221 */ 222 protected boolean isContactPhotoCircular() { 223 return true; 224 } 225 226 public interface Listener { 227 /** 228 * Notification that the contact was selected; no specific action is dictated. 229 */ 230 void onContactSelected(Uri contactLookupUri, Rect viewRect); 231 /** 232 * Notification that the specified number is to be called. 233 */ 234 void onCallNumberDirectly(String phoneNumber); 235 /** 236 * @return The width of each tile. This doesn't have to be a precise number (e.g. paddings 237 * can be ignored), but is used to load the correct picture size from the database 238 */ 239 int getApproximateTileWidth(); 240 } 241 } 242