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