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