PeopleActivity.java revision be18de05d6f6a107c552e369bce58f51c946fde7
1/* 2 * Copyright (C) 2010 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.activities; 18 19import com.android.contacts.ContactSaveService; 20import com.android.contacts.ContactsActivity; 21import com.android.contacts.GroupMetaData; 22import com.android.contacts.R; 23import com.android.contacts.calllog.CallLogFragment; 24import com.android.contacts.detail.ContactDetailFragment; 25import com.android.contacts.dialpad.DialpadFragment; 26import com.android.contacts.group.GroupBrowseListFragment; 27import com.android.contacts.group.GroupBrowseListFragment.OnGroupBrowserActionListener; 28import com.android.contacts.group.GroupDetailFragment; 29import com.android.contacts.interactions.ContactDeletionInteraction; 30import com.android.contacts.interactions.GroupDeletionDialogFragment; 31import com.android.contacts.interactions.GroupRenamingDialogFragment; 32import com.android.contacts.interactions.ImportExportDialogFragment; 33import com.android.contacts.interactions.PhoneNumberInteraction; 34import com.android.contacts.list.ContactBrowseListContextMenuAdapter; 35import com.android.contacts.list.ContactBrowseListFragment; 36import com.android.contacts.list.ContactEntryListFragment; 37import com.android.contacts.list.ContactListFilter; 38import com.android.contacts.list.ContactListFilterController; 39import com.android.contacts.list.ContactsIntentResolver; 40import com.android.contacts.list.ContactsRequest; 41import com.android.contacts.list.ContactsUnavailableFragment; 42import com.android.contacts.list.CustomContactListFilterActivity; 43import com.android.contacts.list.DefaultContactBrowseListFragment; 44import com.android.contacts.list.DirectoryListLoader; 45import com.android.contacts.list.OnContactBrowserActionListener; 46import com.android.contacts.list.OnContactsUnavailableActionListener; 47import com.android.contacts.list.ProviderStatusLoader; 48import com.android.contacts.list.ProviderStatusLoader.ProviderStatusListener; 49import com.android.contacts.list.StrequentContactListFragment; 50import com.android.contacts.model.AccountTypeManager; 51import com.android.contacts.preference.ContactsPreferenceActivity; 52import com.android.contacts.util.AccountSelectionUtil; 53import com.android.contacts.util.DialogManager; 54import com.android.contacts.widget.ContextMenuAdapter; 55 56import android.accounts.Account; 57import android.app.ActionBar; 58import android.app.ActionBar.Tab; 59import android.app.ActionBar.TabListener; 60import android.app.Activity; 61import android.app.Dialog; 62import android.app.Fragment; 63import android.app.FragmentManager; 64import android.app.FragmentTransaction; 65import android.content.ActivityNotFoundException; 66import android.content.ContentValues; 67import android.content.Intent; 68import android.content.res.TypedArray; 69import android.net.Uri; 70import android.os.Bundle; 71import android.provider.ContactsContract; 72import android.provider.ContactsContract.Contacts; 73import android.provider.ContactsContract.Intents; 74import android.provider.ContactsContract.ProviderStatus; 75import android.provider.Settings; 76import android.util.Log; 77import android.view.KeyEvent; 78import android.view.Menu; 79import android.view.MenuInflater; 80import android.view.MenuItem; 81import android.view.View; 82import android.view.View.OnClickListener; 83import android.view.Window; 84import android.widget.SearchView; 85import android.widget.Toast; 86 87import java.util.ArrayList; 88 89/** 90 * Displays a list to browse contacts. For xlarge screens, this also displays a detail-pane on 91 * the right. 92 */ 93public class PeopleActivity extends ContactsActivity 94 implements View.OnCreateContextMenuListener, ActionBarAdapter.Listener, 95 DialogManager.DialogShowingViewActivity, 96 ContactListFilterController.ContactListFilterListener, ProviderStatusListener { 97 98 private static final String TAG = "ContactBrowserActivity"; 99 100 private static final int SUBACTIVITY_NEW_CONTACT = 2; 101 private static final int SUBACTIVITY_EDIT_CONTACT = 3; 102 private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 4; 103 104 private static final String KEY_SEARCH_MODE = "searchMode"; 105 106 private DialogManager mDialogManager = new DialogManager(this); 107 108 private ContactsIntentResolver mIntentResolver; 109 private ContactsRequest mRequest; 110 111 private ActionBarAdapter mActionBarAdapter; 112 113 private boolean mSearchMode; 114 115 private ContactBrowseListFragment mListFragment; 116 117 /** 118 * Whether we have a right-side contact or group detail pane for displaying info on that 119 * contact or group while browsing. Generally means "this is a tablet". 120 */ 121 private boolean mContentPaneDisplayed; 122 123 private ContactDetailFragment mContactDetailFragment; 124 private ContactDetailFragmentListener mContactDetailFragmentListener = 125 new ContactDetailFragmentListener(); 126 127 private GroupDetailFragment mGroupDetailFragment; 128 129 private PhoneNumberInteraction mPhoneNumberCallInteraction; 130 private PhoneNumberInteraction mSendTextMessageInteraction; 131 132 private boolean mSearchInitiated; 133 134 private ContactListFilterController mContactListFilterController; 135 136 private View mAddContactImageView; 137 138 private ContactsUnavailableFragment mContactsUnavailableFragment; 139 private ProviderStatusLoader mProviderStatusLoader; 140 private int mProviderStatus = -1; 141 142 private boolean mOptionsMenuContactsAvailable; 143 private boolean mOptionsMenuGroupActionsEnabled; 144 145 private DefaultContactBrowseListFragment mContactsFragment; 146 private StrequentContactListFragment mFavoritesFragment; 147 private GroupBrowseListFragment mGroupsFragment; 148 149 public PeopleActivity() { 150 mIntentResolver = new ContactsIntentResolver(this); 151 // TODO: Get rid of the ContactListFilterController class because there aren't any 152 // dropdown filters anymore. Just store the selected filter as a member variable. 153 mContactListFilterController = new ContactListFilterController(this); 154 mContactListFilterController.addListener(this); 155 mProviderStatusLoader = new ProviderStatusLoader(this); 156 } 157 158 public boolean areContactsAvailable() { 159 return mProviderStatus == ProviderStatus.STATUS_NORMAL; 160 } 161 162 @Override 163 public void onAttachFragment(Fragment fragment) { 164 if (fragment instanceof ContactBrowseListFragment) { 165 mListFragment = (ContactBrowseListFragment)fragment; 166 mListFragment.setOnContactListActionListener(new ContactBrowserActionListener()); 167 if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) { 168 mListFragment.setContextMenuAdapter( 169 new ContactBrowseListContextMenuAdapter(mListFragment)); 170 } 171 } else if (fragment instanceof GroupBrowseListFragment) { 172 mGroupsFragment = (GroupBrowseListFragment) fragment; 173 mGroupsFragment.setListener(new GroupBrowserActionListener()); 174 } else if (fragment instanceof ContactDetailFragment) { 175 mContactDetailFragment = (ContactDetailFragment) fragment; 176 mContactDetailFragment.setListener(mContactDetailFragmentListener); 177 mContentPaneDisplayed = true; 178 } else if (fragment instanceof ContactsUnavailableFragment) { 179 mContactsUnavailableFragment = (ContactsUnavailableFragment)fragment; 180 mContactsUnavailableFragment.setProviderStatusLoader(mProviderStatusLoader); 181 mContactsUnavailableFragment.setOnContactsUnavailableActionListener( 182 new ContactsUnavailableFragmentListener()); 183 } else if (fragment instanceof GroupDetailFragment) { 184 mGroupDetailFragment = (GroupDetailFragment) fragment; 185 mContentPaneDisplayed = true; 186 } 187 } 188 189 @Override 190 protected void onCreate(Bundle savedState) { 191 super.onCreate(savedState); 192 193 mAddContactImageView = getLayoutInflater().inflate( 194 R.layout.add_contact_menu_item, null, false); 195 View item = mAddContactImageView.findViewById(R.id.menu_item); 196 item.setOnClickListener(new OnClickListener() { 197 @Override 198 public void onClick(View v) { 199 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 200 startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT); 201 } 202 }); 203 204 configureContentView(true, savedState); 205 } 206 207 @Override 208 protected void onNewIntent(Intent intent) { 209 setIntent(intent); 210 configureContentView(false, null); 211 } 212 213 private void configureContentView(boolean createContentView, Bundle savedState) { 214 // Extract relevant information from the intent 215 mRequest = mIntentResolver.resolveIntent(getIntent()); 216 if (!mRequest.isValid()) { 217 setResult(RESULT_CANCELED); 218 finish(); 219 return; 220 } 221 222 Intent redirect = mRequest.getRedirectIntent(); 223 if (redirect != null) { 224 // Need to start a different activity 225 startActivity(redirect); 226 finish(); 227 return; 228 } 229 230 if (createContentView) { 231 setContentView(R.layout.people_activity); 232 233 final FragmentManager fragmentManager = getFragmentManager(); 234 mFavoritesFragment = (StrequentContactListFragment) fragmentManager 235 .findFragmentById(R.id.favorites_fragment); 236 mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager 237 .findFragmentById(R.id.contacts_fragment); 238 mGroupsFragment = (GroupBrowseListFragment) fragmentManager 239 .findFragmentById(R.id.groups_fragment); 240 241 // Hide all tabs (the current tab will later be reshown once a tab is selected) 242 final FragmentTransaction transaction = fragmentManager.beginTransaction(); 243 transaction.hide(mFavoritesFragment); 244 transaction.hide(mContactsFragment); 245 transaction.hide(mGroupsFragment); 246 if (mContactDetailFragment != null) { 247 transaction.hide(mContactDetailFragment); 248 } 249 if (mGroupDetailFragment != null) { 250 transaction.hide(mGroupDetailFragment); 251 } 252 transaction.commit(); 253 } 254 255 if (mRequest.getActionCode() == ContactsRequest.ACTION_VIEW_CONTACT 256 && !mContentPaneDisplayed) { 257 redirect = new Intent(this, ContactDetailActivity.class); 258 redirect.setAction(Intent.ACTION_VIEW); 259 redirect.setData(mRequest.getContactUri()); 260 startActivity(redirect); 261 finish(); 262 return; 263 } 264 265 setTitle(mRequest.getActivityTitle()); 266 ActionBar actionBar = getActionBar(); 267 mActionBarAdapter = new ActionBarAdapter(this); 268 mActionBarAdapter.onCreate(savedState, mRequest, getActionBar()); 269 mActionBarAdapter.setContactListFilterController(mContactListFilterController); 270 271 if (createContentView) { 272 actionBar.removeAllTabs(); 273 Tab favoritesTab = actionBar.newTab(); 274 favoritesTab.setText(getString(R.string.strequentList)); 275 favoritesTab.setTabListener(new TabChangeListener(mFavoritesFragment, 276 mContactDetailFragment)); 277 actionBar.addTab(favoritesTab); 278 279 Tab peopleTab = actionBar.newTab(); 280 peopleTab.setText(getString(R.string.people)); 281 peopleTab.setTabListener(new TabChangeListener(mContactsFragment, 282 mContactDetailFragment)); 283 actionBar.addTab(peopleTab); 284 285 Tab groupsTab = actionBar.newTab(); 286 groupsTab.setText(getString(R.string.contactsGroupsLabel)); 287 groupsTab.setTabListener(new TabChangeListener(mGroupsFragment, 288 mGroupDetailFragment)); 289 actionBar.addTab(groupsTab); 290 actionBar.setDisplayShowTitleEnabled(true); 291 292 TypedArray a = obtainStyledAttributes(null, R.styleable.ActionBarHomeIcon); 293 boolean showHomeIcon = a.getBoolean(R.styleable.ActionBarHomeIcon_show_home_icon, true); 294 actionBar.setDisplayShowHomeEnabled(showHomeIcon); 295 296 invalidateOptionsMenu(); 297 } 298 299 configureFragments(savedState == null); 300 } 301 302 /** 303 * Tab change listener that is instantiated once for each tab. Handles showing/hiding fragments. 304 * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the 305 * support library in our app. 306 */ 307 private class TabChangeListener implements TabListener { 308 private final Fragment mBrowseListFragment; 309 310 /** 311 * Right pane fragment that is present on larger screen sizes (can be 312 * null for smaller screen sizes). 313 */ 314 private final Fragment mDetailFragment; 315 316 public TabChangeListener(Fragment listFragment, Fragment detailFragment) { 317 mBrowseListFragment = listFragment; 318 mDetailFragment = detailFragment; 319 } 320 321 @Override 322 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 323 ft.hide(mBrowseListFragment); 324 if (mDetailFragment != null) { 325 ft.hide(mDetailFragment); 326 } 327 } 328 329 @Override 330 public void onTabSelected(Tab tab, FragmentTransaction ft) { 331 ft.show(mBrowseListFragment); 332 if (mDetailFragment != null) { 333 ft.show(mDetailFragment); 334 } 335 } 336 337 @Override 338 public void onTabReselected(Tab tab, FragmentTransaction ft) { 339 } 340 } 341 342 @Override 343 protected void onPause() { 344 if (mActionBarAdapter != null) { 345 mActionBarAdapter.setListener(null); 346 } 347 348 mOptionsMenuContactsAvailable = false; 349 mOptionsMenuGroupActionsEnabled = false; 350 351 mProviderStatus = -1; 352 mProviderStatusLoader.setProviderStatusListener(null); 353 super.onPause(); 354 } 355 356 @Override 357 protected void onResume() { 358 super.onResume(); 359 if (mActionBarAdapter != null) { 360 mActionBarAdapter.setListener(this); 361 } 362 mProviderStatusLoader.setProviderStatusListener(this); 363 updateFragmentVisibility(); 364 } 365 366 @Override 367 protected void onStart() { 368 mContactListFilterController.onStart(); 369 super.onStart(); 370 } 371 372 private void configureFragments(boolean fromRequest) { 373 if (fromRequest) { 374 ContactListFilter filter = null; 375 int actionCode = mRequest.getActionCode(); 376 switch (actionCode) { 377 case ContactsRequest.ACTION_ALL_CONTACTS: 378 filter = ContactListFilter.createFilterWithType( 379 ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS); 380 break; 381 case ContactsRequest.ACTION_CONTACTS_WITH_PHONES: 382 filter = ContactListFilter.createFilterWithType( 383 ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY); 384 break; 385 386 // TODO: handle FREQUENT and STREQUENT according to the spec 387 case ContactsRequest.ACTION_FREQUENT: 388 case ContactsRequest.ACTION_STREQUENT: 389 // For now they are treated the same as STARRED 390 case ContactsRequest.ACTION_STARRED: 391 filter = ContactListFilter.createFilterWithType( 392 ContactListFilter.FILTER_TYPE_STARRED); 393 break; 394 } 395 396 mSearchMode = mRequest.isSearchMode(); 397 if (filter != null) { 398 mContactListFilterController.setContactListFilter(filter, false); 399 mSearchMode = false; 400 } else if (mRequest.getActionCode() == ContactsRequest.ACTION_ALL_CONTACTS) { 401 mContactListFilterController.setContactListFilter( 402 ContactListFilter.createFilterWithType( 403 ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS), false); 404 } 405 406 if (mRequest.getContactUri() != null) { 407 mSearchMode = false; 408 } 409 410 mListFragment.setContactsRequest(mRequest); 411 configureListFragmentForRequest(); 412 413 } else { 414 mSearchMode = mActionBarAdapter.isSearchMode(); 415 } 416 417 configureListFragment(); 418 419 invalidateOptionsMenu(); 420 } 421 422 @Override 423 public void onContactListFiltersLoaded() { 424 if (mListFragment == null || !mListFragment.isAdded()) { 425 return; 426 } 427 428 mListFragment.setFilter(mContactListFilterController.getFilter()); 429 430 invalidateOptionsMenu(); 431 } 432 433 @Override 434 public void onContactListFilterChanged() { 435 if (mListFragment == null || !mListFragment.isAdded()) { 436 return; 437 } 438 439 mListFragment.setFilter(mContactListFilterController.getFilter()); 440 441 invalidateOptionsMenu(); 442 } 443 444 @Override 445 public void onContactListFilterCustomizationRequest() { 446 startActivityForResult(new Intent(this, CustomContactListFilterActivity.class), 447 SUBACTIVITY_CUSTOMIZE_FILTER); 448 } 449 450 private void setupContactDetailFragment(final Uri contactLookupUri) { 451 mContactDetailFragment.loadUri(contactLookupUri); 452 } 453 454 private void setupGroupDetailFragment(Uri groupUri) { 455 mGroupDetailFragment.loadGroup(groupUri); 456 } 457 458 /** 459 * Handler for action bar actions. 460 */ 461 @Override 462 public void onAction(Action action) { 463 switch (action) { 464 case START_SEARCH_MODE: 465 // Bring the contact list fragment to the front. 466 FragmentTransaction ft = getFragmentManager().beginTransaction(); 467 ft.show(mContactsFragment); 468 ft.commit(); 469 break; 470 case STOP_SEARCH_MODE: 471 case CHANGE_SEARCH_QUERY: 472 // Refresh the contact list fragment. 473 configureFragments(false /* from request */); 474 mListFragment.setQueryString(mActionBarAdapter.getQueryString(), true); 475 break; 476 default: 477 throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action); 478 } 479 } 480 481 private void configureListFragmentForRequest() { 482 Uri contactUri = mRequest.getContactUri(); 483 if (contactUri != null) { 484 mListFragment.setSelectedContactUri(contactUri); 485 } 486 487 mListFragment.setSearchMode(mRequest.isSearchMode()); 488 mListFragment.setQueryString(mRequest.getQueryString(), false); 489 490 if (mRequest.isDirectorySearchEnabled()) { 491 mListFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT); 492 } else { 493 mListFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE); 494 } 495 496 if (mContactListFilterController.isLoaded()) { 497 mListFragment.setFilter(mContactListFilterController.getFilter()); 498 } 499 } 500 501 private void configureListFragment() { 502 mListFragment.setSearchMode(mSearchMode); 503 504 mListFragment.setVisibleScrollbarEnabled(!mSearchMode); 505 mListFragment.setVerticalScrollbarPosition( 506 mContentPaneDisplayed 507 ? View.SCROLLBAR_POSITION_LEFT 508 : View.SCROLLBAR_POSITION_RIGHT); 509 mListFragment.setSelectionVisible(mContentPaneDisplayed); 510 mListFragment.setQuickContactEnabled(!mContentPaneDisplayed); 511 } 512 513 @Override 514 public void onProviderStatusChange() { 515 updateFragmentVisibility(); 516 } 517 518 private void updateFragmentVisibility() { 519 int providerStatus = mProviderStatusLoader.getProviderStatus(); 520 if (providerStatus == mProviderStatus) { 521 return; 522 } 523 524 mProviderStatus = providerStatus; 525 526 View contactsUnavailableView = findViewById(R.id.contacts_unavailable_view); 527 View mainView = findViewById(R.id.main_view); 528 529 if (mProviderStatus == ProviderStatus.STATUS_NORMAL) { 530 contactsUnavailableView.setVisibility(View.GONE); 531 if (mainView != null) { 532 mainView.setVisibility(View.VISIBLE); 533 } 534 if (mListFragment != null) { 535 mListFragment.setEnabled(true); 536 } 537 } else { 538 if (mListFragment != null) { 539 mListFragment.setEnabled(false); 540 } 541 if (mContactsUnavailableFragment == null) { 542 mContactsUnavailableFragment = new ContactsUnavailableFragment(); 543 mContactsUnavailableFragment.setProviderStatusLoader(mProviderStatusLoader); 544 mContactsUnavailableFragment.setOnContactsUnavailableActionListener( 545 new ContactsUnavailableFragmentListener()); 546 getFragmentManager().beginTransaction() 547 .replace(R.id.contacts_unavailable_container, mContactsUnavailableFragment) 548 .commit(); 549 } else { 550 mContactsUnavailableFragment.update(); 551 } 552 contactsUnavailableView.setVisibility(View.VISIBLE); 553 if (mainView != null) { 554 mainView.setVisibility(View.INVISIBLE); 555 } 556 } 557 558 invalidateOptionsMenu(); 559 } 560 561 private final class ContactBrowserActionListener implements OnContactBrowserActionListener { 562 563 @Override 564 public void onSelectionChange() { 565 if (mContentPaneDisplayed) { 566 setupContactDetailFragment(mListFragment.getSelectedContactUri()); 567 } 568 } 569 570 @Override 571 public void onViewContactAction(Uri contactLookupUri) { 572 if (mContentPaneDisplayed) { 573 setupContactDetailFragment(contactLookupUri); 574 } else { 575 startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri)); 576 } 577 } 578 579 @Override 580 public void onCreateNewContactAction() { 581 Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 582 Bundle extras = getIntent().getExtras(); 583 if (extras != null) { 584 intent.putExtras(extras); 585 } 586 startActivity(intent); 587 } 588 589 @Override 590 public void onEditContactAction(Uri contactLookupUri) { 591 Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri); 592 Bundle extras = getIntent().getExtras(); 593 if (extras != null) { 594 intent.putExtras(extras); 595 } 596 startActivityForResult(intent, SUBACTIVITY_EDIT_CONTACT); 597 } 598 599 @Override 600 public void onAddToFavoritesAction(Uri contactUri) { 601 ContentValues values = new ContentValues(1); 602 values.put(Contacts.STARRED, 1); 603 getContentResolver().update(contactUri, values, null, null); 604 } 605 606 @Override 607 public void onRemoveFromFavoritesAction(Uri contactUri) { 608 ContentValues values = new ContentValues(1); 609 values.put(Contacts.STARRED, 0); 610 getContentResolver().update(contactUri, values, null, null); 611 } 612 613 @Override 614 public void onCallContactAction(Uri contactUri) { 615 getPhoneNumberCallInteraction().startInteraction(contactUri); 616 } 617 618 @Override 619 public void onSmsContactAction(Uri contactUri) { 620 getSendTextMessageInteraction().startInteraction(contactUri); 621 } 622 623 @Override 624 public void onDeleteContactAction(Uri contactUri) { 625 ContactDeletionInteraction.start(PeopleActivity.this, contactUri, false); 626 } 627 628 @Override 629 public void onFinishAction() { 630 onBackPressed(); 631 } 632 633 @Override 634 public void onInvalidSelection() { 635 ContactListFilter filter; 636 ContactListFilter currentFilter = mListFragment.getFilter(); 637 if (currentFilter != null 638 && currentFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) { 639 filter = ContactListFilter.createFilterWithType( 640 ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS); 641 mListFragment.setFilter(filter); 642 } else { 643 filter = ContactListFilter.createFilterWithType( 644 ContactListFilter.FILTER_TYPE_SINGLE_CONTACT); 645 mListFragment.setFilter(filter, false); 646 } 647 mContactListFilterController.setContactListFilter(filter, true); 648 } 649 } 650 651 private class ContactDetailFragmentListener implements ContactDetailFragment.Listener { 652 @Override 653 public void onContactNotFound() { 654 // Nothing needs to be done here 655 } 656 657 @Override 658 public void onEditRequested(Uri contactLookupUri) { 659 startActivityForResult( 660 new Intent(Intent.ACTION_EDIT, contactLookupUri), SUBACTIVITY_EDIT_CONTACT); 661 } 662 663 @Override 664 public void onItemClicked(Intent intent) { 665 try { 666 startActivity(intent); 667 } catch (ActivityNotFoundException e) { 668 Log.e(TAG, "No activity found for intent: " + intent); 669 } 670 } 671 672 @Override 673 public void onDeleteRequested(Uri contactUri) { 674 ContactDeletionInteraction.start(PeopleActivity.this, contactUri, false); 675 } 676 677 @Override 678 public void onCreateRawContactRequested(ArrayList<ContentValues> values, Account account) { 679 Toast.makeText(PeopleActivity.this, R.string.toast_making_personal_copy, 680 Toast.LENGTH_LONG).show(); 681 Intent serviceIntent = ContactSaveService.createNewRawContactIntent( 682 PeopleActivity.this, values, account, 683 PeopleActivity.class, Intent.ACTION_VIEW); 684 startService(serviceIntent); 685 } 686 } 687 688 private class ContactsUnavailableFragmentListener 689 implements OnContactsUnavailableActionListener { 690 691 @Override 692 public void onCreateNewContactAction() { 693 startActivity(new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI)); 694 } 695 696 @Override 697 public void onAddAccountAction() { 698 Intent intent = new Intent(Settings.ACTION_ADD_ACCOUNT); 699 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 700 intent.putExtra(Settings.EXTRA_AUTHORITIES, 701 new String[] { ContactsContract.AUTHORITY }); 702 startActivity(intent); 703 } 704 705 @Override 706 public void onImportContactsFromFileAction() { 707 AccountSelectionUtil.doImportFromSdCard(PeopleActivity.this, null); 708 } 709 710 @Override 711 public void onFreeInternalStorageAction() { 712 startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)); 713 } 714 } 715 716 private final class GroupBrowserActionListener implements OnGroupBrowserActionListener { 717 718 @Override 719 public void onViewGroupAction(Uri groupUri) { 720 if (mContentPaneDisplayed) { 721 setupGroupDetailFragment(groupUri); 722 } else { 723 Intent intent = new Intent(PeopleActivity.this, GroupDetailActivity.class); 724 intent.setData(groupUri); 725 startActivity(intent); 726 } 727 } 728 } 729 730 public void startActivityAndForwardResult(final Intent intent) { 731 intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 732 733 // Forward extras to the new activity 734 Bundle extras = getIntent().getExtras(); 735 if (extras != null) { 736 intent.putExtras(extras); 737 } 738 startActivity(intent); 739 finish(); 740 } 741 742 @Override 743 public boolean onCreatePanelMenu(int featureId, Menu menu) { 744 // No menu if contacts are unavailable 745 if (!areContactsAvailable()) { 746 return false; 747 } 748 749 return super.onCreatePanelMenu(featureId, menu); 750 } 751 752 @Override 753 public boolean onPreparePanel(int featureId, View view, Menu menu) { 754 // No menu if contacts are unavailable 755 if (!areContactsAvailable()) { 756 return false; 757 } 758 759 return super.onPreparePanel(featureId, view, menu); 760 } 761 762 @Override 763 public boolean onCreateOptionsMenu(Menu menu) { 764 if (!areContactsAvailable()) { 765 return false; 766 } 767 super.onCreateOptionsMenu(menu); 768 769 MenuInflater inflater = getMenuInflater(); 770 inflater.inflate(R.menu.actions, menu); 771 // TODO: Figure out if R.menu.list or R.menu.search are necessary according to the overflow 772 // menus on the UX mocks. 773 MenuItem searchMenuItem = menu.findItem(R.id.menu_search); 774 if (searchMenuItem != null && searchMenuItem.getActionView() instanceof SearchView) { 775 SearchView searchView = (SearchView) searchMenuItem.getActionView(); 776 searchView.setQueryHint(getString(R.string.hint_findContacts)); 777 searchView.setIconifiedByDefault(false); 778 779 if (mActionBarAdapter != null) { 780 mActionBarAdapter.setSearchView(searchView); 781 } 782 } 783 784 // TODO: Can remove this as a custom view because the account selector is in the editor now. 785 // Change add contact button to button with a custom view 786 final MenuItem addContact = menu.findItem(R.id.menu_add); 787 addContact.setActionView(mAddContactImageView); 788 return true; 789 } 790 791 @Override 792 public void invalidateOptionsMenu() { 793 if (isOptionsMenuChanged()) { 794 super.invalidateOptionsMenu(); 795 } 796 } 797 798 public boolean isOptionsMenuChanged() { 799 if (mOptionsMenuContactsAvailable != areContactsAvailable()) { 800 return true; 801 } 802 803 if (mOptionsMenuGroupActionsEnabled != areGroupActionsEnabled()) { 804 return true; 805 } 806 807 if (mListFragment != null && mListFragment.isOptionsMenuChanged()) { 808 return true; 809 } 810 811 if (mContactDetailFragment != null && mContactDetailFragment.isOptionsMenuChanged()) { 812 return true; 813 } 814 815 return false; 816 } 817 818 @Override 819 public boolean onPrepareOptionsMenu(Menu menu) { 820 mOptionsMenuContactsAvailable = areContactsAvailable(); 821 if (!mOptionsMenuContactsAvailable) { 822 return false; 823 } 824 825 MenuItem settings = menu.findItem(R.id.menu_settings); 826 if (settings != null) { 827 settings.setVisible(!ContactsPreferenceActivity.isEmpty(this)); 828 } 829 830 mOptionsMenuGroupActionsEnabled = areGroupActionsEnabled(); 831 832 MenuItem renameGroup = menu.findItem(R.id.menu_rename_group); 833 if (renameGroup != null) { 834 renameGroup.setVisible(mOptionsMenuGroupActionsEnabled); 835 } 836 837 MenuItem deleteGroup = menu.findItem(R.id.menu_delete_group); 838 if (deleteGroup != null) { 839 deleteGroup.setVisible(mOptionsMenuGroupActionsEnabled); 840 } 841 842 return true; 843 } 844 845 private boolean areGroupActionsEnabled() { 846 boolean groupActionsEnabled = false; 847 if (mListFragment != null) { 848 ContactListFilter filter = mListFragment.getFilter(); 849 if (filter != null 850 && filter.filterType == ContactListFilter.FILTER_TYPE_GROUP 851 && !filter.groupReadOnly) { 852 groupActionsEnabled = true; 853 } 854 } 855 return groupActionsEnabled; 856 } 857 858 @Override 859 public boolean onOptionsItemSelected(MenuItem item) { 860 switch (item.getItemId()) { 861 case R.id.menu_settings: { 862 final Intent intent = new Intent(this, ContactsPreferenceActivity.class); 863 startActivity(intent); 864 return true; 865 } 866 case R.id.menu_contacts_filter: { 867 final Intent intent = new Intent(this, CustomContactListFilterActivity.class); 868 startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER); 869 return true; 870 } 871 case R.id.menu_search: { 872 onSearchRequested(); 873 return true; 874 } 875 case R.id.menu_add: { 876 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); 877 startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT); 878 return true; 879 } 880 case R.id.menu_import_export: { 881 ImportExportDialogFragment.show(getFragmentManager()); 882 return true; 883 } 884 case R.id.menu_accounts: { 885 final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS); 886 intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] { 887 ContactsContract.AUTHORITY 888 }); 889 intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 890 startActivity(intent); 891 return true; 892 } 893 case R.id.menu_rename_group: { 894 ContactListFilter filter = mListFragment.getFilter(); 895 GroupRenamingDialogFragment.show(getFragmentManager(), filter.groupId, 896 filter.title); 897 return true; 898 } 899 case R.id.menu_delete_group: { 900 ContactListFilter filter = mListFragment.getFilter(); 901 GroupDeletionDialogFragment.show(getFragmentManager(), filter.groupId, 902 filter.title); 903 return true; 904 } 905 } 906 return false; 907 } 908 909 @Override 910 public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, 911 boolean globalSearch) { 912 if (mListFragment != null && mListFragment.isAdded() && !globalSearch) { 913 mListFragment.startSearch(initialQuery); 914 } else { 915 super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); 916 } 917 } 918 919 @Override 920 protected Dialog onCreateDialog(int id, Bundle bundle) { 921 if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, bundle); 922 923 Dialog dialog = getPhoneNumberCallInteraction().onCreateDialog(id, bundle); 924 if (dialog != null) return dialog; 925 926 dialog = getSendTextMessageInteraction().onCreateDialog(id, bundle); 927 if (dialog != null) return dialog; 928 929 return super.onCreateDialog(id, bundle); 930 } 931 932 @Override 933 protected void onPrepareDialog(int id, Dialog dialog, Bundle bundle) { 934 if (getPhoneNumberCallInteraction().onPrepareDialog(id, dialog, bundle)) { 935 return; 936 } 937 938 if (getSendTextMessageInteraction().onPrepareDialog(id, dialog, bundle)) { 939 return; 940 } 941 942 super.onPrepareDialog(id, dialog, bundle); 943 } 944 945 @Override 946 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 947 switch (requestCode) { 948 case SUBACTIVITY_CUSTOMIZE_FILTER: { 949 if (resultCode == Activity.RESULT_OK) { 950 mContactListFilterController.selectCustomFilter(); 951 } 952 break; 953 } 954 955 case SUBACTIVITY_EDIT_CONTACT: 956 case SUBACTIVITY_NEW_CONTACT: { 957 if (resultCode == RESULT_OK && mContentPaneDisplayed) { 958 mRequest.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT); 959 mListFragment.reloadDataAndSetSelectedUri(data.getData()); 960 } 961 break; 962 } 963 964 // TODO: Using the new startActivityWithResultFromFragment API this should not be needed 965 // anymore 966 case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER: 967 if (resultCode == RESULT_OK) { 968 mListFragment.onPickerResult(data); 969 } 970 971// TODO fix or remove multipicker code 972// else if (resultCode == RESULT_CANCELED && mMode == MODE_PICK_MULTIPLE_PHONES) { 973// // Finish the activity if the sub activity was canceled as back key is used 974// // to confirm user selection in MODE_PICK_MULTIPLE_PHONES. 975// finish(); 976// } 977// break; 978 } 979 } 980 981 @Override 982 public boolean onContextItemSelected(MenuItem item) { 983 ContextMenuAdapter menuAdapter = mListFragment.getContextMenuAdapter(); 984 if (menuAdapter != null) { 985 return menuAdapter.onContextItemSelected(item); 986 } 987 988 return super.onContextItemSelected(item); 989 } 990 991 @Override 992 public boolean onKeyDown(int keyCode, KeyEvent event) { 993 // TODO move to the fragment 994 switch (keyCode) { 995// case KeyEvent.KEYCODE_CALL: { 996// if (callSelection()) { 997// return true; 998// } 999// break; 1000// } 1001 1002 case KeyEvent.KEYCODE_DEL: { 1003 if (deleteSelection()) { 1004 return true; 1005 } 1006 break; 1007 } 1008 default: { 1009 // Bring up the search UI if the user starts typing 1010 final int unicodeChar = event.getUnicodeChar(); 1011 if (unicodeChar != 0 && !Character.isWhitespace(unicodeChar)) { 1012 String query = new String(new int[]{ unicodeChar }, 0, 1); 1013 if (!mActionBarAdapter.isSearchMode()) { 1014 mActionBarAdapter.setQueryString(query); 1015 mActionBarAdapter.setSearchMode(true); 1016 return true; 1017 } else if (!mRequest.isSearchMode()) { 1018 if (!mSearchInitiated) { 1019 mSearchInitiated = true; 1020 startSearch(query, false, null, false); 1021 return true; 1022 } 1023 } 1024 } 1025 } 1026 } 1027 1028 return super.onKeyDown(keyCode, event); 1029 } 1030 1031 @Override 1032 public void onBackPressed() { 1033 if (mSearchMode && mActionBarAdapter != null) { 1034 mActionBarAdapter.setSearchMode(false); 1035 } else { 1036 super.onBackPressed(); 1037 } 1038 } 1039 1040 private boolean deleteSelection() { 1041 // TODO move to the fragment 1042// if (mActionCode == ContactsRequest.ACTION_DEFAULT) { 1043// final int position = mListView.getSelectedItemPosition(); 1044// if (position != ListView.INVALID_POSITION) { 1045// Uri contactUri = getContactUri(position); 1046// if (contactUri != null) { 1047// doContactDelete(contactUri); 1048// return true; 1049// } 1050// } 1051// } 1052 return false; 1053 } 1054 1055 @Override 1056 protected void onSaveInstanceState(Bundle outState) { 1057 super.onSaveInstanceState(outState); 1058 outState.putBoolean(KEY_SEARCH_MODE, mSearchMode); 1059 if (mActionBarAdapter != null) { 1060 mActionBarAdapter.onSaveInstanceState(outState); 1061 } 1062 } 1063 1064 @Override 1065 protected void onRestoreInstanceState(Bundle inState) { 1066 super.onRestoreInstanceState(inState); 1067 mSearchMode = inState.getBoolean(KEY_SEARCH_MODE); 1068 if (mActionBarAdapter != null) { 1069 mActionBarAdapter.onRestoreInstanceState(inState); 1070 } 1071 } 1072 1073 private PhoneNumberInteraction getPhoneNumberCallInteraction() { 1074 if (mPhoneNumberCallInteraction == null) { 1075 mPhoneNumberCallInteraction = new PhoneNumberInteraction(this, false, null); 1076 } 1077 return mPhoneNumberCallInteraction; 1078 } 1079 1080 private PhoneNumberInteraction getSendTextMessageInteraction() { 1081 if (mSendTextMessageInteraction == null) { 1082 mSendTextMessageInteraction = new PhoneNumberInteraction(this, true, null); 1083 } 1084 return mSendTextMessageInteraction; 1085 } 1086 1087 @Override 1088 public DialogManager getDialogManager() { 1089 return mDialogManager; 1090 } 1091 1092 // Visible for testing 1093 public ContactBrowseListFragment getListFragment() { 1094 return mListFragment; 1095 } 1096 1097 // Visible for testing 1098 public ContactDetailFragment getDetailFragment() { 1099 return mContactDetailFragment; 1100 } 1101} 1102