PageRenderTime 35ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/CVox/src/com/android/contacts/ContactsListActivity.java

http://eyes-free.googlecode.com/
Java | 1437 lines | 667 code | 136 blank | 634 comment | 100 complexity | 9cbc043d250443b1896557300326e5a9 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0
  1. /*
  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. //package com.android.contacts;
  17. package com.android.contacts;
  18. import com.cvox.browser.R;
  19. import com.cvox.browser.R.drawable;
  20. import com.cvox.browser.R.layout;
  21. import com.cvox.browser.R.string;
  22. import android.app.Activity;
  23. import android.app.AlertDialog;
  24. import android.app.ListActivity;
  25. import android.app.SearchManager;
  26. import android.content.AsyncQueryHandler;
  27. import android.content.ContentResolver;
  28. import android.content.ContentUris;
  29. import android.content.ContentValues;
  30. import android.content.Context;
  31. import android.content.DialogInterface;
  32. import android.content.Intent;
  33. import android.content.SharedPreferences;
  34. import android.database.Cursor;
  35. import android.database.CharArrayBuffer;
  36. import android.graphics.Bitmap;
  37. import android.net.Uri;
  38. import android.os.Bundle;
  39. import android.os.Parcelable;
  40. import android.preference.PreferenceManager;
  41. import android.provider.Contacts;
  42. import android.provider.Contacts.ContactMethods;
  43. import android.provider.Contacts.Groups;
  44. import android.provider.Contacts.Intents;
  45. import android.provider.Contacts.People;
  46. import android.provider.Contacts.Phones;
  47. //import android.provider.Contacts.Presence;
  48. import android.provider.Contacts.Intents.UI;
  49. import android.telephony.PhoneNumberUtils;
  50. import android.text.TextUtils;
  51. import android.util.Log;
  52. import android.view.ContextMenu;
  53. import android.view.KeyEvent;
  54. import android.view.LayoutInflater;
  55. import android.view.Menu;
  56. import android.view.MenuItem;
  57. import android.view.View;
  58. import android.view.ViewGroup;
  59. import android.view.ContextMenu.ContextMenuInfo;
  60. import android.widget.AdapterView;
  61. import android.widget.ListView;
  62. import android.widget.ResourceCursorAdapter;
  63. import android.widget.TextView;
  64. import java.util.ArrayList;
  65. /**
  66. * Displays a list of contacts. Usually is embedded into the ContactsActivity.
  67. */
  68. public final class ContactsListActivity extends ListActivity
  69. implements View.OnCreateContextMenuListener, DialogInterface.OnClickListener {
  70. private static final String TAG = "ContactsListActivity";
  71. private static final String LIST_STATE_KEY = "liststate";
  72. private static final String FOCUS_KEY = "focused";
  73. static final int MENU_ITEM_VIEW_CONTACT = 1;
  74. static final int MENU_ITEM_CALL = 2;
  75. static final int MENU_ITEM_EDIT_BEFORE_CALL = 3;
  76. static final int MENU_ITEM_SEND_SMS = 4;
  77. static final int MENU_ITEM_SEND_IM = 5;
  78. static final int MENU_ITEM_EDIT = 6;
  79. static final int MENU_ITEM_DELETE = 7;
  80. static final int MENU_ITEM_TOGGLE_STAR = 8;
  81. public static final int MENU_DIALER = 9;
  82. public static final int MENU_NEW_CONTACT = 10;
  83. public static final int MENU_DISPLAY_GROUP = 11;
  84. private static final int SUBACTIVITY_NEW_CONTACT = 1;
  85. /** Mask for picker mode */
  86. static final int MODE_MASK_PICKER = 0x80000000;
  87. /** Mask for no presence mode */
  88. static final int MODE_MASK_NO_PRESENCE = 0x40000000;
  89. /** Mask for enabling list filtering */
  90. static final int MODE_MASK_NO_FILTER = 0x20000000;
  91. /** Mask for having a "create new contact" header in the list */
  92. static final int MODE_MASK_CREATE_NEW = 0x10000000;
  93. /** Unknown mode */
  94. static final int MODE_UNKNOWN = 0;
  95. /** Show members of the "Contacts" group */
  96. static final int MODE_GROUP = 5;
  97. /** Show all contacts sorted alphabetically */
  98. static final int MODE_ALL_CONTACTS = 10;
  99. /** Show all contacts with phone numbers, sorted alphabetically */
  100. static final int MODE_WITH_PHONES = 15;
  101. /** Show all starred contacts */
  102. static final int MODE_STARRED = 20;
  103. /** Show frequently contacted contacts */
  104. static final int MODE_FREQUENT = 30;
  105. /** Show starred and the frequent */
  106. static final int MODE_STREQUENT = 35;
  107. /** Show all contacts and pick them when clicking */
  108. static final int MODE_PICK_CONTACT = 40 | MODE_MASK_PICKER;
  109. /** Show all contacts as well as the option to create a new one */
  110. static final int MODE_PICK_OR_CREATE_CONTACT = 42 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW;
  111. /** Show all contacts and pick them when clicking, and allow creating a new contact */
  112. static final int MODE_INSERT_OR_EDIT_CONTACT = 45 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW;
  113. /** Show all phone numbers and pick them when clicking */
  114. static final int MODE_PICK_PHONE = 50 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE;
  115. /** Show all postal addresses and pick them when clicking */
  116. static final int MODE_PICK_POSTAL =
  117. 55 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
  118. /** Show all email addresses and pick them when clicking */
  119. static final int MODE_PICK_EMAIL = 56 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
  120. /** Run a search query */
  121. static final int MODE_QUERY = 60 | MODE_MASK_NO_FILTER;
  122. static final int DEFAULT_MODE = MODE_ALL_CONTACTS;
  123. static final String NAME_COLUMN = People.DISPLAY_NAME;
  124. static final String[] CONTACTS_PROJECTION = new String[] {
  125. People._ID, // 0
  126. NAME_COLUMN, // 1
  127. People.NUMBER, // 2
  128. People.TYPE, // 3
  129. People.LABEL, // 4
  130. People.STARRED, // 5
  131. People.PRIMARY_PHONE_ID, // 6
  132. People.PRIMARY_EMAIL_ID, // 7
  133. // People.PRESENCE_STATUS, // 8
  134. };
  135. static final String[] STREQUENT_PROJECTION = new String[] {
  136. People._ID, // 0
  137. NAME_COLUMN, // 1
  138. People.NUMBER, // 2
  139. People.TYPE, // 3
  140. People.LABEL, // 4
  141. People.STARRED, // 5
  142. People.PRIMARY_PHONE_ID, // 6
  143. People.PRIMARY_EMAIL_ID, // 7
  144. // People.PRESENCE_STATUS, // 8
  145. People.TIMES_CONTACTED, // 9 (not displayed, but required for the order by to work)
  146. };
  147. static final String[] PHONES_PROJECTION = new String[] {
  148. Phones._ID, // 0
  149. NAME_COLUMN, // 1
  150. Phones.NUMBER, // 2
  151. Phones.TYPE, // 3
  152. Phones.LABEL, // 4
  153. Phones.STARRED, // 5
  154. };
  155. static final String[] CONTACT_METHODS_PROJECTION = new String[] {
  156. ContactMethods._ID, // 0
  157. NAME_COLUMN, // 1
  158. ContactMethods.DATA, // 2
  159. ContactMethods.TYPE, // 3
  160. ContactMethods.LABEL, // 4
  161. ContactMethods.STARRED, // 5
  162. };
  163. static final int ID_COLUMN_INDEX = 0;
  164. static final int NAME_COLUMN_INDEX = 1;
  165. static final int NUMBER_COLUMN_INDEX = 2;
  166. static final int DATA_COLUMN_INDEX = 2;
  167. static final int TYPE_COLUMN_INDEX = 3;
  168. static final int LABEL_COLUMN_INDEX = 4;
  169. static final int STARRED_COLUMN_INDEX = 5;
  170. static final int PRIMARY_PHONE_ID_COLUMN_INDEX = 6;
  171. static final int PRIMARY_EMAIL_ID_COLUMN_INDEX = 7;
  172. static final int SERVER_STATUS_COLUMN_INDEX = 8;
  173. static final int DISPLAY_GROUP_INDEX_ALL_CONTACTS = 0;
  174. static final int DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES = 1;
  175. static final int DISPLAY_GROUP_INDEX_MY_CONTACTS = 2;
  176. static final String SORT_ORDER = NAME_COLUMN + " COLLATE LOCALIZED ASC";
  177. private static final int QUERY_TOKEN = 42;
  178. private static final String[] GROUPS_PROJECTION = new String[] {
  179. Groups.SYSTEM_ID, // 0
  180. Groups.NAME, // 1
  181. };
  182. private static final int GROUPS_COLUMN_INDEX_SYSTEM_ID = 0;
  183. private static final int GROUPS_COLUMN_INDEX_NAME = 1;
  184. static final String GROUP_WITH_PHONES = "android_smartgroup_phone";
  185. ContactItemListAdapter mAdapter;
  186. private int mMode = DEFAULT_MODE;
  187. // The current display group
  188. private String mDisplayInfo;
  189. private int mDisplayType;
  190. // The current list of display groups, during selection from menu
  191. private CharSequence[] mDisplayGroups;
  192. // If true position 2 in mDisplayGroups is the MyContacts group
  193. private boolean mDisplayGroupsIncludesMyContacts = false;
  194. private int mDisplayGroupOriginalSelection;
  195. private int mDisplayGroupCurrentSelection;
  196. private QueryHandler mQueryHandler;
  197. private String mQuery;
  198. private Uri mGroupFilterUri;
  199. private Uri mGroupUri;
  200. private boolean mJustCreated;
  201. /**
  202. * Used to keep track of the scroll state of the list.
  203. */
  204. private Parcelable mListState = null;
  205. private boolean mListHasFocus;
  206. private boolean mCreateShortcut;
  207. private boolean mDefaultMode = false;
  208. private class DeleteClickListener implements DialogInterface.OnClickListener {
  209. private Uri mUri;
  210. public DeleteClickListener(Uri uri) {
  211. mUri = uri;
  212. }
  213. public void onClick(DialogInterface dialog, int which) {
  214. getContentResolver().delete(mUri, null, null);
  215. }
  216. }
  217. @Override
  218. protected void onCreate(Bundle icicle) {
  219. super.onCreate(icicle);
  220. // Make sure the preferences are setup
  221. // PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
  222. // Resolve the intent
  223. final Intent intent = getIntent();
  224. // Allow the title to be set to a custom String using an extra on the intent
  225. String title = intent.getStringExtra(Contacts.Intents.UI.TITLE_EXTRA_KEY);
  226. if (title != null) {
  227. setTitle(title);
  228. }
  229. final String action = intent.getAction();
  230. mMode = MODE_UNKNOWN;
  231. setContentView(R.layout.contacts_list_content);
  232. // if (UI.LIST_DEFAULT.equals(action)) {
  233. // mDefaultMode = true;
  234. // // When mDefaultMode is true the mode is set in onResume(), since the preferneces
  235. // // activity may change it whenever this activity isn't running
  236. // } else if (UI.LIST_GROUP_ACTION.equals(action)) {
  237. // mMode = MODE_GROUP;
  238. // String groupName = intent.getStringExtra(UI.GROUP_NAME_EXTRA_KEY);
  239. // if (TextUtils.isEmpty(groupName)) {
  240. // finish();
  241. // return;
  242. // }
  243. // buildUserGroupUris(groupName);
  244. // } else if (UI.LIST_ALL_CONTACTS_ACTION.equals(action)) {
  245. // mMode = MODE_ALL_CONTACTS;
  246. // } else if (UI.LIST_STARRED_ACTION.equals(action)) {
  247. // mMode = MODE_STARRED;
  248. // } else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
  249. // mMode = MODE_FREQUENT;
  250. // } else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
  251. // mMode = MODE_STREQUENT;
  252. // } else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
  253. // mMode = MODE_WITH_PHONES;
  254. // } else if (Intent.ACTION_PICK.equals(action)) {
  255. // // XXX These should be showing the data from the URI given in
  256. // // the Intent.
  257. // final String type = intent.resolveType(this);
  258. // if (People.CONTENT_TYPE.equals(type)) {
  259. // mMode = MODE_PICK_CONTACT;
  260. // } else if (Phones.CONTENT_TYPE.equals(type)) {
  261. // mMode = MODE_PICK_PHONE;
  262. // } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(type)) {
  263. // mMode = MODE_PICK_POSTAL;
  264. // }
  265. // } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
  266. // mMode = MODE_PICK_OR_CREATE_CONTACT;
  267. // mCreateShortcut = true;
  268. // } else
  269. if (Intent.ACTION_GET_CONTENT.equals(action)) {
  270. final String type = intent.resolveType(this);
  271. if (People.CONTENT_ITEM_TYPE.equals(type)) {
  272. mMode = MODE_PICK_OR_CREATE_CONTACT;
  273. } else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
  274. mMode = MODE_PICK_PHONE;
  275. } else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
  276. mMode = MODE_PICK_POSTAL;
  277. } else if (ContactMethods.CONTENT_EMAIL_ITEM_TYPE.equals(type)) {
  278. mMode = MODE_PICK_EMAIL;
  279. }
  280. // } else if (Intent.ACTION_INSERT_OR_EDIT.equals(action)) {
  281. // mMode = MODE_INSERT_OR_EDIT_CONTACT;
  282. // } else if (Intent.ACTION_SEARCH.equals(action)) {
  283. // // See if the suggestion was clicked with a search action key (call button)
  284. // if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
  285. // String query = intent.getStringExtra(SearchManager.QUERY);
  286. // if (!TextUtils.isEmpty(query)) {
  287. // Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
  288. // Uri.fromParts("tel", query, null));
  289. // startActivity(newIntent);
  290. // }
  291. // finish();
  292. // return;
  293. // }
  294. // // Otherwise handle the more normal search case
  295. // mMode = MODE_QUERY;
  296. //
  297. // // Since this is the filter activity it receives all intents
  298. // // dispatched from the SearchManager for security reasons
  299. // // so we need to re-dispatch from here to the intended target.
  300. // } else if (Intents.SEARCH_SUGGESTION_CLICKED.equals(action)) {
  301. // // See if the suggestion was clicked with a search action key (call button)
  302. // Intent newIntent;
  303. // if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
  304. // newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
  305. // } else {
  306. // newIntent = new Intent(Intent.ACTION_VIEW, intent.getData());
  307. // }
  308. // startActivity(newIntent);
  309. // finish();
  310. // return;
  311. // } else if (Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED.equals(action)) {
  312. // Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
  313. // startActivity(newIntent);
  314. // finish();
  315. // return;
  316. // } else if (Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED.equals(action)) {
  317. // String number = intent.getData().getSchemeSpecificPart();
  318. // Intent newIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
  319. // newIntent.putExtra(Intents.Insert.PHONE, number);
  320. // startActivity(newIntent);
  321. // finish();
  322. // return;
  323. }
  324. // if (mMode == MODE_UNKNOWN) {
  325. // mMode = DEFAULT_MODE;
  326. // }
  327. /*
  328. if (!mDefaultMode) {
  329. findViewById(R.id.contact_group).banner.setVisibility(View.GONE);
  330. }
  331. */
  332. // Setup the UI
  333. final ListView list = getListView();
  334. list.setFocusable(true);
  335. list.setOnCreateContextMenuListener(this);
  336. // if ((mMode & MODE_MASK_NO_FILTER) != MODE_MASK_NO_FILTER) {
  337. // list.setTextFilterEnabled(true);
  338. // }
  339. //
  340. // if ((mMode & MODE_MASK_CREATE_NEW) != 0) {
  341. // // Add the header for creating a new contact
  342. // final LayoutInflater inflater = getLayoutInflater();
  343. // View header = inflater.inflate(android.R.layout.simple_list_item_1, list, false);
  344. // TextView text = (TextView) header.findViewById(android.R.id.text1);
  345. // text.setText(R.string.pickerNewContactHeader);
  346. // list.addHeaderView(header);
  347. // }
  348. // Set the proper empty string
  349. setEmptyText();
  350. mAdapter = new ContactItemListAdapter(this, R.layout.contacts_list_item, null);
  351. setListAdapter(mAdapter);
  352. // We manually save/restore the listview state
  353. list.setSaveEnabled(false);
  354. mQueryHandler = new QueryHandler(this);
  355. mJustCreated = true;
  356. }
  357. private void setEmptyText() {
  358. // TextView empty = (TextView) findViewById(android.R.id.empty);
  359. // switch (mMode) {
  360. // case MODE_GROUP:
  361. // if (Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
  362. // empty.setText(getString(R.string.groupEmpty,
  363. // getText(R.string.groupNameMyContacts)));
  364. // } else {
  365. // empty.setText(getString(R.string.groupEmpty, mDisplayInfo));
  366. // }
  367. // break;
  368. //
  369. // case MODE_STARRED:
  370. // case MODE_STREQUENT:
  371. // case MODE_FREQUENT:
  372. // empty.setText(getText(R.string.noFavorites));
  373. // break;
  374. //
  375. // case MODE_WITH_PHONES:
  376. // empty.setText(getText(R.string.noContactsWithPhoneNumbers));
  377. // break;
  378. //
  379. // default:
  380. // empty.setText(getText(R.string.noContacts));
  381. // break;
  382. // }
  383. }
  384. /**
  385. * Builds the URIs to query when displaying a user group
  386. *
  387. * @param groupName the group being displayed
  388. */
  389. private void buildUserGroupUris(String groupName) {
  390. mGroupFilterUri = Uri.parse("content://contacts/groups/name/" + groupName
  391. + "/members/filter/");
  392. mGroupUri = Uri.parse("content://contacts/groups/name/" + groupName + "/members");
  393. }
  394. /**
  395. * Builds the URIs to query when displaying a system group
  396. *
  397. * @param systemId the system group's ID
  398. */
  399. private void buildSystemGroupUris(String systemId) {
  400. mGroupFilterUri = Uri.parse("content://contacts/groups/system_id/" + systemId
  401. + "/members/filter/");
  402. mGroupUri = Uri.parse("content://contacts/groups/system_id/" + systemId + "/members");
  403. }
  404. /**
  405. * Sets the mode when the request is for "default"
  406. */
  407. private void setDefaultMode() {
  408. // // Load the preferences
  409. // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
  410. //
  411. // // Lookup the group to display
  412. // mDisplayType = prefs.getInt(ContactsPreferenceActivity.PREF_DISPLAY_TYPE,
  413. // ContactsPreferenceActivity.DISPLAY_TYPE_UNKNOWN);
  414. // switch (mDisplayType) {
  415. // case ContactsPreferenceActivity.DISPLAY_TYPE_ALL_WITH_PHONES: {
  416. // mMode = MODE_WITH_PHONES;
  417. // mDisplayInfo = null;
  418. // break;
  419. // }
  420. //
  421. // case ContactsPreferenceActivity.DISPLAY_TYPE_SYSTEM_GROUP: {
  422. // String systemId = prefs.getString(
  423. // ContactsPreferenceActivity.PREF_DISPLAY_INFO, null);
  424. // if (!TextUtils.isEmpty(systemId)) {
  425. // // Display the selected system group
  426. // mMode = MODE_GROUP;
  427. // buildSystemGroupUris(systemId);
  428. // mDisplayInfo = systemId;
  429. // } else {
  430. // // No valid group is present, display everything
  431. // mMode = MODE_WITH_PHONES;
  432. // mDisplayInfo = null;
  433. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_ALL;
  434. // }
  435. // break;
  436. // }
  437. //
  438. // case ContactsPreferenceActivity.DISPLAY_TYPE_USER_GROUP: {
  439. // String displayGroup = prefs.getString(
  440. // ContactsPreferenceActivity.PREF_DISPLAY_INFO, null);
  441. // if (!TextUtils.isEmpty(displayGroup)) {
  442. // // Display the selected user group
  443. // mMode = MODE_GROUP;
  444. // buildUserGroupUris(displayGroup);
  445. // mDisplayInfo = displayGroup;
  446. // } else {
  447. // // No valid group is present, display everything
  448. // mMode = MODE_WITH_PHONES;
  449. // mDisplayInfo = null;
  450. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_ALL;
  451. // }
  452. // break;
  453. // }
  454. //
  455. // case ContactsPreferenceActivity.DISPLAY_TYPE_ALL: {
  456. // mMode = MODE_ALL_CONTACTS;
  457. // mDisplayInfo = null;
  458. // break;
  459. // }
  460. //
  461. // default: {
  462. // // We don't know what to display, default to My Contacts
  463. // mMode = MODE_GROUP;
  464. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_SYSTEM_GROUP;
  465. // buildSystemGroupUris(Groups.GROUP_MY_CONTACTS);
  466. // mDisplayInfo = Groups.GROUP_MY_CONTACTS;
  467. // break;
  468. // }
  469. // }
  470. //
  471. // // Update the empty text view with the proper string, as the group may have changed
  472. // setEmptyText();
  473. }
  474. @Override
  475. protected void onResume() {
  476. super.onResume();
  477. boolean runQuery = true;
  478. Activity parent = getParent();
  479. // Do this before setting the filter. The filter thread relies
  480. // on some state that is initialized in setDefaultMode
  481. if (mDefaultMode) {
  482. // If we're in default mode we need to possibly reset the mode due to a change
  483. // in the preferences activity while we weren't running
  484. setDefaultMode();
  485. }
  486. // See if we were invoked with a filter
  487. // if (parent != null && parent instanceof DialtactsActivity) {
  488. // String filterText = ((DialtactsActivity) parent).getAndClearFilterText();
  489. // if (filterText != null && filterText.length() > 0) {
  490. // getListView().setFilterText(filterText);
  491. // // Don't start a new query since it will conflict with the filter
  492. // runQuery = false;
  493. // } else if (mJustCreated) {
  494. // getListView().clearTextFilter();
  495. // }
  496. // }
  497. if (runQuery) {
  498. // Calling requery here may cause an ANR, so always do the async query
  499. startQuery();
  500. }
  501. mJustCreated = false;
  502. }
  503. private void updateGroup() {
  504. if (mDefaultMode) {
  505. setDefaultMode();
  506. }
  507. // Calling requery here may cause an ANR, so always do the async query
  508. startQuery();
  509. }
  510. @Override
  511. protected void onSaveInstanceState(Bundle icicle) {
  512. super.onSaveInstanceState(icicle);
  513. // Save list state in the bundle so we can restore it after the QueryHandler has run
  514. // icicle.putParcelable(LIST_STATE_KEY, mList.onSaveInstanceState());
  515. // icicle.putBoolean(FOCUS_KEY, mList.hasFocus());
  516. }
  517. @Override
  518. protected void onRestoreInstanceState(Bundle icicle) {
  519. super.onRestoreInstanceState(icicle);
  520. // Retrieve list state. This will be applied after the QueryHandler has run
  521. // mListState = icicle.getParcelable(LIST_STATE_KEY);
  522. // mListHasFocus = icicle.getBoolean(FOCUS_KEY);
  523. }
  524. @Override
  525. protected void onStop() {
  526. super.onStop();
  527. // We don't want the list to display the empty state, since when we resume it will still
  528. // be there and show up while the new query is happening. After the async query finished
  529. // in response to onResume() setLoading(false) will be called.
  530. mAdapter.setLoading(true);
  531. mAdapter.changeCursor(null);
  532. if (mMode == MODE_QUERY) {
  533. // Make sure the search box is closed
  534. SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
  535. searchManager.stopSearch();
  536. }
  537. }
  538. @Override
  539. public boolean onCreateOptionsMenu(Menu menu) {
  540. // If Contacts was invoked by another Activity simply as a way of
  541. // picking a contact, don't show the options menu
  542. if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
  543. return false;
  544. }
  545. // menu.add(0, MENU_NEW_CONTACT, 0, R.string.menu_newContact)
  546. // .setIcon(android.R.drawable.ic_menu_add)
  547. // .setIntent(new Intent(Intents.Insert.ACTION, People.CONTENT_URI))
  548. // .setAlphabeticShortcut('n');
  549. // if (isChild()) {
  550. // menu.add(0, 0, 0, R.string.menu_preferences)
  551. // .setIcon(android.R.drawable.ic_menu_preferences)
  552. // .setIntent(new Intent(this, ContactsPreferenceActivity.class));
  553. // }
  554. // if (mDefaultMode) {
  555. // menu.add(0, MENU_DISPLAY_GROUP, 0, R.string.menu_displayGroup)
  556. // .setIcon(R.drawable.ic_menu_allfriends);
  557. // }
  558. return super.onCreateOptionsMenu(menu);
  559. }
  560. /*
  561. * Implements the handler for display group selection.
  562. */
  563. public void onClick(DialogInterface dialogInterface, int which) {
  564. // if (which == DialogInterface.BUTTON1) {
  565. // // The OK button was pressed
  566. // if (mDisplayGroupOriginalSelection != mDisplayGroupCurrentSelection) {
  567. // // Set the group to display
  568. // if (mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_ALL_CONTACTS) {
  569. // // Display all
  570. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_ALL;
  571. // mDisplayInfo = null;
  572. // } else if (mDisplayGroupCurrentSelection
  573. // == DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES) {
  574. // // Display all with phone numbers
  575. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_ALL_WITH_PHONES;
  576. // mDisplayInfo = null;
  577. // } else if (mDisplayGroupsIncludesMyContacts &&
  578. // mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_MY_CONTACTS) {
  579. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_SYSTEM_GROUP;
  580. // mDisplayInfo = Groups.GROUP_MY_CONTACTS;
  581. // } else {
  582. // mDisplayType = ContactsPreferenceActivity.DISPLAY_TYPE_USER_GROUP;
  583. // mDisplayInfo = mDisplayGroups[mDisplayGroupCurrentSelection].toString();
  584. // }
  585. //
  586. // // Save the changes to the preferences
  587. // SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
  588. // prefs.edit()
  589. // .putInt(ContactsPreferenceActivity.PREF_DISPLAY_TYPE, mDisplayType)
  590. // .putString(ContactsPreferenceActivity.PREF_DISPLAY_INFO, mDisplayInfo)
  591. // .commit();
  592. //
  593. // // Update the display state
  594. // updateGroup();
  595. // }
  596. // } else {
  597. // // A list item was selected, cache the position
  598. // mDisplayGroupCurrentSelection = which;
  599. // }
  600. }
  601. @Override
  602. public boolean onOptionsItemSelected(MenuItem item) {
  603. // if (item.getItemId() == MENU_DISPLAY_GROUP) {
  604. // AlertDialog.Builder builder = new AlertDialog.Builder(this)
  605. // .setTitle(R.string.select_group_title)
  606. // .setPositiveButton(android.R.string.ok, this)
  607. // .setNegativeButton(android.R.string.cancel, null);
  608. //
  609. // setGroupEntries(builder);
  610. //
  611. // builder.show();
  612. // return true;
  613. // }
  614. return false;
  615. }
  616. @Override
  617. protected void onActivityResult(int requestCode, int resultCode,
  618. Intent data) {
  619. switch (requestCode) {
  620. case SUBACTIVITY_NEW_CONTACT:
  621. if (resultCode == RESULT_OK) {
  622. // Contact was created, pass it back
  623. returnPickerResult(data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
  624. data.getData());
  625. }
  626. }
  627. }
  628. @Override
  629. public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
  630. // If Contacts was invoked by another Activity simply as a way of
  631. // picking a contact, don't show the context menu
  632. if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
  633. return;
  634. }
  635. // AdapterView.AdapterContextMenuInfo info;
  636. // try {
  637. // info = (AdapterView.AdapterContextMenuInfo) menuInfo;
  638. // } catch (ClassCastException e) {
  639. // Log.e(TAG, "bad menuInfo", e);
  640. // return;
  641. // }
  642. //
  643. // Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
  644. // if (cursor == null) {
  645. // // For some reason the requested item isn't available, do nothing
  646. // return;
  647. // }
  648. // long id = info.id;
  649. // Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
  650. //
  651. // // Setup the menu header
  652. // menu.setHeaderTitle(cursor.getString(NAME_COLUMN_INDEX));
  653. //
  654. // // View contact details
  655. // menu.add(0, MENU_ITEM_VIEW_CONTACT, 0, R.string.menu_viewContact)
  656. // .setIntent(new Intent(Intent.ACTION_VIEW, personUri));
  657. //
  658. // // Calling contact
  659. // long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
  660. // if (phoneId > 0) {
  661. // // Get the display label for the number
  662. // CharSequence label = cursor.getString(LABEL_COLUMN_INDEX);
  663. // int type = cursor.getInt(TYPE_COLUMN_INDEX);
  664. // label = Phones.getDisplayLabel(this, type, label);
  665. // Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
  666. // ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
  667. // menu.add(0, MENU_ITEM_CALL, 0, String.format(getString(R.string.menu_callNumber), label))
  668. // .setIntent(intent);
  669. //
  670. // // Send SMS item
  671. // menu.add(0, MENU_ITEM_SEND_SMS, 0, R.string.menu_sendSMS)
  672. // .setIntent(new Intent(Intent.ACTION_SENDTO,
  673. // Uri.fromParts("sms", cursor.getString(NUMBER_COLUMN_INDEX), null)));
  674. // }
  675. //
  676. // // Star toggling
  677. // int starState = cursor.getInt(STARRED_COLUMN_INDEX);
  678. // if (starState == 0) {
  679. // menu.add(0, MENU_ITEM_TOGGLE_STAR, 0, R.string.menu_addStar);
  680. // } else {
  681. // menu.add(0, MENU_ITEM_TOGGLE_STAR, 0, R.string.menu_removeStar);
  682. // }
  683. //
  684. // // Contact editing
  685. // menu.add(0, MENU_ITEM_EDIT, 0, R.string.menu_editContact)
  686. // .setIntent(new Intent(Intent.ACTION_EDIT, personUri));
  687. // menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact);
  688. }
  689. @Override
  690. public boolean onContextItemSelected(MenuItem item) {
  691. // AdapterView.AdapterContextMenuInfo info;
  692. // try {
  693. // info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
  694. // } catch (ClassCastException e) {
  695. // Log.e(TAG, "bad menuInfo", e);
  696. // return false;
  697. // }
  698. //
  699. // Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
  700. //
  701. // switch (item.getItemId()) {
  702. // case MENU_ITEM_TOGGLE_STAR: {
  703. // // Toggle the star
  704. // ContentValues values = new ContentValues(1);
  705. // values.put(People.STARRED, cursor.getInt(STARRED_COLUMN_INDEX) == 0 ? 1 : 0);
  706. // Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI,
  707. // cursor.getInt(ID_COLUMN_INDEX));
  708. // getContentResolver().update(personUri, values, null, null);
  709. // return true;
  710. // }
  711. //
  712. // case MENU_ITEM_DELETE: {
  713. // // Get confirmation
  714. // Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
  715. // cursor.getLong(ID_COLUMN_INDEX));
  716. // //TODO make this dialog persist across screen rotations
  717. // new AlertDialog.Builder(ContactsListActivity.this)
  718. // .setTitle(R.string.deleteConfirmation_title)
  719. // .setIcon(android.R.drawable.ic_dialog_alert)
  720. // .setMessage(R.string.deleteConfirmation)
  721. // .setNegativeButton(R.string.noButton, null)
  722. // .setPositiveButton(R.string.yesButton, new DeleteClickListener(uri))
  723. // .setCancelable(false)
  724. // .show();
  725. // return true;
  726. // }
  727. // }
  728. //
  729. return super.onContextItemSelected(item);
  730. }
  731. @Override
  732. public boolean onKeyDown(int keyCode, KeyEvent event) {
  733. // switch (keyCode) {
  734. // case KeyEvent.KEYCODE_CALL: {
  735. // if (callSelection()) {
  736. // return true;
  737. // }
  738. // break;
  739. // }
  740. //
  741. // case KeyEvent.KEYCODE_DEL: {
  742. // Object o = getListView().getSelectedItem();
  743. // if (o != null) {
  744. // Cursor cursor = (Cursor) o;
  745. // Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
  746. // cursor.getLong(ID_COLUMN_INDEX));
  747. // //TODO make this dialog persist across screen rotations
  748. // new AlertDialog.Builder(ContactsListActivity.this)
  749. // .setTitle(R.string.deleteConfirmation_title)
  750. // .setIcon(android.R.drawable.ic_dialog_alert)
  751. // .setMessage(R.string.deleteConfirmation)
  752. // .setNegativeButton(R.string.noButton, null)
  753. // .setPositiveButton(R.string.yesButton, new DeleteClickListener(uri))
  754. // .setCancelable(false)
  755. // .show();
  756. // return true;
  757. // }
  758. // break;
  759. // }
  760. // }
  761. return super.onKeyDown(keyCode, event);
  762. }
  763. @Override
  764. protected void onListItemClick(ListView l, View v, int position, long id) {
  765. // if (mMode == MODE_INSERT_OR_EDIT_CONTACT) {
  766. // Intent intent;
  767. // if (position == 0) {
  768. // // Insert
  769. // intent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
  770. // } else {
  771. // // Edit
  772. // intent = new Intent(Intent.ACTION_EDIT,
  773. // ContentUris.withAppendedId(People.CONTENT_URI, id));
  774. // }
  775. // intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
  776. // final Bundle extras = getIntent().getExtras();
  777. // if (extras != null) {
  778. // intent.putExtras(extras);
  779. // }
  780. // startActivity(intent);
  781. // finish();
  782. // } else
  783. if (id != -1) {
  784. if ((mMode & MODE_MASK_PICKER) == 0) {
  785. Intent intent = new Intent(Intent.ACTION_VIEW,
  786. ContentUris.withAppendedId(People.CONTENT_URI, id));
  787. startActivity(intent);
  788. } else if (mMode == MODE_PICK_CONTACT
  789. || mMode == MODE_PICK_OR_CREATE_CONTACT) {
  790. Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, id);
  791. if (mCreateShortcut) {
  792. // Subtract one if we have Create Contact at the top
  793. Cursor c = (Cursor) mAdapter.getItem(position
  794. - (mMode == MODE_PICK_OR_CREATE_CONTACT? 1:0));
  795. returnPickerResult(c.getString(NAME_COLUMN_INDEX), uri);
  796. } else {
  797. returnPickerResult(null, uri);
  798. }
  799. } else if (mMode == MODE_PICK_PHONE) {
  800. setResult(RESULT_OK, new Intent().setData(
  801. ContentUris.withAppendedId(Phones.CONTENT_URI, id)));
  802. finish();
  803. } else if (mMode == MODE_PICK_POSTAL) {
  804. setResult(RESULT_OK, new Intent().setData(
  805. ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id)));
  806. finish();
  807. } else if (mMode == MODE_PICK_EMAIL) {
  808. setResult(RESULT_OK, new Intent().setData(
  809. ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id)));
  810. finish();
  811. }
  812. // } else if ((mMode & MODE_MASK_CREATE_NEW) == MODE_MASK_CREATE_NEW
  813. // && position == 0) {
  814. // Intent newContact = new Intent(Intents.Insert.ACTION, People.CONTENT_URI);
  815. // startActivityForResult(newContact, SUBACTIVITY_NEW_CONTACT);
  816. // } else {
  817. // signalError();
  818. }
  819. }
  820. private void returnPickerResult(String name, Uri uri) {
  821. final Intent intent = new Intent();
  822. // if (mCreateShortcut) {
  823. // Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, uri);
  824. // shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
  825. // intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
  826. // intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
  827. // final Bitmap icon = People.loadContactPhoto(this, uri, 0, null);
  828. // if (icon != null) {
  829. // intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
  830. // } else {
  831. // intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
  832. // Intent.ShortcutIconResource.fromContext(this,
  833. // R.drawable.ic_launcher_contacts));
  834. // }
  835. // setResult(RESULT_OK, intent);
  836. // } else {
  837. setResult(RESULT_OK, intent.setData(uri));
  838. // }
  839. finish();
  840. }
  841. String[] getProjection() {
  842. switch (mMode) {
  843. case MODE_GROUP:
  844. case MODE_ALL_CONTACTS:
  845. case MODE_WITH_PHONES:
  846. case MODE_PICK_CONTACT:
  847. case MODE_PICK_OR_CREATE_CONTACT:
  848. case MODE_QUERY:
  849. case MODE_STARRED:
  850. case MODE_FREQUENT:
  851. case MODE_INSERT_OR_EDIT_CONTACT:
  852. return CONTACTS_PROJECTION;
  853. case MODE_STREQUENT:
  854. return STREQUENT_PROJECTION;
  855. case MODE_PICK_PHONE:
  856. return PHONES_PROJECTION;
  857. case MODE_PICK_POSTAL:
  858. return CONTACT_METHODS_PROJECTION;
  859. case MODE_PICK_EMAIL:
  860. return CONTACT_METHODS_PROJECTION;
  861. }
  862. return null;
  863. }
  864. private Uri getPeopleFilterUri(String filter) {
  865. if (!TextUtils.isEmpty(filter)) {
  866. return Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(filter));
  867. } else {
  868. return People.CONTENT_URI;
  869. }
  870. }
  871. void startQuery() {
  872. mAdapter.setLoading(true);
  873. // Cancel any pending queries
  874. mQueryHandler.cancelOperation(QUERY_TOKEN);
  875. // Kick off the new query
  876. switch (mMode) {
  877. case MODE_GROUP:
  878. mQueryHandler.startQuery(QUERY_TOKEN, null,
  879. mGroupUri, CONTACTS_PROJECTION, null, null, SORT_ORDER);
  880. break;
  881. case MODE_ALL_CONTACTS:
  882. case MODE_PICK_CONTACT:
  883. case MODE_PICK_OR_CREATE_CONTACT:
  884. case MODE_INSERT_OR_EDIT_CONTACT:
  885. mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
  886. null, null, SORT_ORDER);
  887. break;
  888. case MODE_WITH_PHONES:
  889. mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
  890. People.PRIMARY_PHONE_ID + " IS NOT NULL", null, People.DEFAULT_SORT_ORDER);
  891. break;
  892. case MODE_QUERY: {
  893. mQuery = getIntent().getStringExtra(SearchManager.QUERY);
  894. mQueryHandler.startQuery(QUERY_TOKEN, null, getPeopleFilterUri(mQuery),
  895. CONTACTS_PROJECTION, null, null, SORT_ORDER);
  896. break;
  897. }
  898. case MODE_STARRED:
  899. mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
  900. People.STARRED + "=1", null, SORT_ORDER);
  901. break;
  902. case MODE_FREQUENT:
  903. mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
  904. People.TIMES_CONTACTED + " > 0", null,
  905. People.TIMES_CONTACTED + " DESC, " + NAME_COLUMN + " ASC");
  906. break;
  907. case MODE_STREQUENT:
  908. mQueryHandler.startQuery(QUERY_TOKEN, null,
  909. Uri.withAppendedPath(People.CONTENT_URI, "strequent"), STREQUENT_PROJECTION,
  910. null, null, null);
  911. break;
  912. case MODE_PICK_PHONE:
  913. mQueryHandler.startQuery(QUERY_TOKEN, null, Phones.CONTENT_URI, PHONES_PROJECTION,
  914. null, null, SORT_ORDER);
  915. break;
  916. case MODE_PICK_POSTAL:
  917. mQueryHandler.startQuery(QUERY_TOKEN, null, ContactMethods.CONTENT_URI,
  918. CONTACT_METHODS_PROJECTION,
  919. ContactMethods.KIND + "=" + Contacts.KIND_POSTAL, null, SORT_ORDER);
  920. break;
  921. case MODE_PICK_EMAIL:
  922. mQueryHandler.startQuery(QUERY_TOKEN, null, ContactMethods.CONTENT_URI,
  923. CONTACT_METHODS_PROJECTION,
  924. ContactMethods.KIND + "=" + Contacts.KIND_EMAIL, null, SORT_ORDER);
  925. break;
  926. }
  927. }
  928. /**
  929. * Called from a background thread to do the filter and return the resulting cursor.
  930. *
  931. * @param filter the text that was entered to filter on
  932. * @return a cursor with the results of the filter
  933. */
  934. Cursor doFilter(String filter) {
  935. final ContentResolver resolver = getContentResolver();
  936. switch (mMode) {
  937. case MODE_GROUP: {
  938. Uri uri;
  939. if (TextUtils.isEmpty(filter)) {
  940. uri = mGroupUri;
  941. } else {
  942. uri = Uri.withAppendedPath(mGroupFilterUri, Uri.encode(filter));
  943. }
  944. return resolver.query(uri, CONTACTS_PROJECTION, null, null,
  945. People.DEFAULT_SORT_ORDER);
  946. }
  947. case MODE_ALL_CONTACTS:
  948. case MODE_PICK_CONTACT:
  949. case MODE_PICK_OR_CREATE_CONTACT:
  950. case MODE_INSERT_OR_EDIT_CONTACT: {
  951. return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION, null, null,
  952. SORT_ORDER);
  953. }
  954. case MODE_WITH_PHONES: {
  955. return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
  956. People.PRIMARY_PHONE_ID + " IS NOT NULL", null, SORT_ORDER);
  957. }
  958. case MODE_STARRED: {
  959. return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
  960. People.STARRED + "=1", null, SORT_ORDER);
  961. }
  962. case MODE_FREQUENT: {
  963. return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
  964. People.TIMES_CONTACTED + " > 0", null,
  965. People.TIMES_CONTACTED + " DESC, " + NAME_COLUMN + " ASC");
  966. }
  967. case MODE_STREQUENT: {
  968. Uri uri;
  969. if (!TextUtils.isEmpty(filter)) {
  970. uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent/filter/"
  971. + Uri.encode(filter));
  972. } else {
  973. uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent");
  974. }
  975. return resolver.query(uri, STREQUENT_PROJECTION, null, null, null);
  976. }
  977. case MODE_PICK_PHONE: {
  978. Uri uri;
  979. if (!TextUtils.isEmpty(filter)) {
  980. uri = Uri.withAppendedPath(Phones.CONTENT_URI, "filter_name/"
  981. + Uri.encode(filter));
  982. } else {
  983. uri = Phones.CONTENT_URI;
  984. }
  985. return resolver.query(uri, PHONES_PROJECTION, null, null, SORT_ORDER);
  986. }
  987. }
  988. throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
  989. }
  990. /**
  991. * Calls the currently selected list item.
  992. * @return true if the call was initiated, false otherwise
  993. */
  994. boolean callSelection() {
  995. // ListView list = getListView();
  996. // if (list.hasFocus()) {
  997. // Cursor cursor = (Cursor) list.getSelectedItem();
  998. // if (cursor != null) {
  999. // long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
  1000. // if (phoneId == 0) {
  1001. // // There is no phone number.
  1002. // signalError();
  1003. // return false;
  1004. // }
  1005. // Uri uri = ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId);
  1006. // Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
  1007. // startActivity(intent);
  1008. // return true;
  1009. // }
  1010. // }
  1011. return false;
  1012. }
  1013. /**
  1014. * Signal an error to the user.
  1015. */
  1016. void signalError() {
  1017. //TODO play an error beep or something...
  1018. }
  1019. Cursor getItemForView(View view) {
  1020. ListView listView = getListView();
  1021. int index = listView.getPositionForView(view);
  1022. if (index < 0) {
  1023. return null;
  1024. }
  1025. return (Cursor) listView.getAdapter().getItem(index);
  1026. }
  1027. private void setGroupEntries(AlertDialog.Builder builder) {
  1028. // boolean syncEverything;
  1029. // // For now we only support a single account and the UI doesn't know what
  1030. // // the account name is, so we're using a global setting for SYNC_EVERYTHING.
  1031. // // Some day when we add multiple accounts to the UI this should use the per
  1032. // // account setting.
  1033. // String value = Contacts.Settings.getSetting(getContentResolver(), null,
  1034. // Contacts.Settings.SYNC_EVERYTHING);
  1035. // if (value == null) {
  1036. // // If nothing is set yet we default to syncing everything
  1037. // syncEverything = true;
  1038. // } else {
  1039. // syncEverything = !TextUtils.isEmpty(value) && !"0".equals(value);
  1040. // }
  1041. //
  1042. // Cursor cursor;
  1043. // if (!syncEverything) {
  1044. // cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
  1045. // Groups.SHOULD_SYNC + " != 0", null, Groups.DEFAULT_SORT_ORDER);
  1046. // } else {
  1047. // cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
  1048. // null, null, Groups.DEFAULT_SORT_ORDER);
  1049. // }
  1050. // try {
  1051. // ArrayList<CharSequence> groups = new ArrayList<CharSequence>();
  1052. // ArrayList<CharSequence> prefStrings = new ArrayList<CharSequence>();
  1053. //
  1054. // // Add All Contacts
  1055. // groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS, getString(R.string.showAllGroups));
  1056. // prefStrings.add("");
  1057. //
  1058. // // Add Contacts with phones
  1059. // groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES,
  1060. // getString(R.string.groupNameWithPhones));
  1061. // prefStrings.add(GROUP_WITH_PHONES);
  1062. //
  1063. // int i = 3;
  1064. // int currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
  1065. // while (cursor.moveToNext()) {
  1066. // String systemId = cursor.getString(GROUPS_COLUMN_INDEX_SYSTEM_ID);
  1067. // String name = cursor.getString(GROUPS_COLUMN_INDEX_NAME);
  1068. // if (cursor.isNull(GROUPS_COLUMN_INDEX_SYSTEM_ID)
  1069. // && !Groups.GROUP_MY_CONTACTS.equals(systemId)) {
  1070. // // All groups that aren't My Contacts, since that one is localized on the phone
  1071. // groups.add(name);
  1072. // if (name.equals(mDisplayInfo)) {
  1073. // currentIndex = i;
  1074. // }
  1075. // i++;
  1076. // } else {
  1077. // // The My Contacts group
  1078. // groups.add(DISPLAY_GROUP_INDEX_MY_CONTACTS,
  1079. // getString(R.string.groupNameMyContacts));
  1080. // if (mDisplayType == ContactsPreferenceActivity.DISPLAY_TYPE_SYSTEM_GROUP
  1081. // && Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
  1082. // currentIndex = DISPLAY_GROUP_INDEX_MY_CONTACTS;
  1083. // }
  1084. // mDisplayGroupsIncludesMyContacts = true;
  1085. // }
  1086. // }
  1087. // if (mMode == MODE_ALL_CONTACTS) {
  1088. // currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
  1089. // } else if (mMode == MODE_WITH_PHONES) {
  1090. // currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES;
  1091. // }
  1092. // mDisplayGroups = groups.toArray(new CharSequence[groups.size()]);
  1093. // builder.setSingleChoiceItems(mDisplayGroups,
  1094. // currentIndex, this);
  1095. // mDisplayGroupOriginalSelection = currentIndex;
  1096. // } finally {
  1097. // cursor.close();
  1098. // }
  1099. }
  1100. private final class QueryHandler extends AsyncQueryHandler {
  1101. public QueryHandler(Context context) {
  1102. super(context.getContentResolver());
  1103. }
  1104. @Override
  1105. protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
  1106. if (!isFinishing()) {
  1107. mAdapter.setLoading(false);
  1108. mAdapter.changeCursor(cursor);
  1109. // Now that the cursor is populated again, it's possible to restore the list state
  1110. if (mListState != null) {
  1111. getListView().onRestoreInstanceState(mListState);
  1112. if (mListHasFocus) {
  1113. getListView().requestFocus();
  1114. }
  1115. mListHasFocus = false;
  1116. mListState = null;
  1117. }
  1118. } else {
  1119. cursor.close();
  1120. }
  1121. }
  1122. }
  1123. final static class ContactListItemCache {
  1124. public TextView nameView;
  1125. public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
  1126. public TextView labelView;
  1127. public CharArrayBuffer labelBuffer = new CharArrayBuffer(128);
  1128. public TextView numberView;
  1129. public CharArrayBuffer numberBuffer = new CharArrayBuffer(128);
  1130. }
  1131. private final class ContactItemListAdapter extends ResourceCursorAdapter
  1132. implements FastScrollView.SectionIndexer {
  1133. private String [] mAlphabet;
  1134. private AlphabetIndexer mIndexer;
  1135. private boolean mLoading = true;
  1136. private CharSequence mUnknownNameText;
  1137. private CharSequence[] mLocalizedLabels;
  1138. public ContactItemListAdapter(Context context, int resource, Cursor cursor) {
  1139. super(context, resource, cursor);
  1140. getAlphabet(context);
  1141. if (cursor != null) {
  1142. mIndexer = new AlphabetIndexer(cursor, NAME_COLUMN_INDEX, mAlphabet);
  1143. }
  1144. mUnknownNameText = context.getText(android.R.string.unknownName);
  1145. switch (mMode) {
  1146. case MODE_PICK_POSTAL:
  1147. mLocalizedLabels = EditContactActivity.getLabelsForKind(getBaseContext(),
  1148. Contacts.KIND_POSTAL);
  1149. break;
  1150. case MODE_PICK_EMAIL:
  1151. mLocalizedLabels = EditContactActivity.getLabelsForKind(getBaseContext(),
  1152. Contacts.KIND_EMAIL);
  1153. break;
  1154. default:
  1155. mLocalizedLabels = EditContactActivity.getLabelsForKind(getBaseContext(),
  1156. Contacts.KIND_PHONE);
  1157. break;
  1158. }
  1159. }
  1160. public void setLoading(boolean loading) {
  1161. mLoading = loading;
  1162. }
  1163. @Override
  1164. public boolean isEmpty() {
  1165. if (mLoading) {
  1166. // We don't want the empty state to show when loading.
  1167. return false;
  1168. } else {
  1169. return super.isEmpty();
  1170. }
  1171. }
  1172. private void getAlphabet(Context context) {
  1173. String alphabetString = "\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //context.getResources().getString(R.string.alphabet);
  1174. mAlphabet = new String[alphabetString.length()];
  1175. for (int i = 0; i < mAlphabet.length; i++) {
  1176. mAlphabet[i] = String.valueOf(alphabetString.charAt(i));
  1177. }
  1178. }
  1179. @Override
  1180. public View newView(Context context, Cursor cursor, ViewGroup parent) {
  1181. final View view = super.newView(context, cursor, parent);
  1182. final ContactListItemCache cache = new ContactListItemCache();
  1183. cache.nameView = (TextView) view.findViewById(R.id.name);
  1184. cache.labelView = (TextView) view.findViewById(R.id.label);
  1185. cache.labelView.setCompoundDrawablePadding(3);
  1186. cache.numberView = (TextView) view.findViewById(R.id.number);
  1187. view.setTag(cache);
  1188. return view;
  1189. }
  1190. @Override
  1191. public void bindView(View view, Context context, Cursor cursor) {
  1192. final ContactListItemCache cache = (ContactListItemCache) view.getTag();
  1193. // Set the name
  1194. cursor.copyStringToBuffer(NAME_COLUMN_INDEX, cache.nameBuffer);
  1195. int size = cache.nameBuffer.sizeCopied;
  1196. if (size != 0) {
  1197. cache.nameView.setText(cache.nameBuffer.data, 0, size);
  1198. } else {
  1199. cache.nameView.setText(mUnknownNameText);
  1200. }
  1201. // Set the phone number
  1202. TextView numberView = cache.numberView;
  1203. cursor.copyStringToBuffer(NUMBER_COLUMN_INDEX, cache.numberBuffer);
  1204. size = cache.numberBuffer.sizeCopied;
  1205. if (size != 0) {
  1206. numberView.setText(cache.numberBuffer.data, 0, size);
  1207. numberView.setVisibility(View.VISIBLE);
  1208. } else {
  1209. numberView.setVisibility(View.GONE);
  1210. }
  1211. // Set the label
  1212. TextView labelView = cache.labelView;
  1213. if (!cursor.isNull(TYPE_COLUMN_INDEX)) {
  1214. int type = cursor.getInt(TYPE_COLUMN_INDEX);
  1215. if (type != People.Phones.TYPE_CUSTOM) {
  1216. try {
  1217. labelView.setText(mLocalizedLabels[type - 1]);
  1218. } catch (ArrayIndexOutOfBoundsException e) {
  1219. labelView.setText(mLocalizedLabels[People.Phones.TYPE_HOME - 1]);
  1220. }
  1221. } else {
  1222. cursor.copyStringToBuffer(LABEL_COLUMN_INDEX, cache.labelBuffer);
  1223. // Don't check size, if it's zero just don't show anything
  1224. labelView.setText(cache.labelBuffer.data, 0, cache.labelBuffer.sizeCopied);
  1225. }
  1226. } else {
  1227. // Set the text to a length of 0
  1228. labelView.setText(cache.labelBuffer.data, 0, 0);
  1229. }
  1230. // Set the proper icon in the label view
  1231. if (mMode != MODE_STREQUENT) {
  1232. if ((mMode & MODE_MASK_NO_PRESENCE) == 0) {
  1233. int serverStatus;
  1234. if (!cursor.isNull(SERVER_STATUS_COLUMN_INDEX)) {
  1235. serverStatus = cursor.getInt(SERVER_STATUS_COLUMN_INDEX);
  1236. // labelView.setCompoundDrawablesWithIntrinsicBounds(
  1237. // getResources().getDrawable(
  1238. // Presence.getPresenceIconResourceId(serverStatus)),
  1239. // null, null, null);
  1240. } else {
  1241. labelView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
  1242. }
  1243. } else {
  1244. labelView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
  1245. }
  1246. } else {
  1247. if (cursor.getInt(STARRED_COLUMN_INDEX) != 0) {
  1248. // labelView.setCompoundDrawablesWithIntrinsicBounds(
  1249. // getResources().getDrawable(R.drawable.star_on),
  1250. // null, null, null);
  1251. } else {
  1252. labelView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
  1253. }
  1254. }
  1255. }
  1256. @Override
  1257. public void changeCursor(Cursor cursor) {
  1258. super.changeCursor(cursor);
  1259. updateIndexer(cursor);
  1260. }
  1261. private void updateIndexer(Cursor cursor) {
  1262. if (mIndexer == null) {
  1263. mIndexer = new AlphabetIndexer(cursor, NAME_COLUMN_INDEX, mAlphabet);
  1264. } else {
  1265. mIndexer.setCursor(cursor);
  1266. }
  1267. }
  1268. /**
  1269. * Run the query on a helper thread. Beware that this code does not run
  1270. * on the main UI thread!
  1271. */
  1272. @Override
  1273. public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
  1274. return doFilter(constraint.toString());
  1275. }
  1276. public Object [] getSections() {
  1277. if (mMode == MODE_STREQUENT) {
  1278. return new String[] { " " };
  1279. } else {
  1280. return mAlphabet;
  1281. }
  1282. }
  1283. public int getPositionForSection(int sectionIndex) {
  1284. if (mMode == MODE_STREQUENT) {
  1285. return 0;
  1286. }
  1287. if (mIndexer == null) {
  1288. Cursor cursor = mAdapter.getCursor();
  1289. if (cursor == null) {
  1290. // No cursor, the section doesn't exist so just return 0
  1291. return 0;
  1292. }
  1293. mIndexer = new AlphabetIndexer(cursor, NAME_COLUMN_INDEX, mAlphabet);
  1294. }
  1295. return mIndexer.indexOf(sectionIndex);
  1296. }
  1297. public int getSectionForPosition(int position) {
  1298. return 0;
  1299. }
  1300. }
  1301. }