blob: 2aeb34d79b68a3b1e64397dd9522d03698fb00b9 [file] [log] [blame]
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001/*
2 * Copyright (C) 2007 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
17package com.android.contacts;
18
Evan Millar54a5c9f2009-06-23 17:41:09 -070019import com.android.contacts.Collapser.Collapsible;
Evan Millar11d628c2009-09-02 08:55:01 -070020import com.android.contacts.model.ContactsSource;
21import com.android.contacts.model.Sources;
22import com.android.contacts.model.ContactsSource.DataKind;
Evan Millardf181202009-09-30 15:15:51 -070023import com.android.contacts.ui.EditContactActivity;
Jeff Sharkey49d17b32009-09-07 02:14:21 -070024import com.android.contacts.util.Constants;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070025import com.android.contacts.util.DataStatus;
Evan Millar11d628c2009-09-02 08:55:01 -070026import com.android.contacts.util.NotifyingAsyncQueryHandler;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080027import com.android.internal.telephony.ITelephony;
Evan Millar11d628c2009-09-02 08:55:01 -070028import com.android.internal.widget.ContactHeaderWidget;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070029import com.google.android.collect.Lists;
30import com.google.android.collect.Maps;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080031
Evan Millar11d628c2009-09-02 08:55:01 -070032import android.app.Activity;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080033import android.app.AlertDialog;
34import android.app.Dialog;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080035import android.content.ActivityNotFoundException;
36import android.content.ContentResolver;
37import android.content.ContentUris;
38import android.content.ContentValues;
39import android.content.Context;
40import android.content.DialogInterface;
Evan Millar5f4af702009-08-11 11:12:00 -070041import android.content.Entity;
Evan Millar11d628c2009-09-02 08:55:01 -070042import android.content.EntityIterator;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080043import android.content.Intent;
Evan Millar11d628c2009-09-02 08:55:01 -070044import android.content.Entity.NamedContentValues;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080045import android.content.res.Resources;
46import android.database.ContentObserver;
47import android.database.Cursor;
48import android.graphics.drawable.Drawable;
Evan Millar951fa9c2009-10-26 14:57:43 -070049import android.net.ParseException;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080050import android.net.Uri;
Evan Millar951fa9c2009-10-26 14:57:43 -070051import android.net.WebAddress;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080052import android.os.Bundle;
53import android.os.Handler;
54import android.os.RemoteException;
55import android.os.ServiceManager;
Dmitri Plotnikov4e3a0432009-09-15 13:54:40 -070056import android.provider.ContactsContract;
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -070057import android.provider.ContactsContract.AggregationExceptions;
58import android.provider.ContactsContract.CommonDataKinds;
Evan Millar11d628c2009-09-02 08:55:01 -070059import android.provider.ContactsContract.Contacts;
Evan Millar66388be2009-05-28 15:41:07 -070060import android.provider.ContactsContract.Data;
Dmitri Plotnikov39466592009-07-27 11:23:51 -070061import android.provider.ContactsContract.RawContacts;
Fred Quintana8579e252009-12-07 14:50:12 -080062import android.provider.ContactsContract.RawContactsEntity;
Dmitri Plotnikov160e9da2009-09-30 23:48:12 -070063import android.provider.ContactsContract.StatusUpdates;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070064import android.provider.ContactsContract.CommonDataKinds.Email;
65import android.provider.ContactsContract.CommonDataKinds.Im;
66import android.provider.ContactsContract.CommonDataKinds.Nickname;
67import android.provider.ContactsContract.CommonDataKinds.Note;
68import android.provider.ContactsContract.CommonDataKinds.Organization;
Evan Millar54a5c9f2009-06-23 17:41:09 -070069import android.provider.ContactsContract.CommonDataKinds.Phone;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070070import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
Evan Millar951fa9c2009-10-26 14:57:43 -070071import android.provider.ContactsContract.CommonDataKinds.Website;
Evan Millar54a5c9f2009-06-23 17:41:09 -070072import android.telephony.PhoneNumberUtils;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080073import android.text.TextUtils;
74import android.util.Log;
75import android.view.ContextMenu;
76import android.view.KeyEvent;
Evan Millar11d628c2009-09-02 08:55:01 -070077import android.view.LayoutInflater;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080078import android.view.Menu;
Jeff Sharkey49d17b32009-09-07 02:14:21 -070079import android.view.MenuInflater;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080080import android.view.MenuItem;
81import android.view.View;
82import android.view.ViewGroup;
Evan Millar11d628c2009-09-02 08:55:01 -070083import android.view.Window;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080084import android.view.ContextMenu.ContextMenuInfo;
85import android.widget.AdapterView;
Evan Millar7911ff52009-07-21 15:55:18 -070086import android.widget.FrameLayout;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080087import android.widget.ImageView;
88import android.widget.ListView;
Evan Millarcdeea942009-10-07 11:47:35 -070089import android.widget.ScrollView;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080090import android.widget.TextView;
91import android.widget.Toast;
92
93import java.util.ArrayList;
Jeff Sharkey624ddc32009-10-01 21:32:19 -070094import java.util.HashMap;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080095
96/**
97 * Displays the details of a specific contact.
98 */
Evan Millar11d628c2009-09-02 08:55:01 -070099public class ViewContactActivity extends Activity
Evan Millar7911ff52009-07-21 15:55:18 -0700100 implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener,
Evan Millardf181202009-09-30 15:15:51 -0700101 AdapterView.OnItemClickListener, NotifyingAsyncQueryHandler.AsyncQueryListener {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800102 private static final String TAG = "ViewContact";
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800103
104 private static final boolean SHOW_SEPARATORS = false;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800105
106 private static final int DIALOG_CONFIRM_DELETE = 1;
Megha Joshid5afd8a2009-09-22 09:38:41 -0700107 private static final int DIALOG_CONFIRM_READONLY_DELETE = 2;
108 private static final int DIALOG_CONFIRM_MULTIPLE_DELETE = 3;
Megha Joshic508bd82009-10-01 17:31:49 -0700109 private static final int DIALOG_CONFIRM_READONLY_HIDE = 4;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800110
Evan Millar8a79cee2009-08-19 17:20:49 -0700111 private static final int REQUEST_JOIN_CONTACT = 1;
Evan Millar9cd81242009-09-26 16:02:31 -0700112 private static final int REQUEST_EDIT_CONTACT = 2;
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700113
Evan Millar8a79cee2009-08-19 17:20:49 -0700114 public static final int MENU_ITEM_MAKE_DEFAULT = 3;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800115
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700116 protected Uri mLookupUri;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800117 private ContentResolver mResolver;
118 private ViewAdapter mAdapter;
119 private int mNumPhoneNumbers = 0;
120
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700121 /**
Dmitri Plotnikove1cd6792009-07-27 20:28:17 -0700122 * A list of distinct contact IDs included in the current contact.
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700123 */
Evan Millar7911ff52009-07-21 15:55:18 -0700124 private ArrayList<Long> mRawContactIds = new ArrayList<Long>();
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700125
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800126 /* package */ ArrayList<ViewEntry> mPhoneEntries = new ArrayList<ViewEntry>();
127 /* package */ ArrayList<ViewEntry> mSmsEntries = new ArrayList<ViewEntry>();
128 /* package */ ArrayList<ViewEntry> mEmailEntries = new ArrayList<ViewEntry>();
129 /* package */ ArrayList<ViewEntry> mPostalEntries = new ArrayList<ViewEntry>();
130 /* package */ ArrayList<ViewEntry> mImEntries = new ArrayList<ViewEntry>();
131 /* package */ ArrayList<ViewEntry> mOrganizationEntries = new ArrayList<ViewEntry>();
The Android Open Source Projectcac191e2009-03-18 22:20:27 -0700132 /* package */ ArrayList<ViewEntry> mGroupEntries = new ArrayList<ViewEntry>();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800133 /* package */ ArrayList<ViewEntry> mOtherEntries = new ArrayList<ViewEntry>();
134 /* package */ ArrayList<ArrayList<ViewEntry>> mSections = new ArrayList<ArrayList<ViewEntry>>();
135
136 private Cursor mCursor;
Evan Millar5c22c3b2009-05-29 11:37:54 -0700137
Evan Millar11d628c2009-09-02 08:55:01 -0700138 protected ContactHeaderWidget mContactHeaderWidget;
139 private NotifyingAsyncQueryHandler mHandler;
140
141 protected LayoutInflater mInflater;
142
Megha Joshid5afd8a2009-09-22 09:38:41 -0700143 protected int mReadOnlySourcesCnt;
144 protected int mWritableSourcesCnt;
Jeff Sharkeye0408762009-11-03 12:57:16 -0800145 protected boolean mAllRestricted;
146
Megha Joshid5afd8a2009-09-22 09:38:41 -0700147 protected ArrayList<Long> mWritableRawContactIds = new ArrayList<Long>();
Evan Millar11d628c2009-09-02 08:55:01 -0700148
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700149 private static final int TOKEN_ENTITIES = 0;
150 private static final int TOKEN_STATUSES = 1;
151
152 private boolean mHasEntities = false;
153 private boolean mHasStatuses = false;
154
155 private ArrayList<Entity> mEntities = Lists.newArrayList();
156 private HashMap<Long, DataStatus> mStatuses = Maps.newHashMap();
Evan Millar11d628c2009-09-02 08:55:01 -0700157
Makoto Onuki7a707382009-11-19 13:35:55 +0900158 /**
159 * The view shown if the detail list is empty.
160 * We set this to the list view when first bind the adapter, so that it won't be shown while
161 * we're loading data.
162 */
163 private View mEmptyView;
164
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800165 private ContentObserver mObserver = new ContentObserver(new Handler()) {
166 @Override
167 public boolean deliverSelfNotifications() {
168 return true;
169 }
170
171 @Override
172 public void onChange(boolean selfChange) {
Evan Millar11d628c2009-09-02 08:55:01 -0700173 if (mCursor != null && !mCursor.isClosed()) {
174 startEntityQuery();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800175 }
176 }
177 };
178
179 public void onClick(DialogInterface dialog, int which) {
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700180 closeCursor();
Megha Joshic508bd82009-10-01 17:31:49 -0700181 getContentResolver().delete(mLookupUri, null, null);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800182 finish();
183 }
184
Evan Millar7911ff52009-07-21 15:55:18 -0700185 private ListView mListView;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800186 private boolean mShowSmsLinksForAllPhones;
187
188 @Override
189 protected void onCreate(Bundle icicle) {
190 super.onCreate(icicle);
191
Evan Millar11d628c2009-09-02 08:55:01 -0700192 final Intent intent = getIntent();
Dmitri Plotnikov4e3a0432009-09-15 13:54:40 -0700193 Uri data = intent.getData();
194 String authority = data.getAuthority();
195 if (ContactsContract.AUTHORITY.equals(authority)) {
196 mLookupUri = data;
197 } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
198 final long rawContactId = ContentUris.parseId(data);
199 mLookupUri = RawContacts.getContactLookupUri(getContentResolver(),
200 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
Dmitri Plotnikov83129f02009-09-02 19:04:41 -0700201
Dmitri Plotnikov4e3a0432009-09-15 13:54:40 -0700202 }
Dmitri Plotnikov83129f02009-09-02 19:04:41 -0700203 mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Evan Millar11d628c2009-09-02 08:55:01 -0700204
205 requestWindowFeature(Window.FEATURE_NO_TITLE);
206 setContentView(R.layout.contact_card_layout);
207
208 mContactHeaderWidget = (ContactHeaderWidget) findViewById(R.id.contact_header_widget);
209 mContactHeaderWidget.showStar(true);
Evan Millar11d628c2009-09-02 08:55:01 -0700210 mContactHeaderWidget.setExcludeMimes(new String[] {
211 Contacts.CONTENT_ITEM_TYPE
212 });
213
Evan Millar11d628c2009-09-02 08:55:01 -0700214 mHandler = new NotifyingAsyncQueryHandler(this, this);
215
Evan Millarcdeea942009-10-07 11:47:35 -0700216 mListView = (ListView) findViewById(R.id.contact_data);
Evan Millar7911ff52009-07-21 15:55:18 -0700217 mListView.setOnCreateContextMenuListener(this);
218 mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
219 mListView.setOnItemClickListener(this);
Makoto Onuki7a707382009-11-19 13:35:55 +0900220 // Don't set it to mListView yet. We do so later when we bind the adapter.
221 mEmptyView = findViewById(android.R.id.empty);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800222
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800223 mResolver = getContentResolver();
224
225 // Build the list of sections. The order they're added to mSections dictates the
226 // order they are displayed in the list.
227 mSections.add(mPhoneEntries);
228 mSections.add(mSmsEntries);
229 mSections.add(mEmailEntries);
230 mSections.add(mImEntries);
231 mSections.add(mPostalEntries);
232 mSections.add(mOrganizationEntries);
The Android Open Source Projectcac191e2009-03-18 22:20:27 -0700233 mSections.add(mGroupEntries);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800234 mSections.add(mOtherEntries);
235
236 //TODO Read this value from a preference
237 mShowSmsLinksForAllPhones = true;
Evan Millar11d628c2009-09-02 08:55:01 -0700238 }
239
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800240 @Override
241 protected void onResume() {
242 super.onResume();
Evan Millar11d628c2009-09-02 08:55:01 -0700243 startEntityQuery();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800244 }
245
246 @Override
247 protected void onPause() {
248 super.onPause();
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700249 closeCursor();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800250 }
251
252 @Override
253 protected void onDestroy() {
254 super.onDestroy();
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700255 closeCursor();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800256 }
257
258 @Override
259 protected Dialog onCreateDialog(int id) {
260 switch (id) {
261 case DIALOG_CONFIRM_DELETE:
262 return new AlertDialog.Builder(this)
263 .setTitle(R.string.deleteConfirmation_title)
264 .setIcon(android.R.drawable.ic_dialog_alert)
265 .setMessage(R.string.deleteConfirmation)
266 .setNegativeButton(android.R.string.cancel, null)
267 .setPositiveButton(android.R.string.ok, this)
268 .setCancelable(false)
269 .create();
Megha Joshid5afd8a2009-09-22 09:38:41 -0700270 case DIALOG_CONFIRM_READONLY_DELETE:
271 return new AlertDialog.Builder(this)
272 .setTitle(R.string.deleteConfirmation_title)
273 .setIcon(android.R.drawable.ic_dialog_alert)
274 .setMessage(R.string.readOnlyContactDeleteConfirmation)
275 .setNegativeButton(android.R.string.cancel, null)
276 .setPositiveButton(android.R.string.ok, this)
277 .setCancelable(false)
278 .create();
279 case DIALOG_CONFIRM_MULTIPLE_DELETE:
280 return new AlertDialog.Builder(this)
281 .setTitle(R.string.deleteConfirmation_title)
282 .setIcon(android.R.drawable.ic_dialog_alert)
283 .setMessage(R.string.multipleContactDeleteConfirmation)
284 .setNegativeButton(android.R.string.cancel, null)
285 .setPositiveButton(android.R.string.ok, this)
286 .setCancelable(false)
287 .create();
Evan Millarcdeea942009-10-07 11:47:35 -0700288 case DIALOG_CONFIRM_READONLY_HIDE: {
Megha Joshic508bd82009-10-01 17:31:49 -0700289 return new AlertDialog.Builder(this)
290 .setTitle(R.string.deleteConfirmation_title)
291 .setIcon(android.R.drawable.ic_dialog_alert)
292 .setMessage(R.string.readOnlyContactWarning)
293 .setPositiveButton(android.R.string.ok, this)
Evan Millarcdeea942009-10-07 11:47:35 -0700294 .create();
Megha Joshic508bd82009-10-01 17:31:49 -0700295 }
296
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800297 }
298 return null;
299 }
300
Evan Millar11d628c2009-09-02 08:55:01 -0700301 /** {@inheritDoc} */
Fred Quintana8579e252009-12-07 14:50:12 -0800302 public void onQueryComplete(int token, Object cookie, Cursor cursor) {
303 if (token == TOKEN_STATUSES) {
304 try {
305 // Read available social rows and consider binding
306 readStatuses(cursor);
307 } finally {
308 if (cursor != null) {
309 cursor.close();
310 }
311 }
312 } else {
313 EntityIterator iterator = RawContacts.newEntityIterator(cursor);
314 try {
315 // Read incoming entities and consider binding
316 readEntities(iterator);
317 } finally {
Evan Millar11d628c2009-09-02 08:55:01 -0700318 iterator.close();
319 }
320 }
Fred Quintana8579e252009-12-07 14:50:12 -0800321 considerBindData();
Evan Millar11d628c2009-09-02 08:55:01 -0700322 }
323
Evan Millar6a61a1a2009-09-29 14:00:43 -0700324 private long getRefreshedContactId() {
325 Uri freshContactUri = Contacts.lookupContact(getContentResolver(), mLookupUri);
326 if (freshContactUri != null) {
327 return ContentUris.parseId(freshContactUri);
328 }
329 return -1;
330 }
331
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700332 /**
333 * Read from the given {@link EntityIterator} to build internal set of
334 * {@link #mEntities} for data display.
335 */
336 private synchronized void readEntities(EntityIterator iterator) {
337 mEntities.clear();
Evan Millar11d628c2009-09-02 08:55:01 -0700338 try {
339 while (iterator.hasNext()) {
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700340 mEntities.add(iterator.next());
Evan Millar11d628c2009-09-02 08:55:01 -0700341 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700342 mHasEntities = true;
Evan Millar11d628c2009-09-02 08:55:01 -0700343 } catch (RemoteException e) {
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700344 Log.w(TAG, "Problem reading contact data: " + e.toString());
Evan Millar11d628c2009-09-02 08:55:01 -0700345 }
Evan Millar11d628c2009-09-02 08:55:01 -0700346 }
347
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700348 /**
349 * Read from the given {@link Cursor} and build a set of {@link DataStatus}
350 * objects to match any valid statuses found.
351 */
352 private synchronized void readStatuses(Cursor cursor) {
353 mStatuses.clear();
354
355 // Walk found statuses, creating internal row for each
356 while (cursor.moveToNext()) {
357 final DataStatus status = new DataStatus(cursor);
358 final long dataId = cursor.getLong(StatusQuery._ID);
359 mStatuses.put(dataId, status);
360 }
361
362 mHasStatuses = true;
363 }
364
365 private synchronized void startEntityQuery() {
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700366 closeCursor();
367
Evan Millar6a61a1a2009-09-29 14:00:43 -0700368 Uri uri = null;
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700369 if (mLookupUri != null) {
370 mLookupUri = Contacts.getLookupUri(getContentResolver(), mLookupUri);
371 if (mLookupUri != null) {
Evan Millar6a61a1a2009-09-29 14:00:43 -0700372 uri = Contacts.lookupContact(getContentResolver(), mLookupUri);
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700373 }
374 }
375
Evan Millar6a61a1a2009-09-29 14:00:43 -0700376 if (uri == null) {
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700377
378 // TODO either figure out a way to prevent a flash of black background or
379 // use some other UI than a toast
380 Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_SHORT).show();
381 Log.e(TAG, "invalid contact uri: " + mLookupUri);
382 finish();
383 return;
384 }
385
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700386 final Uri dataUri = Uri.withAppendedPath(uri, Contacts.Data.CONTENT_DIRECTORY);
387
388 // Keep stub cursor open on side to watch for change events
389 mCursor = mResolver.query(dataUri,
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700390 new String[] {Contacts.DISPLAY_NAME}, null, null, null);
391 mCursor.registerContentObserver(mObserver);
392
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700393 final long contactId = ContentUris.parseId(uri);
394
395 // Clear flags and start queries to data and status
396 mHasEntities = false;
397 mHasStatuses = false;
398
Fred Quintana8579e252009-12-07 14:50:12 -0800399 mHandler.startQuery(TOKEN_ENTITIES, null, RawContactsEntity.CONTENT_URI, null,
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700400 RawContacts.CONTACT_ID + "=" + contactId, null, null);
401 mHandler.startQuery(TOKEN_STATUSES, null, dataUri, StatusQuery.PROJECTION,
402 StatusUpdates.PRESENCE + " IS NOT NULL OR " + StatusUpdates.STATUS
403 + " IS NOT NULL", null, null);
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700404
Evan Millar9b1a1242009-09-16 10:26:10 -0700405 mContactHeaderWidget.bindFromContactLookupUri(mLookupUri);
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700406 }
407
408 private void closeCursor() {
409 if (mCursor != null) {
410 mCursor.unregisterContentObserver(mObserver);
411 mCursor.close();
412 mCursor = null;
413 }
Evan Millar11d628c2009-09-02 08:55:01 -0700414 }
415
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700416 /**
417 * Consider binding views after any of several background queries has
418 * completed. We check internal flags and only bind when all data has
419 * arrived.
420 */
421 private void considerBindData() {
422 if (mHasEntities && mHasStatuses) {
423 bindData();
424 }
425 }
426
Evan Millar11d628c2009-09-02 08:55:01 -0700427 private void bindData() {
428
429 // Build up the contact entries
430 buildEntries();
431
432 // Collapse similar data items in select sections.
433 Collapser.collapseList(mPhoneEntries);
434 Collapser.collapseList(mSmsEntries);
435 Collapser.collapseList(mEmailEntries);
436 Collapser.collapseList(mPostalEntries);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700437 Collapser.collapseList(mImEntries);
Evan Millar11d628c2009-09-02 08:55:01 -0700438
439 if (mAdapter == null) {
440 mAdapter = new ViewAdapter(this, mSections);
441 mListView.setAdapter(mAdapter);
442 } else {
443 mAdapter.setSections(mSections, SHOW_SEPARATORS);
444 }
Makoto Onuki7a707382009-11-19 13:35:55 +0900445 mListView.setEmptyView(mEmptyView);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800446 }
447
448 @Override
449 public boolean onCreateOptionsMenu(Menu menu) {
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700450 super.onCreateOptionsMenu(menu);
451
452 final MenuInflater inflater = getMenuInflater();
453 inflater.inflate(R.menu.view, menu);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800454 return true;
455 }
456
457 @Override
458 public boolean onPrepareOptionsMenu(Menu menu) {
459 super.onPrepareOptionsMenu(menu);
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700460
Evan Millar51514db2009-09-22 11:42:35 -0700461 // Only allow edit when we have at least one raw_contact id
462 final boolean hasRawContact = (mRawContactIds.size() > 0);
Evan Millar2e1b8af2009-09-24 09:39:21 -0700463 menu.findItem(R.id.menu_edit).setEnabled(hasRawContact);
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700464
Jeff Sharkeye0408762009-11-03 12:57:16 -0800465 // Only allow share when unrestricted contacts available
466 menu.findItem(R.id.menu_share).setEnabled(!mAllRestricted);
467
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800468 return true;
469 }
470
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800471 @Override
472 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
473 AdapterView.AdapterContextMenuInfo info;
474 try {
475 info = (AdapterView.AdapterContextMenuInfo) menuInfo;
476 } catch (ClassCastException e) {
477 Log.e(TAG, "bad menuInfo", e);
478 return;
479 }
480
481 // This can be null sometimes, don't crash...
482 if (info == null) {
483 Log.e(TAG, "bad menuInfo");
484 return;
485 }
Evan Millar5c22c3b2009-05-29 11:37:54 -0700486
Evan Millar45e0ed32009-06-01 16:44:38 -0700487 ViewEntry entry = ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
Neel Parekha8fb68a2009-09-25 18:05:18 -0700488 menu.setHeaderTitle(R.string.contactOptionsTitle);
Evan Millar45e0ed32009-06-01 16:44:38 -0700489 if (entry.mimetype.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
490 menu.add(0, 0, 0, R.string.menu_call).setIntent(entry.intent);
Evan Millar15e514d2009-08-04 10:14:57 -0700491 menu.add(0, 0, 0, R.string.menu_sendSMS).setIntent(entry.secondaryIntent);
492 if (!entry.isPrimary) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700493 menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultNumber);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800494 }
Evan Millar45e0ed32009-06-01 16:44:38 -0700495 } else if (entry.mimetype.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
496 menu.add(0, 0, 0, R.string.menu_sendEmail).setIntent(entry.intent);
Evan Millar15e514d2009-08-04 10:14:57 -0700497 if (!entry.isPrimary) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700498 menu.add(0, MENU_ITEM_MAKE_DEFAULT, 0, R.string.menu_makeDefaultEmail);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800499 }
Jeff Sharkeyc6ad3ab2009-07-21 19:30:15 -0700500 } else if (entry.mimetype.equals(CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)) {
Evan Millar45e0ed32009-06-01 16:44:38 -0700501 menu.add(0, 0, 0, R.string.menu_viewAddress).setIntent(entry.intent);
502 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800503 }
504
505 @Override
506 public boolean onOptionsItemSelected(MenuItem item) {
507 switch (item.getItemId()) {
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700508 case R.id.menu_edit: {
Evan Millardf181202009-09-30 15:15:51 -0700509 Long rawContactIdToEdit = null;
510 if (mRawContactIds.size() > 0) {
511 rawContactIdToEdit = mRawContactIds.get(0);
512 } else {
513 // There is no rawContact to edit.
514 break;
Evan Millardb5d88c2009-08-28 09:31:57 -0700515 }
Evan Millar2e1b8af2009-09-24 09:39:21 -0700516 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI,
517 rawContactIdToEdit);
Evan Millar9cd81242009-09-26 16:02:31 -0700518 startActivityForResult(new Intent(Intent.ACTION_EDIT, rawContactUri),
519 REQUEST_EDIT_CONTACT);
Evan Millar8a79cee2009-08-19 17:20:49 -0700520 break;
521 }
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700522 case R.id.menu_delete: {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800523 // Get confirmation
Evan Millarcdeea942009-10-07 11:47:35 -0700524 if (mReadOnlySourcesCnt > 0 & mWritableSourcesCnt > 0) {
Megha Joshid5afd8a2009-09-22 09:38:41 -0700525 showDialog(DIALOG_CONFIRM_READONLY_DELETE);
Evan Millarcdeea942009-10-07 11:47:35 -0700526 } else if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt == 0) {
Megha Joshic508bd82009-10-01 17:31:49 -0700527 showDialog(DIALOG_CONFIRM_READONLY_HIDE);
Evan Millarcdeea942009-10-07 11:47:35 -0700528 } else if (mReadOnlySourcesCnt == 0 && mWritableSourcesCnt > 1) {
529 showDialog(DIALOG_CONFIRM_MULTIPLE_DELETE);
530 } else {
531 showDialog(DIALOG_CONFIRM_DELETE);
532 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800533 return true;
534 }
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700535 case R.id.menu_join: {
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700536 showJoinAggregateActivity();
537 return true;
538 }
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700539 case R.id.menu_options: {
Dmitri Plotnikovef038722009-06-24 18:51:47 -0700540 showOptionsActivity();
541 return true;
542 }
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700543 case R.id.menu_share: {
Jeff Sharkeye0408762009-11-03 12:57:16 -0800544 if (mAllRestricted) return false;
545
Jeff Sharkey93049312009-09-27 17:28:13 -0700546 // TODO: Keep around actual LOOKUP_KEY, or formalize method of extracting
547 final String lookupKey = mLookupUri.getPathSegments().get(2);
548 final Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
549
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700550 final Intent intent = new Intent(Intent.ACTION_SEND);
Jeff Sharkey93049312009-09-27 17:28:13 -0700551 intent.setType(Contacts.CONTENT_VCARD_TYPE);
552 intent.putExtra(Intent.EXTRA_STREAM, shareUri);
Dmitri Plotnikovef038722009-06-24 18:51:47 -0700553
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700554 // Launch chooser to share contact via
555 final CharSequence chooseTitle = getText(R.string.share_via);
556 final Intent chooseIntent = Intent.createChooser(intent, chooseTitle);
Evan Millar5c22c3b2009-05-29 11:37:54 -0700557
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700558 try {
559 startActivity(chooseIntent);
560 } catch (ActivityNotFoundException ex) {
561 Toast.makeText(this, R.string.share_error, Toast.LENGTH_SHORT).show();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800562 }
Jeff Sharkey49d17b32009-09-07 02:14:21 -0700563 return true;
564 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800565 }
566 return super.onOptionsItemSelected(item);
567 }
Evan Millar5c22c3b2009-05-29 11:37:54 -0700568
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800569 @Override
570 public boolean onContextItemSelected(MenuItem item) {
571 switch (item.getItemId()) {
572 case MENU_ITEM_MAKE_DEFAULT: {
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700573 if (makeItemDefault(item)) {
574 return true;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800575 }
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700576 break;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800577 }
578 }
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700579
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800580 return super.onContextItemSelected(item);
581 }
582
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700583 private boolean makeItemDefault(MenuItem item) {
584 ViewEntry entry = getViewEntryForMenuItem(item);
585 if (entry == null) {
586 return false;
587 }
588
589 // Update the primary values in the data record.
Evan Millar14fecb62009-09-09 09:23:12 -0700590 ContentValues values = new ContentValues(1);
Evan Millar54a5c9f2009-06-23 17:41:09 -0700591 values.put(Data.IS_SUPER_PRIMARY, 1);
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700592 getContentResolver().update(ContentUris.withAppendedId(Data.CONTENT_URI, entry.id),
593 values, null, null);
Evan Millar11d628c2009-09-02 08:55:01 -0700594 startEntityQuery();
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700595 return true;
596 }
597
598 /**
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700599 * Shows a list of aggregates that can be joined into the currently viewed aggregate.
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700600 */
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700601 public void showJoinAggregateActivity() {
Evan Millar6a61a1a2009-09-29 14:00:43 -0700602 long freshId = getRefreshedContactId();
603 if (freshId > 0) {
604 String displayName = null;
605 if (mCursor.moveToFirst()) {
606 displayName = mCursor.getString(0);
607 }
608 Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
609 intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, freshId);
610 if (displayName != null) {
611 intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_NAME, displayName);
612 }
613 startActivityForResult(intent, REQUEST_JOIN_CONTACT);
Dmitri Plotnikova5cfca32009-09-29 18:13:08 -0700614 }
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700615 }
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700616
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700617 @Override
618 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Evan Millar2e1b8af2009-09-24 09:39:21 -0700619 if (requestCode == REQUEST_JOIN_CONTACT) {
620 if (resultCode == RESULT_OK && intent != null) {
621 final long contactId = ContentUris.parseId(intent.getData());
622 joinAggregate(contactId);
Evan Millar8a79cee2009-08-19 17:20:49 -0700623 }
Evan Millar9cd81242009-09-26 16:02:31 -0700624 } else if (requestCode == REQUEST_EDIT_CONTACT) {
Evan Millardf181202009-09-30 15:15:51 -0700625 if (resultCode == EditContactActivity.RESULT_CLOSE_VIEW_ACTIVITY) {
626 finish();
Jeff Hamilton5297c6a2009-10-01 02:22:33 -0700627 } else if (resultCode == Activity.RESULT_OK) {
Dmitri Plotnikov160e9da2009-09-30 23:48:12 -0700628 mLookupUri = intent.getData();
629 if (mLookupUri == null) {
630 finish();
631 }
Evan Millardf181202009-09-30 15:15:51 -0700632 }
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700633 }
634 }
635
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700636 private void splitContact(long rawContactId) {
Dmitri Plotnikovf40ccdf2009-09-04 17:37:15 -0700637 setAggregationException(rawContactId, AggregationExceptions.TYPE_KEEP_SEPARATE);
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700638
639 // The split operation may have removed the original aggregate contact, so we need
640 // to requery everything
Dmitri Plotnikov040dc152009-09-03 15:17:56 -0700641 Toast.makeText(this, R.string.contactsSplitMessage, Toast.LENGTH_LONG).show();
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700642 startEntityQuery();
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700643 }
644
Dmitri Plotnikovf40ccdf2009-09-04 17:37:15 -0700645 private void joinAggregate(final long contactId) {
Dmitri Plotnikov39466592009-07-27 11:23:51 -0700646 Cursor c = mResolver.query(RawContacts.CONTENT_URI, new String[] {RawContacts._ID},
Dmitri Plotnikovf40ccdf2009-09-04 17:37:15 -0700647 RawContacts.CONTACT_ID + "=" + contactId, null, null);
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700648
649 try {
650 while(c.moveToNext()) {
Dmitri Plotnikovf40ccdf2009-09-04 17:37:15 -0700651 long rawContactId = c.getLong(0);
652 setAggregationException(rawContactId, AggregationExceptions.TYPE_KEEP_TOGETHER);
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700653 }
654 } finally {
655 c.close();
656 }
657
Dmitri Plotnikov040dc152009-09-03 15:17:56 -0700658 Toast.makeText(this, R.string.contactsJoinedMessage, Toast.LENGTH_LONG).show();
659 startEntityQuery();
Dmitri Plotnikov49f705f2009-06-17 18:31:56 -0700660 }
661
662 /**
663 * Given a contact ID sets an aggregation exception to either join the contact with the
664 * current aggregate or split off.
665 */
Dmitri Plotnikov99eafe72009-09-03 14:09:45 -0700666 protected void setAggregationException(long rawContactId, int exceptionType) {
Dmitri Plotnikovd09f75c2009-06-16 11:59:22 -0700667 ContentValues values = new ContentValues(3);
Dmitri Plotnikovf40ccdf2009-09-04 17:37:15 -0700668 for (long aRawContactId : mRawContactIds) {
669 if (aRawContactId != rawContactId) {
670 values.put(AggregationExceptions.RAW_CONTACT_ID1, aRawContactId);
671 values.put(AggregationExceptions.RAW_CONTACT_ID2, rawContactId);
672 values.put(AggregationExceptions.TYPE, exceptionType);
673 mResolver.update(AggregationExceptions.CONTENT_URI, values, null, null);
674 }
675 }
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700676 }
677
Dmitri Plotnikovef038722009-06-24 18:51:47 -0700678 private void showOptionsActivity() {
679 final Intent intent = new Intent(this, ContactOptionsActivity.class);
Evan Millar6a61a1a2009-09-29 14:00:43 -0700680 intent.setData(mLookupUri);
Dmitri Plotnikovef038722009-06-24 18:51:47 -0700681 startActivity(intent);
682 }
683
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700684 private ViewEntry getViewEntryForMenuItem(MenuItem item) {
685 AdapterView.AdapterContextMenuInfo info;
686 try {
687 info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
688 } catch (ClassCastException e) {
689 Log.e(TAG, "bad menuInfo", e);
690 return null;
691 }
692
693 return ContactEntryAdapter.getEntry(mSections, info.position, SHOW_SEPARATORS);
694 }
695
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800696 @Override
697 public boolean onKeyDown(int keyCode, KeyEvent event) {
698 switch (keyCode) {
699 case KeyEvent.KEYCODE_CALL: {
700 try {
701 ITelephony phone = ITelephony.Stub.asInterface(
702 ServiceManager.checkService("phone"));
703 if (phone != null && !phone.isIdle()) {
704 // Skip out and let the key be handled at a higher level
705 break;
706 }
707 } catch (RemoteException re) {
708 // Fall through and try to call the contact
709 }
710
Evan Millar7911ff52009-07-21 15:55:18 -0700711 int index = mListView.getSelectedItemPosition();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800712 if (index != -1) {
713 ViewEntry entry = ViewAdapter.getEntry(mSections, index, SHOW_SEPARATORS);
Evan Millar66388be2009-05-28 15:41:07 -0700714 if (entry.intent.getAction() == Intent.ACTION_CALL_PRIVILEGED) {
715 startActivity(entry.intent);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800716 }
717 } else if (mNumPhoneNumbers != 0) {
718 // There isn't anything selected, call the default number
Evan Millar6a61a1a2009-09-29 14:00:43 -0700719 long freshContactId = getRefreshedContactId();
720 if (freshContactId > 0) {
721 Uri hardContacUri = ContentUris.withAppendedId(
722 Contacts.CONTENT_URI, freshContactId);
723 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, hardContacUri);
724 startActivity(intent);
725 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800726 }
727 return true;
728 }
729
730 case KeyEvent.KEYCODE_DEL: {
Evan Millarcdeea942009-10-07 11:47:35 -0700731 if (mReadOnlySourcesCnt > 0 & mWritableSourcesCnt > 0) {
Megha Joshid5afd8a2009-09-22 09:38:41 -0700732 showDialog(DIALOG_CONFIRM_READONLY_DELETE);
Evan Millarcdeea942009-10-07 11:47:35 -0700733 } else if (mReadOnlySourcesCnt > 0 && mWritableSourcesCnt == 0) {
Megha Joshic508bd82009-10-01 17:31:49 -0700734 showDialog(DIALOG_CONFIRM_READONLY_HIDE);
Evan Millarcdeea942009-10-07 11:47:35 -0700735 } else if (mReadOnlySourcesCnt == 0 && mWritableSourcesCnt > 1) {
736 showDialog(DIALOG_CONFIRM_MULTIPLE_DELETE);
737 } else {
738 showDialog(DIALOG_CONFIRM_DELETE);
739 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800740 return true;
741 }
742 }
743
744 return super.onKeyDown(keyCode, event);
745 }
746
Evan Millar7911ff52009-07-21 15:55:18 -0700747 public void onItemClick(AdapterView parent, View v, int position, long id) {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800748 ViewEntry entry = ViewAdapter.getEntry(mSections, position, SHOW_SEPARATORS);
749 if (entry != null) {
750 Intent intent = entry.intent;
Evan Millardf181202009-09-30 15:15:51 -0700751 if (intent != null) {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800752 try {
753 startActivity(intent);
754 } catch (ActivityNotFoundException e) {
755 Log.e(TAG, "No activity found for intent: " + intent);
756 signalError();
757 }
758 } else {
759 signalError();
760 }
761 } else {
762 signalError();
763 }
764 }
765
766 /**
767 * Signal an error to the user via a beep, or some other method.
768 */
769 private void signalError() {
770 //TODO: implement this when we have the sonification APIs
771 }
772
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800773 /**
774 * Build up the entries to display on the screen.
Evan Millar5c22c3b2009-05-29 11:37:54 -0700775 *
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800776 * @param personCursor the URI for the contact being displayed
777 */
Evan Millar11d628c2009-09-02 08:55:01 -0700778 private final void buildEntries() {
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800779 // Clear out the old entries
780 final int numSections = mSections.size();
781 for (int i = 0; i < numSections; i++) {
782 mSections.get(i).clear();
783 }
784
Evan Millar7911ff52009-07-21 15:55:18 -0700785 mRawContactIds.clear();
Jeff Sharkeye0408762009-11-03 12:57:16 -0800786
Megha Joshid5afd8a2009-09-22 09:38:41 -0700787 mReadOnlySourcesCnt = 0;
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700788 mWritableSourcesCnt = 0;
Jeff Sharkeye0408762009-11-03 12:57:16 -0800789 mAllRestricted = true;
790
Megha Joshid5afd8a2009-09-22 09:38:41 -0700791 mWritableRawContactIds.clear();
Dmitri Plotnikovb4491ee2009-06-15 09:31:02 -0700792
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700793 final Context context = this;
794 final Sources sources = Sources.getInstance(context);
Evan Millar11d628c2009-09-02 08:55:01 -0700795
Evan Millar66388be2009-05-28 15:41:07 -0700796 // Build up method entries
Evan Millar6a61a1a2009-09-29 14:00:43 -0700797 if (mLookupUri != null) {
Evan Millar11d628c2009-09-02 08:55:01 -0700798 for (Entity entity: mEntities) {
799 final ContentValues entValues = entity.getEntityValues();
800 final String accountType = entValues.getAsString(RawContacts.ACCOUNT_TYPE);
Jeff Sharkeyab066932009-09-21 09:55:30 -0700801 final long rawContactId = entValues.getAsLong(RawContacts._ID);
Evan Millar7911ff52009-07-21 15:55:18 -0700802
Jeff Sharkeye0408762009-11-03 12:57:16 -0800803 // Mark when this contact has any unrestricted components
804 final boolean isRestricted = entValues.getAsInteger(RawContacts.IS_RESTRICTED) != 0;
805 if (!isRestricted) mAllRestricted = false;
806
Dmitri Plotnikov2a8cef02009-09-23 19:01:15 -0700807 if (!mRawContactIds.contains(rawContactId)) {
808 mRawContactIds.add(rawContactId);
809 }
Megha Joshic508bd82009-10-01 17:31:49 -0700810 ContactsSource contactsSource = sources.getInflatedSource(accountType,
811 ContactsSource.LEVEL_SUMMARY);
812 if (contactsSource != null && contactsSource.readOnly) {
813 mReadOnlySourcesCnt += 1;
814 } else {
815 mWritableSourcesCnt += 1;
Evan Millarcdeea942009-10-07 11:47:35 -0700816 mWritableRawContactIds.add(rawContactId);
817 }
Megha Joshic508bd82009-10-01 17:31:49 -0700818
Dmitri Plotnikov2a8cef02009-09-23 19:01:15 -0700819
Evan Millar11d628c2009-09-02 08:55:01 -0700820 for (NamedContentValues subValue : entity.getSubValues()) {
Jeff Sharkeyab066932009-09-21 09:55:30 -0700821 final ContentValues entryValues = subValue.values;
822 entryValues.put(Data.RAW_CONTACT_ID, rawContactId);
823
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700824 final long dataId = entryValues.getAsLong(Data._ID);
825 final String mimeType = entryValues.getAsString(Data.MIMETYPE);
826 if (mimeType == null) continue;
Evan Millar66388be2009-05-28 15:41:07 -0700827
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700828 final DataKind kind = sources.getKindOrFallback(accountType, mimeType, this,
Evan Millar11d628c2009-09-02 08:55:01 -0700829 ContactsSource.LEVEL_MIMETYPES);
Jeff Sharkeyab066932009-09-21 09:55:30 -0700830 if (kind == null) continue;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800831
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700832 final ViewEntry entry = ViewEntry.fromValues(context, mimeType, kind,
833 rawContactId, dataId, entryValues);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800834
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700835 final boolean hasData = !TextUtils.isEmpty(entry.data);
Evan Millarff04a272009-09-26 15:23:37 -0700836 final boolean isSuperPrimary = entryValues.getAsInteger(
837 Data.IS_SUPER_PRIMARY) != 0;
Evan Millar11d628c2009-09-02 08:55:01 -0700838
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700839 if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
Evan Millarff04a272009-09-26 15:23:37 -0700840 // Build phone entries
841 mNumPhoneNumbers++;
Evan Millar11d628c2009-09-02 08:55:01 -0700842
Evan Millarff04a272009-09-26 15:23:37 -0700843 entry.intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700844 Uri.fromParts(Constants.SCHEME_TEL, entry.data, null));
Evan Millarff04a272009-09-26 15:23:37 -0700845 entry.secondaryIntent = new Intent(Intent.ACTION_SENDTO,
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700846 Uri.fromParts(Constants.SCHEME_SMSTO, entry.data, null));
Evan Millar49714ee2009-09-02 16:42:47 -0700847
Evan Millarff04a272009-09-26 15:23:37 -0700848 entry.isPrimary = isSuperPrimary;
849 mPhoneEntries.add(entry);
850
851 if (entry.type == CommonDataKinds.Phone.TYPE_MOBILE
852 || mShowSmsLinksForAllPhones) {
853 // Add an SMS entry
854 if (kind.iconAltRes > 0) {
855 entry.secondaryActionIcon = kind.iconAltRes;
Evan Millar49714ee2009-09-02 16:42:47 -0700856 }
Evan Millarff04a272009-09-26 15:23:37 -0700857 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700858 } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
Evan Millarff04a272009-09-26 15:23:37 -0700859 // Build email entries
860 entry.intent = new Intent(Intent.ACTION_SENDTO,
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700861 Uri.fromParts(Constants.SCHEME_MAILTO, entry.data, null));
Evan Millarff04a272009-09-26 15:23:37 -0700862 entry.isPrimary = isSuperPrimary;
863 mEmailEntries.add(entry);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700864
865 // When Email rows have status, create additional Im row
866 final DataStatus status = mStatuses.get(entry.id);
867 if (status != null) {
868 final String imMime = Im.CONTENT_ITEM_TYPE;
869 final DataKind imKind = sources.getKindOrFallback(accountType,
870 imMime, this, ContactsSource.LEVEL_MIMETYPES);
871 final ViewEntry imEntry = ViewEntry.fromValues(context,
872 imMime, imKind, rawContactId, dataId, entryValues);
873 imEntry.intent = ContactsUtils.buildImIntent(entryValues);
874 imEntry.applyStatus(status, false);
875 mImEntries.add(imEntry);
876 }
877 } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
Evan Millarff04a272009-09-26 15:23:37 -0700878 // Build postal entries
879 entry.maxLines = 4;
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700880 entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
Evan Millarff04a272009-09-26 15:23:37 -0700881 mPostalEntries.add(entry);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700882 } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
883 // Build IM entries
884 entry.intent = ContactsUtils.buildImIntent(entryValues);
Evan Millarff04a272009-09-26 15:23:37 -0700885 if (TextUtils.isEmpty(entry.label)) {
886 entry.label = getString(R.string.chat).toLowerCase();
887 }
Evan Millar11d628c2009-09-02 08:55:01 -0700888
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700889 // Apply presence and status details when available
890 final DataStatus status = mStatuses.get(entry.id);
891 if (status != null) {
892 entry.applyStatus(status, false);
Evan Millarff04a272009-09-26 15:23:37 -0700893 }
Evan Millarff04a272009-09-26 15:23:37 -0700894 mImEntries.add(entry);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700895 } else if ((Organization.CONTENT_ITEM_TYPE.equals(mimeType)
896 || Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) && hasData) {
Evan Millarff04a272009-09-26 15:23:37 -0700897 // Build organization and note entries
898 entry.uri = null;
Evan Millar11d628c2009-09-02 08:55:01 -0700899 mOrganizationEntries.add(entry);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700900 } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
Evan Millar11d628c2009-09-02 08:55:01 -0700901 // Build note entries
Evan Millar11d628c2009-09-02 08:55:01 -0700902 entry.uri = null;
Evan Millar11d628c2009-09-02 08:55:01 -0700903 entry.maxLines = 10;
904 mOtherEntries.add(entry);
Evan Millar951fa9c2009-10-26 14:57:43 -0700905 } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
906 // Build note entries
907 entry.uri = null;
908 entry.maxLines = 10;
909 try {
910 WebAddress webAddress = new WebAddress(entry.data);
Makoto Onuki7a707382009-11-19 13:35:55 +0900911 entry.intent = new Intent(Intent.ACTION_VIEW,
Evan Millar951fa9c2009-10-26 14:57:43 -0700912 Uri.parse(webAddress.toString()));
913 } catch (ParseException e) {
914 Log.e(TAG, "Couldn't parse website: " + entry.data);
915 }
916 mOtherEntries.add(entry);
Jeff Sharkeyab066932009-09-21 09:55:30 -0700917 } else {
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700918 // Handle showing custom rows
Evan Millarff04a272009-09-26 15:23:37 -0700919 entry.intent = new Intent(Intent.ACTION_VIEW, entry.uri);
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700920
921 // Use social summary when requested by external source
922 final DataStatus status = mStatuses.get(entry.id);
923 final boolean hasSocial = kind.actionBodySocial && status != null;
924 if (hasSocial) {
925 entry.applyStatus(status, true);
926 }
927
928 if (hasSocial || hasData) {
929 mOtherEntries.add(entry);
930 }
Evan Millar11d628c2009-09-02 08:55:01 -0700931 }
Evan Millar2e1b8af2009-09-24 09:39:21 -0700932 }
Evan Millar66388be2009-05-28 15:41:07 -0700933 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800934 }
935 }
936
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700937 static String buildActionString(DataKind kind, ContentValues values, boolean lowerCase,
938 Context context) {
Evan Millar11d628c2009-09-02 08:55:01 -0700939 if (kind.actionHeader == null) {
940 return null;
Jeff Hamilton8350e5b2009-03-24 21:01:34 -0700941 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700942 CharSequence actionHeader = kind.actionHeader.inflateUsing(context, values);
Evan Millar11d628c2009-09-02 08:55:01 -0700943 if (actionHeader == null) {
944 return null;
945 }
946 return lowerCase ? actionHeader.toString().toLowerCase() : actionHeader.toString();
947 }
Jeff Hamilton8350e5b2009-03-24 21:01:34 -0700948
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700949 static String buildDataString(DataKind kind, ContentValues values, Context context) {
Evan Millar11d628c2009-09-02 08:55:01 -0700950 if (kind.actionBody == null) {
951 return null;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800952 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700953 CharSequence actionBody = kind.actionBody.inflateUsing(context, values);
Evan Millar11d628c2009-09-02 08:55:01 -0700954 return actionBody == null ? null : actionBody.toString();
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800955 }
Evan Millar5c22c3b2009-05-29 11:37:54 -0700956
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800957 /**
958 * A basic structure with the data for a contact entry in the list.
959 */
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700960 static class ViewEntry extends ContactEntryAdapter.Entry implements Collapsible<ViewEntry> {
961 public Context context = null;
Jeff Sharkeyab066932009-09-21 09:55:30 -0700962 public String resPackageName = null;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800963 public int actionIcon = -1;
Evan Millar15e514d2009-08-04 10:14:57 -0700964 public boolean isPrimary = false;
Evan Millar15e514d2009-08-04 10:14:57 -0700965 public int secondaryActionIcon = -1;
966 public Intent intent;
967 public Intent secondaryIntent = null;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800968 public int maxLabelLines = 1;
Evan Millar54a5c9f2009-06-23 17:41:09 -0700969 public ArrayList<Long> ids = new ArrayList<Long>();
970 public int collapseCount = 0;
971
Jeff Sharkey624ddc32009-10-01 21:32:19 -0700972 public int presence = -1;
973 public int presenceIcon = -1;
974
975 public CharSequence footerLine = null;
976
977 private ViewEntry() {
978 }
979
980 /**
981 * Build new {@link ViewEntry} and populate from the given values.
982 */
983 public static ViewEntry fromValues(Context context, String mimeType, DataKind kind,
984 long rawContactId, long dataId, ContentValues values) {
985 final ViewEntry entry = new ViewEntry();
986 entry.context = context;
987 entry.contactId = rawContactId;
988 entry.id = dataId;
989 entry.uri = ContentUris.withAppendedId(Data.CONTENT_URI, entry.id);
990 entry.mimetype = mimeType;
991 entry.label = buildActionString(kind, values, false, context);
992 entry.data = buildDataString(kind, values, context);
993
994 if (kind.typeColumn != null && values.containsKey(kind.typeColumn)) {
995 entry.type = values.getAsInteger(kind.typeColumn);
996 }
997 if (kind.iconRes > 0) {
998 entry.resPackageName = kind.resPackageName;
999 entry.actionIcon = kind.iconRes;
1000 }
1001
1002 return entry;
1003 }
1004
1005 /**
1006 * Apply given {@link DataStatus} values over this {@link ViewEntry}
1007 *
1008 * @param fillData When true, the given status replaces {@link #data}
1009 * and {@link #footerLine}. Otherwise only {@link #presence}
1010 * is updated.
1011 */
1012 public ViewEntry applyStatus(DataStatus status, boolean fillData) {
1013 presence = status.getPresence();
1014 presenceIcon = (presence == -1) ? -1 :
1015 StatusUpdates.getPresenceIconResourceId(this.presence);
1016
1017 if (fillData && status.isValid()) {
1018 this.data = status.getStatus().toString();
1019 this.footerLine = status.getTimestampLabel(context);
1020 }
1021
1022 return this;
1023 }
1024
Evan Millar54a5c9f2009-06-23 17:41:09 -07001025 public boolean collapseWith(ViewEntry entry) {
1026 // assert equal collapse keys
Evan Millaradb0f8c2009-09-28 17:20:50 -07001027 if (!shouldCollapseWith(entry)) {
Evan Millar54a5c9f2009-06-23 17:41:09 -07001028 return false;
1029 }
1030
1031 // Choose the label associated with the highest type precedence.
1032 if (TypePrecedence.getTypePrecedence(mimetype, type)
1033 > TypePrecedence.getTypePrecedence(entry.mimetype, entry.type)) {
1034 type = entry.type;
1035 label = entry.label;
1036 }
1037
1038 // Choose the max of the maxLines and maxLabelLines values.
1039 maxLines = Math.max(maxLines, entry.maxLines);
1040 maxLabelLines = Math.max(maxLabelLines, entry.maxLabelLines);
1041
1042 // Choose the presence with the highest precedence.
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001043 if (StatusUpdates.getPresencePrecedence(presence)
1044 < StatusUpdates.getPresencePrecedence(entry.presence)) {
1045 presence = entry.presence;
Evan Millar54a5c9f2009-06-23 17:41:09 -07001046 }
1047
1048 // If any of the collapsed entries are primary make the whole thing primary.
Evan Millar15e514d2009-08-04 10:14:57 -07001049 isPrimary = entry.isPrimary ? true : isPrimary;
Evan Millar54a5c9f2009-06-23 17:41:09 -07001050
1051 // uri, and contactdId, shouldn't make a difference. Just keep the original.
1052
1053 // Keep track of all the ids that have been collapsed with this one.
1054 ids.add(entry.id);
1055 collapseCount++;
1056 return true;
1057 }
1058
Evan Millaradb0f8c2009-09-28 17:20:50 -07001059 public boolean shouldCollapseWith(ViewEntry entry) {
1060 if (entry == null) {
1061 return false;
1062 }
1063
Makoto Onukic710b0e2009-10-13 15:43:24 -07001064 if (!ContactsUtils.areDataEqual(context, mimetype, data, entry.mimetype, entry.data)) {
1065 return false;
Evan Millaradb0f8c2009-09-28 17:20:50 -07001066 }
1067
Makoto Onukic710b0e2009-10-13 15:43:24 -07001068 if (!TextUtils.equals(mimetype, entry.mimetype)
1069 || !ContactsUtils.areIntentActionEqual(intent, entry.intent)
1070 || !ContactsUtils.areIntentActionEqual(secondaryIntent, entry.secondaryIntent)
Evan Millaradb0f8c2009-09-28 17:20:50 -07001071 || actionIcon != entry.actionIcon) {
1072 return false;
1073 }
1074
1075 return true;
1076 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001077 }
1078
Evan Millar15e514d2009-08-04 10:14:57 -07001079 /** Cache of the children views of a row */
1080 static class ViewCache {
1081 public TextView label;
1082 public TextView data;
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001083 public TextView footer;
Evan Millar15e514d2009-08-04 10:14:57 -07001084 public ImageView actionIcon;
1085 public ImageView presenceIcon;
1086 public ImageView primaryIcon;
1087 public ImageView secondaryActionButton;
1088 public View secondaryActionDivider;
Evan Millar5c22c3b2009-05-29 11:37:54 -07001089
Evan Millar15e514d2009-08-04 10:14:57 -07001090 // Need to keep track of this too
1091 ViewEntry entry;
1092 }
1093
1094 private final class ViewAdapter extends ContactEntryAdapter<ViewEntry>
1095 implements View.OnClickListener {
1096
Evan Millar5c22c3b2009-05-29 11:37:54 -07001097
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001098 ViewAdapter(Context context, ArrayList<ArrayList<ViewEntry>> sections) {
1099 super(context, sections, SHOW_SEPARATORS);
1100 }
1101
Evan Millar15e514d2009-08-04 10:14:57 -07001102 public void onClick(View v) {
1103 Intent intent = (Intent) v.getTag();
1104 startActivity(intent);
1105 }
1106
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001107 @Override
1108 public View getView(int position, View convertView, ViewGroup parent) {
Evan Millar5c22c3b2009-05-29 11:37:54 -07001109 ViewEntry entry = getEntry(mSections, position, false);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001110 View v;
1111
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001112 ViewCache views;
1113
1114 // Check to see if we can reuse convertView
1115 if (convertView != null) {
1116 v = convertView;
1117 views = (ViewCache) v.getTag();
1118 } else {
1119 // Create a new view if needed
1120 v = mInflater.inflate(R.layout.list_item_text_icons, parent, false);
1121
1122 // Cache the children
1123 views = new ViewCache();
1124 views.label = (TextView) v.findViewById(android.R.id.text1);
1125 views.data = (TextView) v.findViewById(android.R.id.text2);
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001126 views.footer = (TextView) v.findViewById(R.id.footer);
Evan Millar15e514d2009-08-04 10:14:57 -07001127 views.actionIcon = (ImageView) v.findViewById(R.id.action_icon);
1128 views.primaryIcon = (ImageView) v.findViewById(R.id.primary_icon);
1129 views.presenceIcon = (ImageView) v.findViewById(R.id.presence_icon);
1130 views.secondaryActionButton = (ImageView) v.findViewById(
1131 R.id.secondary_action_button);
1132 views.secondaryActionButton.setOnClickListener(this);
Evan Millar15e514d2009-08-04 10:14:57 -07001133 views.secondaryActionDivider = v.findViewById(R.id.divider);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001134 v.setTag(views);
1135 }
1136
1137 // Update the entry in the view cache
1138 views.entry = entry;
1139
1140 // Bind the data to the view
1141 bindView(v, entry);
1142 return v;
1143 }
1144
1145 @Override
1146 protected View newView(int position, ViewGroup parent) {
1147 // getView() handles this
1148 throw new UnsupportedOperationException();
1149 }
1150
1151 @Override
1152 protected void bindView(View view, ViewEntry entry) {
1153 final Resources resources = mContext.getResources();
1154 ViewCache views = (ViewCache) view.getTag();
1155
1156 // Set the label
1157 TextView label = views.label;
1158 setMaxLines(label, entry.maxLabelLines);
1159 label.setText(entry.label);
1160
1161 // Set the data
1162 TextView data = views.data;
1163 if (data != null) {
Evan Millar54a5c9f2009-06-23 17:41:09 -07001164 if (entry.mimetype.equals(Phone.CONTENT_ITEM_TYPE)
Jeff Sharkey49d17b32009-09-07 02:14:21 -07001165 || entry.mimetype.equals(Constants.MIME_SMS_ADDRESS)) {
Evan Millar54a5c9f2009-06-23 17:41:09 -07001166 data.setText(PhoneNumberUtils.formatNumber(entry.data));
1167 } else {
1168 data.setText(entry.data);
1169 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001170 setMaxLines(data, entry.maxLines);
1171 }
1172
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001173 // Set the footer
1174 if (!TextUtils.isEmpty(entry.footerLine)) {
1175 views.footer.setText(entry.footerLine);
1176 views.footer.setVisibility(View.VISIBLE);
1177 } else {
1178 views.footer.setVisibility(View.GONE);
1179 }
1180
Evan Millar15e514d2009-08-04 10:14:57 -07001181 // Set the primary icon
1182 views.primaryIcon.setVisibility(entry.isPrimary ? View.VISIBLE : View.GONE);
1183
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001184 // Set the action icon
1185 ImageView action = views.actionIcon;
1186 if (entry.actionIcon != -1) {
Jeff Sharkeyab066932009-09-21 09:55:30 -07001187 Drawable actionIcon;
1188 if (entry.resPackageName != null) {
1189 // Load external resources through PackageManager
1190 actionIcon = mContext.getPackageManager().getDrawable(entry.resPackageName,
1191 entry.actionIcon, null);
1192 } else {
1193 actionIcon = resources.getDrawable(entry.actionIcon);
1194 }
1195 action.setImageDrawable(actionIcon);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001196 action.setVisibility(View.VISIBLE);
1197 } else {
1198 // Things should still line up as if there was an icon, so make it invisible
1199 action.setVisibility(View.INVISIBLE);
1200 }
1201
1202 // Set the presence icon
1203 Drawable presenceIcon = null;
Evan Millar15e514d2009-08-04 10:14:57 -07001204 if (entry.presenceIcon != -1) {
1205 presenceIcon = resources.getDrawable(entry.presenceIcon);
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001206 } else if (entry.presence != -1) {
Evan Millar54a5c9f2009-06-23 17:41:09 -07001207 presenceIcon = resources.getDrawable(
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001208 StatusUpdates.getPresenceIconResourceId(entry.presence));
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001209 }
Evan Millar15e514d2009-08-04 10:14:57 -07001210 ImageView presenceIconView = views.presenceIcon;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001211 if (presenceIcon != null) {
Evan Millar15e514d2009-08-04 10:14:57 -07001212 presenceIconView.setImageDrawable(presenceIcon);
1213 presenceIconView.setVisibility(View.VISIBLE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001214 } else {
Evan Millar15e514d2009-08-04 10:14:57 -07001215 presenceIconView.setVisibility(View.GONE);
1216 }
1217
1218 // Set the secondary action button
1219 ImageView secondaryActionView = views.secondaryActionButton;
1220 Drawable secondaryActionIcon = null;
1221 if (entry.secondaryActionIcon != -1) {
1222 secondaryActionIcon = resources.getDrawable(entry.secondaryActionIcon);
1223 }
1224 if (entry.secondaryIntent != null && secondaryActionIcon != null) {
1225 secondaryActionView.setImageDrawable(secondaryActionIcon);
1226 secondaryActionView.setTag(entry.secondaryIntent);
1227 secondaryActionView.setVisibility(View.VISIBLE);
1228 views.secondaryActionDivider.setVisibility(View.VISIBLE);
1229 } else {
1230 secondaryActionView.setVisibility(View.GONE);
1231 views.secondaryActionDivider.setVisibility(View.GONE);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001232 }
1233 }
1234
1235 private void setMaxLines(TextView textView, int maxLines) {
1236 if (maxLines == 1) {
1237 textView.setSingleLine(true);
1238 textView.setEllipsize(TextUtils.TruncateAt.END);
1239 } else {
1240 textView.setSingleLine(false);
1241 textView.setMaxLines(maxLines);
1242 textView.setEllipsize(null);
1243 }
1244 }
1245 }
Jeff Sharkey624ddc32009-10-01 21:32:19 -07001246
1247 private interface StatusQuery {
1248 final String[] PROJECTION = new String[] {
1249 Data._ID,
1250 Data.STATUS,
1251 Data.STATUS_RES_PACKAGE,
1252 Data.STATUS_ICON,
1253 Data.STATUS_LABEL,
1254 Data.STATUS_TIMESTAMP,
1255 Data.PRESENCE,
1256 };
1257
1258 final int _ID = 0;
1259 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001260}