| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.contacts.activities; |
| |
| import android.Manifest; |
| import android.accounts.Account; |
| import android.app.Fragment; |
| import android.app.FragmentManager; |
| import android.app.FragmentTransaction; |
| import android.content.BroadcastReceiver; |
| import android.content.ContentResolver; |
| import android.content.ContentUris; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.SyncStatusObserver; |
| import android.content.res.Configuration; |
| import android.graphics.Color; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.provider.ContactsContract; |
| import android.provider.ContactsContract.Intents; |
| import android.provider.ContactsContract.ProviderStatus; |
| import androidx.annotation.LayoutRes; |
| import androidx.coordinatorlayout.widget.CoordinatorLayout; |
| import com.google.android.material.snackbar.Snackbar; |
| import androidx.core.content.ContextCompat; |
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; |
| import androidx.core.view.GravityCompat; |
| import androidx.drawerlayout.widget.DrawerLayout; |
| import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; |
| import androidx.appcompat.app.ActionBarDrawerToggle; |
| import androidx.appcompat.app.AppCompatActivity; |
| import androidx.appcompat.widget.Toolbar; |
| import android.util.Log; |
| import android.view.KeyCharacterMap; |
| import android.view.KeyEvent; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.accessibility.AccessibilityManager; |
| import android.widget.ImageButton; |
| import android.widget.Toast; |
| |
| import com.android.contacts.AppCompatContactsActivity; |
| import com.android.contacts.ContactSaveService; |
| import com.android.contacts.R; |
| import com.android.contacts.compat.CompatUtils; |
| import com.android.contacts.drawer.DrawerFragment; |
| import com.android.contacts.drawer.DrawerFragment.DrawerFragmentListener; |
| import com.android.contacts.editor.ContactEditorFragment; |
| import com.android.contacts.editor.SelectAccountDialogFragment; |
| import com.android.contacts.group.GroupListItem; |
| import com.android.contacts.group.GroupMembersFragment; |
| import com.android.contacts.group.GroupNameEditDialogFragment; |
| import com.android.contacts.group.GroupUtil; |
| import com.android.contacts.list.AccountFilterActivity; |
| import com.android.contacts.list.ContactListFilter; |
| import com.android.contacts.list.ContactListFilterController; |
| import com.android.contacts.list.ContactListFilterController.ContactListFilterListener; |
| import com.android.contacts.list.ContactsIntentResolver; |
| import com.android.contacts.list.ContactsRequest; |
| import com.android.contacts.list.ContactsUnavailableFragment; |
| import com.android.contacts.list.DefaultContactBrowseListFragment; |
| import com.android.contacts.list.MultiSelectContactsListFragment; |
| import com.android.contacts.list.ProviderStatusWatcher; |
| import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener; |
| import com.android.contacts.logging.Logger; |
| import com.android.contacts.logging.ScreenEvent.ScreenType; |
| import com.android.contacts.model.AccountTypeManager; |
| import com.android.contacts.model.account.AccountInfo; |
| import com.android.contacts.model.account.AccountWithDataSet; |
| import com.android.contacts.preference.ContactsPreferenceActivity; |
| import com.android.contacts.util.AccountFilterUtil; |
| import com.android.contacts.util.Constants; |
| import com.android.contacts.util.ImplicitIntentsUtil; |
| import com.android.contacts.util.MaterialColorMapUtils; |
| import com.android.contacts.util.PermissionsUtil; |
| import com.android.contacts.util.SharedPreferenceUtil; |
| import com.android.contacts.util.SyncUtil; |
| import com.android.contacts.util.ViewUtil; |
| import com.android.contacts.widget.FloatingActionButtonController; |
| import com.android.contactsbind.FeatureHighlightHelper; |
| import com.android.contactsbind.HelpUtils; |
| import com.android.contactsbind.ObjectFactory; |
| |
| import com.google.common.util.concurrent.Futures; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| /** |
| * Displays a list to browse contacts. |
| */ |
| public class PeopleActivity extends AppCompatContactsActivity implements |
| DrawerFragmentListener, |
| SelectAccountDialogFragment.Listener { |
| |
| /** Possible views of Contacts app. */ |
| public enum ContactsView { |
| NONE, |
| ALL_CONTACTS, |
| ASSISTANT, |
| GROUP_VIEW, |
| ACCOUNT_VIEW, |
| } |
| |
| private static final String TAG = "PeopleActivity"; |
| private static final String TAG_ALL = "contacts-all"; |
| private static final String TAG_UNAVAILABLE = "contacts-unavailable"; |
| private static final String TAG_GROUP_VIEW = "contacts-groups"; |
| private static final String TAG_SELECT_ACCOUNT_DIALOG = "selectAccountDialog"; |
| private static final String TAG_GROUP_NAME_EDIT_DIALOG = "groupNameEditDialog"; |
| |
| public static final String TAG_ASSISTANT = "contacts-assistant"; |
| public static final String TAG_SECOND_LEVEL = "second-level"; |
| public static final String TAG_THIRD_LEVEL = "third-level"; |
| public static final String TAG_ASSISTANT_HELPER = "assistant-helper"; |
| public static final String TAG_DUPLICATES = "DuplicatesFragment"; |
| public static final String TAG_DUPLICATES_UTIL = "DuplicatesUtilFragment"; |
| |
| private static final String KEY_GROUP_URI = "groupUri"; |
| private static final String KEY_CONTACTS_VIEW = "contactsView"; |
| private static final String KEY_NEW_GROUP_ACCOUNT = "newGroupAccount"; |
| |
| private static final long DRAWER_CLOSE_DELAY = 300L; |
| |
| private ContactsIntentResolver mIntentResolver; |
| private ContactsRequest mRequest; |
| private AccountTypeManager mAccountTypeManager; |
| |
| private FloatingActionButtonController mFloatingActionButtonController; |
| private View mFloatingActionButtonContainer; |
| private boolean wasLastFabAnimationScaleIn = false; |
| |
| private ProviderStatusWatcher mProviderStatusWatcher; |
| private Integer mProviderStatus; |
| |
| private BroadcastReceiver mSaveServiceListener; |
| |
| private boolean mShouldSwitchToGroupView; |
| |
| private ContactsView mCurrentView; |
| |
| private CoordinatorLayout mLayoutRoot; |
| |
| /** |
| * Showing a list of Contacts. Also used for showing search results in search mode. |
| */ |
| private DefaultContactBrowseListFragment mContactsListFragment; |
| |
| private GroupMembersFragment mMembersFragment; |
| private Uri mGroupUri; |
| |
| /** |
| * True if this activity instance is a re-created one. i.e. set true after orientation change. |
| */ |
| private boolean mIsRecreatedInstance; |
| |
| private boolean mShouldSwitchToAllContacts; |
| |
| /** Sequential ID assigned to each instance; used for logging */ |
| private final int mInstanceId; |
| private static final AtomicInteger sNextInstanceId = new AtomicInteger(); |
| |
| private ContactListFilterController mContactListFilterController; |
| |
| /** Navigation drawer related */ |
| private DrawerLayout mDrawerLayout; |
| private DrawerFragment mDrawerFragment; |
| private ContactsActionBarDrawerToggle mToggle; |
| private Toolbar mToolbar; |
| |
| // The account the new group will be created under. |
| private AccountWithDataSet mNewGroupAccount; |
| |
| private Object mStatusChangeListenerHandle; |
| |
| private final Handler mHandler = new Handler(); |
| |
| private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() { |
| public void onStatusChanged(int which) { |
| mHandler.post(new Runnable() { |
| public void run() { |
| onSyncStateUpdated(); |
| } |
| }); |
| } |
| }; |
| |
| // Update sync status for accounts in current ContactListFilter |
| private void onSyncStateUpdated() { |
| if (isListFragmentInSearchMode() || isListFragmentInSelectionMode()) { |
| return; |
| } |
| |
| final ContactListFilter filter = mContactListFilterController.getFilter(); |
| if (filter != null) { |
| final SwipeRefreshLayout swipeRefreshLayout = |
| mContactsListFragment.getSwipeRefreshLayout(); |
| if (swipeRefreshLayout == null) { |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null"); |
| } |
| return; |
| } |
| |
| final List<AccountWithDataSet> accounts; |
| if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT && |
| filter.isGoogleAccountType()) { |
| accounts = Collections.singletonList(new AccountWithDataSet(filter.accountName, |
| filter.accountType, null)); |
| } else if (filter.shouldShowSyncState()) { |
| accounts = AccountInfo.extractAccounts( |
| mAccountTypeManager.getWritableGoogleAccounts()); |
| } else { |
| accounts = Collections.emptyList(); |
| } |
| if (SyncUtil.isAnySyncing(accounts)) { |
| return; |
| } |
| swipeRefreshLayout.setRefreshing(false); |
| } |
| } |
| |
| public void showConnectionErrorMsg() { |
| Snackbar.make(mLayoutRoot, R.string.connection_error_message, Snackbar.LENGTH_LONG).show(); |
| } |
| |
| private final ContactListFilterListener mFilterListener = new ContactListFilterListener() { |
| @Override |
| public void onContactListFilterChanged() { |
| final ContactListFilter filter = mContactListFilterController.getFilter(); |
| handleFilterChangeForFragment(filter); |
| handleFilterChangeForActivity(filter); |
| } |
| }; |
| |
| private final ProviderStatusListener mProviderStatusListener = new ProviderStatusListener() { |
| @Override |
| public void onProviderStatusChange() { |
| // TODO see if it works with drawer fragment. |
| updateViewConfiguration(false); |
| } |
| }; |
| |
| private class ContactsActionBarDrawerToggle extends ActionBarDrawerToggle { |
| private boolean mMenuClickedBefore = SharedPreferenceUtil.getHamburgerMenuClickedBefore( |
| PeopleActivity.this); |
| |
| public ContactsActionBarDrawerToggle(AppCompatActivity activity, DrawerLayout drawerLayout, |
| Toolbar toolbar, int openDrawerContentDescRes, int closeDrawerContentDescRes) { |
| super(activity, drawerLayout, toolbar, openDrawerContentDescRes, |
| closeDrawerContentDescRes); |
| } |
| |
| @Override |
| public void onDrawerOpened(View drawerView) { |
| super.onDrawerOpened(drawerView); |
| if (!mMenuClickedBefore) { |
| SharedPreferenceUtil.setHamburgerMenuClickedBefore(PeopleActivity.this); |
| mMenuClickedBefore = true; |
| } |
| drawerView.requestFocus(); |
| invalidateOptionsMenu(); |
| // Stop search and selection mode like Gmail and Keep. Otherwise, if user switches to |
| // another fragment in navigation drawer, the current search/selection mode will be |
| // overlaid by the action bar of the newly-created fragment. |
| stopSearchAndSelection(); |
| updateStatusBarBackground(); |
| } |
| |
| private void stopSearchAndSelection() { |
| final MultiSelectContactsListFragment listFragment; |
| if (isAllContactsView() || isAccountView()) { |
| listFragment = getListFragment(); |
| } else if (isGroupView()) { |
| listFragment = getGroupFragment(); |
| } else { |
| listFragment = null; |
| } |
| if (listFragment == null) { |
| return; |
| } |
| final ActionBarAdapter actionBarAdapter = listFragment.getActionBarAdapter(); |
| if (actionBarAdapter == null) { |
| return; |
| } |
| if (actionBarAdapter.isSearchMode()) { |
| actionBarAdapter.setSearchMode(false); |
| } else if (actionBarAdapter.isSelectionMode()) { |
| actionBarAdapter.setSelectionMode(false); |
| } |
| } |
| |
| @Override |
| public void onDrawerClosed(View view) { |
| super.onDrawerClosed(view); |
| invalidateOptionsMenu(); |
| } |
| |
| @Override |
| public void onDrawerStateChanged(int newState) { |
| super.onDrawerStateChanged(newState); |
| // Set transparent status bar when drawer starts to move. |
| if (newState != DrawerLayout.STATE_IDLE) { |
| updateStatusBarBackground(); |
| } |
| } |
| } |
| |
| |
| public PeopleActivity() { |
| mInstanceId = sNextInstanceId.getAndIncrement(); |
| mIntentResolver = new ContactsIntentResolver(this); |
| mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this); |
| } |
| |
| @Override |
| public String toString() { |
| // Shown on logcat |
| return String.format("%s@%d", getClass().getSimpleName(), mInstanceId); |
| } |
| |
| private boolean areContactsAvailable() { |
| return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL); |
| } |
| |
| @Override |
| protected void onCreate(Bundle savedState) { |
| if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { |
| Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start"); |
| } |
| |
| // Make sure this is *before* calling super.onCreate |
| setTheme(R.style.PeopleActivityTheme); |
| super.onCreate(savedState); |
| |
| mAccountTypeManager = AccountTypeManager.getInstance(this); |
| mContactListFilterController = ContactListFilterController.getInstance(this); |
| |
| RequestPermissionsActivity.startPermissionActivityIfNeeded(this); |
| |
| if (!processIntent(false)) { |
| finish(); |
| return; |
| } |
| |
| mContactListFilterController.checkFilterValidity(false); |
| |
| super.setContentView(R.layout.contacts_drawer_activity); |
| |
| // Set up the action bar. |
| mToolbar = getView(R.id.toolbar); |
| setSupportActionBar(mToolbar); |
| |
| // Add shadow under toolbar. |
| ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources()); |
| |
| // Set up hamburger button. |
| mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); |
| mDrawerFragment = (DrawerFragment) getFragmentManager().findFragmentById(R.id.drawer); |
| mToggle = new ContactsActionBarDrawerToggle(this, mDrawerLayout, mToolbar, |
| R.string.navigation_drawer_open, R.string.navigation_drawer_close); |
| mDrawerLayout.setDrawerListener(mToggle); |
| // Set fallback handler for when drawer is disabled. |
| mToggle.setToolbarNavigationClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| onBackPressed(); |
| } |
| }); |
| |
| // Set up navigation mode. |
| if (savedState != null) { |
| mCurrentView = ContactsView.values()[savedState.getInt(KEY_CONTACTS_VIEW)]; |
| } else { |
| mCurrentView = ContactsView.ALL_CONTACTS; |
| } |
| |
| if (savedState != null && savedState.containsKey(KEY_NEW_GROUP_ACCOUNT)) { |
| mNewGroupAccount = AccountWithDataSet.unstringify( |
| savedState.getString(KEY_NEW_GROUP_ACCOUNT)); |
| } |
| |
| mContactListFilterController.addListener(mFilterListener); |
| mProviderStatusWatcher.addListener(mProviderStatusListener); |
| |
| mIsRecreatedInstance = (savedState != null); |
| |
| if (mIsRecreatedInstance) { |
| mGroupUri = savedState.getParcelable(KEY_GROUP_URI); |
| } |
| |
| createViewsAndFragments(); |
| |
| if (!PermissionsUtil.hasPermission(this, Manifest.permission.POST_NOTIFICATIONS)) { |
| requestPermissions(new String[] { Manifest.permission.POST_NOTIFICATIONS }, 1); |
| } |
| |
| if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) { |
| Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish"); |
| } |
| getWindow().setBackgroundDrawable(null); |
| } |
| |
| @SuppressWarnings("MissingSuperCall") // TODO: Fix me |
| @Override |
| protected void onNewIntent(Intent intent) { |
| final String action = intent.getAction(); |
| if (GroupUtil.ACTION_CREATE_GROUP.equals(action)) { |
| mGroupUri = intent.getData(); |
| if (mGroupUri == null) { |
| toast(R.string.groupSavedErrorToast); |
| return; |
| } |
| if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri); |
| switchView(ContactsView.GROUP_VIEW); |
| mMembersFragment.toastForSaveAction(action); |
| return; |
| } |
| |
| if (isGroupSaveAction(action)) { |
| mGroupUri = intent.getData(); |
| if (mGroupUri == null) { |
| popSecondLevel(); |
| toast(R.string.groupSavedErrorToast); |
| return; |
| } |
| if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri); |
| // ACTION_REMOVE_FROM_GROUP doesn't reload data, so it shouldn't cause b/32223934 |
| // but it's necessary to use the previous fragment since |
| // GroupMembersFragment#mIsEditMode needs to be persisted between remove actions. |
| if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action)) { |
| switchToOrUpdateGroupView(action); |
| } else { |
| switchView(ContactsView.GROUP_VIEW); |
| } |
| mMembersFragment.toastForSaveAction(action); |
| } |
| |
| setIntent(intent); |
| |
| if (!processIntent(true)) { |
| finish(); |
| return; |
| } |
| |
| mContactListFilterController.checkFilterValidity(false); |
| |
| if (!isInSecondLevel()) { |
| // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke |
| // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter |
| // initially. |
| mContactsListFragment.setParameters(/* ContactsRequest */ mRequest, |
| /* fromOnNewIntent */ true); |
| mContactsListFragment.initializeActionBarAdapter(null); |
| } |
| |
| initializeFabVisibility(); |
| invalidateOptionsMenuIfNeeded(); |
| } |
| |
| private static boolean isGroupSaveAction(String action) { |
| return GroupUtil.ACTION_UPDATE_GROUP.equals(action) |
| || GroupUtil.ACTION_ADD_TO_GROUP.equals(action) |
| || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action); |
| } |
| |
| private void toast(int resId) { |
| if (resId >= 0) { |
| Toast.makeText(this, resId, Toast.LENGTH_SHORT).show(); |
| } |
| } |
| |
| /** |
| * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect |
| * is needed. |
| * |
| * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}. |
| * @return {@code true} if {@link PeopleActivity} should continue running. {@code false} |
| * if it shouldn't, in which case the caller should finish() itself and shouldn't do |
| * farther initialization. |
| */ |
| private boolean processIntent(boolean forNewIntent) { |
| // Extract relevant information from the intent |
| mRequest = mIntentResolver.resolveIntent(getIntent()); |
| if (Log.isLoggable(TAG, Log.DEBUG)) { |
| Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent |
| + " intent=" + getIntent() + " request=" + mRequest); |
| } |
| if (!mRequest.isValid()) { |
| setResult(RESULT_CANCELED); |
| return false; |
| } |
| |
| switch (mRequest.getActionCode()) { |
| case ContactsRequest.ACTION_VIEW_CONTACT: { |
| ImplicitIntentsUtil.startQuickContact( |
| this, mRequest.getContactUri(), ScreenType.UNKNOWN); |
| return false; |
| } |
| case ContactsRequest.ACTION_INSERT_GROUP: { |
| onCreateGroupMenuItemClicked(); |
| return true; |
| } |
| case ContactsRequest.ACTION_VIEW_GROUP: |
| case ContactsRequest.ACTION_EDIT_GROUP: { |
| mShouldSwitchToGroupView = true; |
| return true; |
| } |
| } |
| return true; |
| } |
| |
| private void createViewsAndFragments() { |
| setContentView(R.layout.people_activity); |
| |
| final FragmentManager fragmentManager = getFragmentManager(); |
| |
| setUpListFragment(fragmentManager); |
| |
| mMembersFragment = (GroupMembersFragment) fragmentManager.findFragmentByTag(TAG_GROUP_VIEW); |
| |
| // Configure floating action button |
| mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container); |
| final ImageButton floatingActionButton |
| = (ImageButton) findViewById(R.id.floating_action_button); |
| floatingActionButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(), |
| mContactListFilterController.getFilter()); |
| } |
| }); |
| mFloatingActionButtonController = new FloatingActionButtonController(this, |
| mFloatingActionButtonContainer, floatingActionButton); |
| |
| invalidateOptionsMenuIfNeeded(); |
| |
| mLayoutRoot = (CoordinatorLayout) findViewById(R.id.root); |
| |
| if (mShouldSwitchToGroupView && !mIsRecreatedInstance) { |
| mGroupUri = mRequest.getContactUri(); |
| switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP); |
| mShouldSwitchToGroupView = false; |
| } |
| } |
| |
| @Override |
| public void setContentView(@LayoutRes int layoutResID) { |
| final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame); |
| if (parent != null) { |
| parent.removeAllViews(); |
| } |
| LayoutInflater.from(this).inflate(layoutResID, parent); |
| } |
| |
| private void setUpListFragment(FragmentManager fragmentManager) { |
| mContactsListFragment = (DefaultContactBrowseListFragment) |
| fragmentManager.findFragmentByTag(TAG_ALL); |
| |
| if (mContactsListFragment == null) { |
| mContactsListFragment = new DefaultContactBrowseListFragment(); |
| mContactsListFragment.setAnimateOnLoad(true); |
| fragmentManager.beginTransaction() |
| .add(R.id.contacts_list_container, mContactsListFragment, TAG_ALL) |
| .commit(); |
| fragmentManager.executePendingTransactions(); |
| } |
| |
| mContactsListFragment.setContactsAvailable(areContactsAvailable()); |
| mContactsListFragment.setListType(mContactListFilterController.getFilterListType()); |
| mContactsListFragment.setParameters(/* ContactsRequest */ mRequest, |
| /* fromOnNewIntent */ false); |
| } |
| |
| @Override |
| protected void onPause() { |
| mProviderStatusWatcher.stop(); |
| |
| LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener); |
| |
| super.onPause(); |
| |
| ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle); |
| onSyncStateUpdated(); |
| } |
| |
| @SuppressWarnings("MissingSuperCall") // TODO: Fix me |
| @Override |
| public void onMultiWindowModeChanged(boolean entering) { |
| initializeHomeVisibility(); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| |
| if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { |
| updateStatusBarBackground(); |
| } |
| |
| if (mShouldSwitchToAllContacts) { |
| switchToAllContacts(); |
| } |
| |
| mProviderStatusWatcher.start(); |
| updateViewConfiguration(true); |
| |
| mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener( |
| ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE |
| | ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
| | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, |
| mSyncStatusObserver); |
| onSyncStateUpdated(); |
| |
| initializeFabVisibility(); |
| initializeHomeVisibility(); |
| |
| mSaveServiceListener = new SaveServiceListener(); |
| LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener, |
| new IntentFilter(ContactSaveService.BROADCAST_GROUP_DELETED)); |
| } |
| |
| public void updateStatusBarBackground() { |
| updateStatusBarBackground(/* color */ -1); |
| } |
| |
| public void updateStatusBarBackground(int color) { |
| if (!CompatUtils.isLollipopCompatible()) return; |
| if (color == -1) { |
| mDrawerLayout.setStatusBarBackgroundColor( |
| MaterialColorMapUtils.getStatusBarColor(this)); |
| } else { |
| mDrawerLayout.setStatusBarBackgroundColor(color); |
| } |
| mDrawerLayout.invalidate(); |
| getWindow().setStatusBarColor(Color.TRANSPARENT); |
| } |
| |
| @Override |
| protected void onDestroy() { |
| mProviderStatusWatcher.removeListener(mProviderStatusListener); |
| mContactListFilterController.removeListener(mFilterListener); |
| super.onDestroy(); |
| } |
| |
| private void initializeFabVisibility() { |
| mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE); |
| mFloatingActionButtonController.resetIn(); |
| wasLastFabAnimationScaleIn = !shouldHideFab(); |
| } |
| |
| private void initializeHomeVisibility() { |
| // Remove the navigation icon if we return to the fragment in a search or select state |
| if (getToolbar() != null && (isListFragmentInSelectionMode() |
| || isListFragmentInSearchMode() || isGroupsFragmentInSelectionMode() |
| || isGroupsFragmentInSearchMode())) { |
| getToolbar().setNavigationIcon(null); |
| } |
| } |
| |
| private boolean shouldHideFab() { |
| if (mContactsListFragment != null && mContactsListFragment.getActionBarAdapter() == null |
| || isInSecondLevel()) { |
| return true; |
| } |
| return isListFragmentInSearchMode() |
| || isListFragmentInSelectionMode(); |
| } |
| |
| public void showFabWithAnimation(boolean showFab) { |
| if (mFloatingActionButtonContainer == null) { |
| return; |
| } |
| if (showFab) { |
| if (!wasLastFabAnimationScaleIn) { |
| mFloatingActionButtonContainer.setVisibility(View.VISIBLE); |
| mFloatingActionButtonController.scaleIn(0); |
| } |
| wasLastFabAnimationScaleIn = true; |
| |
| } else { |
| if (wasLastFabAnimationScaleIn) { |
| mFloatingActionButtonContainer.setVisibility(View.VISIBLE); |
| mFloatingActionButtonController.scaleOut(); |
| } |
| wasLastFabAnimationScaleIn = false; |
| } |
| } |
| |
| private void updateViewConfiguration(boolean forceUpdate) { |
| int providerStatus = mProviderStatusWatcher.getProviderStatus(); |
| if (!forceUpdate && (mProviderStatus != null) |
| && (mProviderStatus.equals(providerStatus))) return; |
| mProviderStatus = providerStatus; |
| |
| final FragmentManager fragmentManager= getFragmentManager(); |
| final FragmentTransaction transaction = fragmentManager.beginTransaction(); |
| |
| // Change in CP2's provider status may not take effect immediately, see b/30566908. |
| // So we need to handle the case where provider status is STATUS_EMPTY and there is |
| // actually at least one real account (not "local" account) on device. |
| if (shouldShowList()) { |
| if (mContactsListFragment != null) { |
| final Fragment unavailableFragment = fragmentManager |
| .findFragmentByTag(TAG_UNAVAILABLE); |
| if (unavailableFragment != null) { |
| transaction.remove(unavailableFragment); |
| } |
| if (mContactsListFragment.isHidden()) { |
| transaction.show(mContactsListFragment); |
| } |
| mContactsListFragment.setContactsAvailable(areContactsAvailable()); |
| mContactsListFragment.setEnabled(true); |
| } |
| } else { |
| // Setting up the page so that the user can still use the app |
| // even without an account. |
| if (mContactsListFragment != null) { |
| mContactsListFragment.setEnabled(false); |
| } |
| final ContactsUnavailableFragment fragment = new ContactsUnavailableFragment(); |
| transaction.hide(mContactsListFragment); |
| transaction.replace(R.id.contacts_unavailable_container, fragment, TAG_UNAVAILABLE); |
| fragment.updateStatus(mProviderStatus); |
| } |
| if (!transaction.isEmpty()) { |
| transaction.commit(); |
| fragmentManager.executePendingTransactions(); |
| } |
| |
| invalidateOptionsMenuIfNeeded(); |
| } |
| |
| private boolean shouldShowList() { |
| return mProviderStatus != null |
| && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) |
| && mAccountTypeManager.hasNonLocalAccount()) |
| || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL)); |
| } |
| |
| private void invalidateOptionsMenuIfNeeded() { |
| if (mContactsListFragment != null |
| && mContactsListFragment.getOptionsMenuContactsAvailable() |
| != areContactsAvailable()) { |
| invalidateOptionsMenu(); |
| } |
| } |
| |
| @Override |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| // If the drawer is open, consume KEYCODE_BACK event only. |
| if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { |
| if (keyCode == KeyEvent.KEYCODE_BACK) { |
| // Should eventually go to onBackPressed(). |
| return super.onKeyDown(keyCode, event); |
| } |
| return false; |
| } |
| // Bring up the search UI if the user starts typing |
| final int unicodeChar = event.getUnicodeChar(); |
| if ((unicodeChar != 0) |
| // If COMBINING_ACCENT is set, it's not a unicode character. |
| && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0) |
| && !Character.isWhitespace(unicodeChar)) { |
| if (mContactsListFragment.onKeyDown(unicodeChar)) { |
| return true; |
| } |
| } |
| |
| return super.onKeyDown(keyCode, event); |
| } |
| |
| @Override |
| public void onBackPressed() { |
| if (!isSafeToCommitTransactions()) { |
| return; |
| } |
| |
| // Handle the back event in drawer first. |
| if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) { |
| closeDrawer(); |
| return; |
| } |
| |
| // Handle the back event in "second level". |
| if (isGroupView()) { |
| onBackPressedGroupView(); |
| return; |
| } |
| |
| if (isAssistantView()) { |
| onBackPressedAssistantView(); |
| return; |
| } |
| |
| // If feature highlight is present, let it handle the back event before |
| // mContactsListFragment. |
| if (FeatureHighlightHelper.tryRemoveHighlight(this)) { |
| return; |
| } |
| |
| // Handle the back event in "first level" - mContactsListFragment. |
| if (maybeHandleInListFragment()) { |
| return; |
| } |
| |
| super.onBackPressed(); |
| } |
| |
| private void onBackPressedGroupView() { |
| if (mMembersFragment.isEditMode()) { |
| mMembersFragment.exitEditMode(); |
| } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) { |
| mMembersFragment.getActionBarAdapter().setSelectionMode(false); |
| mMembersFragment.displayCheckBoxes(false); |
| } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) { |
| mMembersFragment.getActionBarAdapter().setSearchMode(false); |
| } else { |
| switchToAllContacts(); |
| } |
| } |
| |
| private void onBackPressedAssistantView() { |
| if (!isInThirdLevel()) { |
| switchToAllContacts(); |
| } else { |
| setDrawerLockMode(/* enabled */ true); |
| super.onBackPressed(); |
| } |
| } |
| |
| // Returns true if back event is handled in this method. |
| private boolean maybeHandleInListFragment() { |
| if (isListFragmentInSelectionMode()) { |
| mContactsListFragment.getActionBarAdapter().setSelectionMode(false); |
| return true; |
| } |
| |
| if (isListFragmentInSearchMode()) { |
| mContactsListFragment.getActionBarAdapter().setSearchMode(false); |
| if (mContactsListFragment.wasSearchResultClicked()) { |
| mContactsListFragment.resetSearchResultClicked(); |
| } else { |
| Logger.logScreenView(this, ScreenType.SEARCH_EXIT); |
| Logger.logSearchEvent(mContactsListFragment.createSearchState()); |
| } |
| return true; |
| } |
| |
| if (!AccountFilterUtil.isAllContactsFilter(mContactListFilterController.getFilter()) |
| && !mContactsListFragment.isHidden()) { |
| // If mContactsListFragment is hidden, then mContactsUnavailableFragment is visible so we |
| // don't need to switch to all contacts. |
| switchToAllContacts(); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| private boolean isListFragmentInSelectionMode() { |
| return mContactsListFragment != null && mContactsListFragment.getActionBarAdapter() != null |
| && mContactsListFragment.getActionBarAdapter().isSelectionMode(); |
| } |
| |
| private boolean isListFragmentInSearchMode() { |
| return mContactsListFragment != null && mContactsListFragment.getActionBarAdapter() != null |
| && mContactsListFragment.getActionBarAdapter().isSearchMode(); |
| } |
| |
| private boolean isGroupsFragmentInSelectionMode() { |
| return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null |
| && mMembersFragment.getActionBarAdapter().isSelectionMode(); |
| } |
| |
| private boolean isGroupsFragmentInSearchMode() { |
| return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null |
| && mMembersFragment.getActionBarAdapter().isSearchMode(); |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| super.onSaveInstanceState(outState); |
| if (mNewGroupAccount != null) { |
| outState.putString(KEY_NEW_GROUP_ACCOUNT, mNewGroupAccount.stringify()); |
| } |
| outState.putInt(KEY_CONTACTS_VIEW, mCurrentView.ordinal()); |
| outState.putParcelable(KEY_GROUP_URI, mGroupUri); |
| } |
| |
| @Override |
| protected void onRestoreInstanceState(Bundle savedInstanceState) { |
| super.onRestoreInstanceState(savedInstanceState); |
| mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI); |
| } |
| |
| private void onGroupDeleted(final Intent intent) { |
| if (!ContactSaveService.canUndo(intent)) return; |
| |
| final AccessibilityManager am = |
| (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); |
| //TODO set to INDEFINITE and track user interaction to dismiss b/33208886 |
| final int accessibilityLength = 15000; |
| final int length = am.isEnabled() ? accessibilityLength : Snackbar.LENGTH_LONG; |
| final String message = getString(R.string.groupDeletedToast); |
| |
| final Snackbar snackbar = Snackbar.make(mLayoutRoot, message, length) |
| .setAction(R.string.undo, new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| ContactSaveService.startService(PeopleActivity.this, |
| ContactSaveService.createUndoIntent(PeopleActivity.this, intent)); |
| } |
| }).setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_action_text)); |
| |
| // Announce for a11y talkback |
| mLayoutRoot.announceForAccessibility(message); |
| mLayoutRoot.announceForAccessibility(getString(R.string.undo)); |
| |
| snackbar.show(); |
| } |
| |
| private class SaveServiceListener extends BroadcastReceiver { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| switch (intent.getAction()) { |
| case ContactSaveService.BROADCAST_GROUP_DELETED: |
| onGroupDeleted(intent); |
| break; |
| } |
| } |
| } |
| |
| private void onGroupMenuItemClicked(long groupId) { |
| if (isGroupView() && mMembersFragment != null |
| && mMembersFragment.isCurrentGroup(groupId)) { |
| return; |
| } |
| mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId); |
| switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP); |
| } |
| |
| private void onFilterMenuItemClicked(Intent intent) { |
| // We must pop second level first to "restart" mContactsListFragment before changing filter. |
| if (isInSecondLevel()) { |
| popSecondLevel(); |
| showFabWithAnimation(/* showFab */ true); |
| // HACK: swap the current filter to force listeners to update because the group |
| // member view no longer changes the filter. Fix for b/32223767 |
| final ContactListFilter current = mContactListFilterController.getFilter(); |
| mContactListFilterController.setContactListFilter( |
| AccountFilterUtil.createContactsFilter(this), false); |
| mContactListFilterController.setContactListFilter(current, false); |
| } |
| mCurrentView = ContactsView.ACCOUNT_VIEW; |
| AccountFilterUtil.handleAccountFilterResult(mContactListFilterController, |
| AppCompatActivity.RESULT_OK, intent); |
| } |
| |
| private void switchToOrUpdateGroupView(String action) { |
| // If group fragment is active and visible, we simply update it. |
| if (mMembersFragment != null && !mMembersFragment.isInactive()) { |
| mMembersFragment.updateExistingGroupFragment(mGroupUri, action); |
| } else { |
| switchView(ContactsView.GROUP_VIEW); |
| } |
| } |
| |
| protected void launchAssistant() { |
| switchView(ContactsView.ASSISTANT); |
| } |
| |
| private void switchView(ContactsView contactsView) { |
| mCurrentView = contactsView; |
| |
| final FragmentManager fragmentManager = getFragmentManager(); |
| final FragmentTransaction transaction = fragmentManager.beginTransaction(); |
| popSecondLevel(); |
| if (isGroupView()) { |
| mMembersFragment = GroupMembersFragment.newInstance(mGroupUri); |
| transaction.replace( |
| R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW); |
| } else if (isAssistantView()) { |
| Fragment uiFragment = fragmentManager.findFragmentByTag(TAG_ASSISTANT); |
| Fragment unavailableFragment = fragmentManager.findFragmentByTag(TAG_UNAVAILABLE); |
| if (uiFragment == null) { |
| uiFragment = ObjectFactory.getAssistantFragment(); |
| } |
| if (unavailableFragment != null) { |
| transaction.remove(unavailableFragment); |
| } |
| transaction.replace(R.id.contacts_list_container, uiFragment, TAG_ASSISTANT); |
| resetToolBarStatusBarColor(); |
| } |
| transaction.addToBackStack(TAG_SECOND_LEVEL); |
| transaction.commit(); |
| fragmentManager.executePendingTransactions(); |
| |
| showFabWithAnimation(/* showFab */ false); |
| } |
| |
| public void switchToAllContacts() { |
| popSecondLevel(); |
| mShouldSwitchToAllContacts = false; |
| mCurrentView = ContactsView.ALL_CONTACTS; |
| mDrawerFragment.setNavigationItemChecked(ContactsView.ALL_CONTACTS); |
| showFabWithAnimation(/* showFab */ true); |
| mContactsListFragment.scrollToTop(); |
| resetFilter(); |
| setTitle(getString(R.string.contactsList)); |
| } |
| |
| private void resetFilter() { |
| final Intent intent = new Intent(); |
| final ContactListFilter filter = AccountFilterUtil.createContactsFilter(this); |
| intent.putExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER, filter); |
| AccountFilterUtil.handleAccountFilterResult( |
| mContactListFilterController, AppCompatActivity.RESULT_OK, intent); |
| } |
| |
| // Reset toolbar and status bar color to Contacts theme color. |
| private void resetToolBarStatusBarColor() { |
| findViewById(R.id.toolbar_frame).setBackgroundColor( |
| ContextCompat.getColor(this, R.color.primary_color)); |
| updateStatusBarBackground(ContextCompat.getColor(this, R.color.primary_color_dark)); |
| } |
| |
| protected DefaultContactBrowseListFragment getListFragment() { |
| return mContactsListFragment; |
| } |
| |
| protected GroupMembersFragment getGroupFragment() { |
| return mMembersFragment; |
| } |
| |
| private void handleFilterChangeForFragment(ContactListFilter filter) { |
| if (mContactsListFragment.canSetActionBar()) { |
| mContactsListFragment.setFilterAndUpdateTitle(filter); |
| // Scroll to top after filter is changed. |
| mContactsListFragment.scrollToTop(); |
| } |
| } |
| |
| private void handleFilterChangeForActivity(ContactListFilter filter) { |
| // The filter was changed while this activity was in the background. If we're in the |
| // assistant view Switch to the main contacts list when we resume to prevent |
| // b/31838582 and b/31829161 |
| // TODO: this is a hack; we need to do some cleanup of the contact list filter stuff |
| if (isAssistantView() && filter.isContactsFilterType()) { |
| mShouldSwitchToAllContacts = true; |
| } |
| |
| if (CompatUtils.isNCompatible()) { |
| getWindow().getDecorView() |
| .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); |
| } |
| invalidateOptionsMenu(); |
| } |
| |
| public void updateDrawerGroupMenu(long groupId) { |
| if (mDrawerFragment != null) { |
| mDrawerFragment.updateGroupMenu(groupId); |
| } |
| } |
| |
| public void setDrawerLockMode(boolean enabled) { |
| // Prevent drawer from being opened by sliding from the start of screen. |
| mDrawerLayout.setDrawerLockMode(enabled ? DrawerLayout.LOCK_MODE_UNLOCKED |
| : DrawerLayout.LOCK_MODE_LOCKED_CLOSED); |
| |
| // Order of these statements matter. |
| // Display back button and disable drawer indicator. |
| if (enabled) { |
| getSupportActionBar().setDisplayHomeAsUpEnabled(false); |
| mToggle.setDrawerIndicatorEnabled(true); |
| } else { |
| mToggle.setDrawerIndicatorEnabled(false); |
| getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
| } |
| } |
| |
| public Toolbar getToolbar() { |
| return mToolbar; |
| } |
| |
| @Override |
| protected void onPostCreate(Bundle savedInstanceState) { |
| super.onPostCreate(savedInstanceState); |
| mToggle.syncState(); |
| } |
| |
| @Override |
| public void onConfigurationChanged(Configuration newConfig) { |
| super.onConfigurationChanged(newConfig); |
| mToggle.onConfigurationChanged(newConfig); |
| } |
| |
| protected void onCreateGroupMenuItemClicked() { |
| // Select the account to create the group |
| final Bundle extras = getIntent().getExtras(); |
| final Account account = extras == null ? null : |
| (Account) extras.getParcelable(Intents.Insert.EXTRA_ACCOUNT); |
| if (account == null) { |
| selectAccountForNewGroup(); |
| } else { |
| final String dataSet = extras == null |
| ? null : extras.getString(Intents.Insert.EXTRA_DATA_SET); |
| final AccountWithDataSet accountWithDataSet = new AccountWithDataSet( |
| account.name, account.type, dataSet); |
| onAccountChosen(accountWithDataSet, /* extraArgs */ null); |
| } |
| } |
| |
| private void selectAccountForNewGroup() { |
| // This should never block because the DrawerFragment loads the accounts and the |
| // "Create Label" item only exists when that loading finishes |
| final List<AccountInfo> accounts = Futures.getUnchecked(AccountTypeManager.getInstance(this) |
| .filterAccountsAsync(AccountTypeManager.AccountFilter.GROUPS_WRITABLE)); |
| if (accounts.isEmpty()) { |
| // We shouldn't present the add group button if there are no writable accounts |
| // but check it since it's possible we are started with an Intent. |
| Toast.makeText(this, R.string.groupCreateFailedToast, Toast.LENGTH_SHORT).show(); |
| return; |
| } |
| // If there is a single writable account, use it w/o showing a dialog. |
| if (accounts.size() == 1) { |
| onAccountChosen(accounts.get(0).getAccount(), /* extraArgs */ null); |
| return; |
| } |
| SelectAccountDialogFragment.show(getFragmentManager(), R.string.dialog_new_group_account, |
| AccountTypeManager.AccountFilter.GROUPS_WRITABLE, /* extraArgs */ null, |
| TAG_SELECT_ACCOUNT_DIALOG); |
| } |
| |
| // Implementation of SelectAccountDialogFragment.Listener |
| @Override |
| public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) { |
| mNewGroupAccount = account; |
| GroupNameEditDialogFragment.newInstanceForCreation( |
| mNewGroupAccount, GroupUtil.ACTION_CREATE_GROUP) |
| .show(getFragmentManager(), TAG_GROUP_NAME_EDIT_DIALOG); |
| } |
| |
| @Override |
| public void onAccountSelectorCancelled() { |
| } |
| |
| // Implementation of DrawerFragmentListener |
| @Override |
| public void onDrawerItemClicked(){ |
| closeDrawer(); |
| } |
| |
| @Override |
| public void onContactsViewSelected(ContactsView mode) { |
| if (mode == ContactsView.ALL_CONTACTS) { |
| switchToAllContacts(); |
| } else if (mode == ContactsView.ASSISTANT) { |
| launchAssistant(); |
| } else { |
| throw new IllegalStateException("Unknown view " + mode); |
| } |
| } |
| |
| @Override |
| public void onCreateLabelButtonClicked() { |
| onCreateGroupMenuItemClicked(); |
| } |
| |
| @Override |
| public void onOpenSettings() { |
| new Handler().postDelayed(new Runnable() { |
| @Override |
| public void run() { |
| startActivity(createPreferenceIntent()); |
| } |
| }, DRAWER_CLOSE_DELAY); |
| } |
| |
| @Override |
| public void onLaunchHelpFeedback() { |
| HelpUtils.launchHelpAndFeedbackForMainScreen(this); |
| } |
| |
| @Override |
| public void onGroupViewSelected(GroupListItem groupListItem) { |
| onGroupMenuItemClicked(groupListItem.getGroupId()); |
| } |
| |
| @Override |
| public void onAccountViewSelected(ContactListFilter filter) { |
| final Intent intent = new Intent(); |
| intent.putExtra(AccountFilterActivity.EXTRA_CONTACT_LIST_FILTER, filter); |
| onFilterMenuItemClicked(intent); |
| } |
| |
| public boolean isGroupView() { |
| return mCurrentView == ContactsView.GROUP_VIEW; |
| } |
| |
| protected boolean isAssistantView() { |
| return mCurrentView == ContactsView.ASSISTANT; |
| } |
| |
| protected boolean isAllContactsView() { |
| return mCurrentView == ContactsView.ALL_CONTACTS; |
| } |
| |
| protected boolean isAccountView() { |
| return mCurrentView == ContactsView.ACCOUNT_VIEW; |
| } |
| |
| public boolean isInSecondLevel() { |
| return isGroupView() || isAssistantView(); |
| } |
| |
| private boolean isInThirdLevel() { |
| return isLastBackStackTag(TAG_THIRD_LEVEL); |
| } |
| |
| private boolean isLastBackStackTag(String tag) { |
| final int count = getFragmentManager().getBackStackEntryCount(); |
| if (count > 0) { |
| final FragmentManager.BackStackEntry last = |
| getFragmentManager().getBackStackEntryAt(count - 1); |
| if (tag == null) { |
| return last.getName() == null; |
| } |
| return tag.equals(last.getName()); |
| } |
| return false; |
| } |
| |
| private void popSecondLevel() { |
| getFragmentManager().popBackStackImmediate( |
| TAG_ASSISTANT_HELPER, FragmentManager.POP_BACK_STACK_INCLUSIVE); |
| getFragmentManager().popBackStackImmediate( |
| TAG_SECOND_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE); |
| mMembersFragment = null; |
| resetToolBarStatusBarColor(); |
| } |
| |
| public void closeDrawer() { |
| mDrawerLayout.closeDrawer(GravityCompat.START); |
| } |
| |
| private Intent createPreferenceIntent() { |
| final Intent intent = new Intent(this, ContactsPreferenceActivity.class); |
| intent.putExtra(ContactsPreferenceActivity.EXTRA_NEW_LOCAL_PROFILE, |
| ContactEditorFragment.INTENT_EXTRA_NEW_LOCAL_PROFILE); |
| return intent; |
| } |
| |
| |
| } |