blob: 426dcd70de10995f435f1cb924bc3118b8d70ef5 [file] [log] [blame]
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08001/*
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -07002 * Copyright (C) 2010 The Android Open Source Project
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -08003 *
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
Dmitri Plotnikov27834b22010-07-01 14:10:08 -070017package com.android.contacts.activities;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080018
Wenyi Wang303b9492016-06-21 10:06:30 -070019import android.accounts.Account;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070020import android.app.Fragment;
21import android.app.FragmentManager;
22import android.app.FragmentTransaction;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070023import android.content.BroadcastReceiver;
John Shao52dd5d72016-10-06 15:16:14 -070024import android.content.ContentResolver;
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -070025import android.content.ContentUris;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070026import android.content.Context;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070027import android.content.Intent;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070028import android.content.IntentFilter;
John Shao52dd5d72016-10-06 15:16:14 -070029import android.content.SyncStatusObserver;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070030import android.net.Uri;
31import android.os.Bundle;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070032import android.os.Handler;
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -070033import android.provider.ContactsContract;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070034import android.provider.ContactsContract.ProviderStatus;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070035import android.support.design.widget.CoordinatorLayout;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070036import android.support.design.widget.Snackbar;
Wenyi Wang92d7e512016-10-03 14:57:19 -070037import android.support.v4.content.ContextCompat;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070038import android.support.v4.content.LocalBroadcastManager;
Walter Jang758f5652016-04-05 09:29:56 -070039import android.support.v4.view.GravityCompat;
Xi Chen947c23d2016-06-30 20:23:52 -070040import android.support.v4.widget.SwipeRefreshLayout;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070041import android.util.Log;
42import android.view.KeyCharacterMap;
43import android.view.KeyEvent;
44import android.view.Menu;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070045import android.view.MenuItem;
Wenyi Wang9cfe1af2016-04-07 18:06:08 -070046import android.view.SubMenu;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070047import android.view.View;
Wenyi Wang32912eb2016-09-29 17:17:07 -070048import android.view.accessibility.AccessibilityEvent;
James Laskey6b712bc2016-11-22 11:02:09 -080049import android.view.accessibility.AccessibilityManager;
Paul Soulos2b9563d2014-05-27 16:21:23 -070050import android.widget.ImageButton;
Jay Shraunerd391f842014-11-26 11:14:24 -080051import android.widget.Toast;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070052
Cody Thomasf32dc992016-05-11 10:56:04 -070053import com.android.contacts.ContactSaveService;
Wenyi Wangbb229242016-05-25 16:04:13 -070054import com.android.contacts.ContactsDrawerActivity;
Dmitri Plotnikov27834b22010-07-01 14:10:08 -070055import com.android.contacts.R;
Gary Mai69c182a2016-12-05 13:07:03 -080056import com.android.contacts.compat.CompatUtils;
Gary Mai0a49afa2016-12-05 15:53:58 -080057import com.android.contacts.group.GroupMembersFragment;
58import com.android.contacts.group.GroupMetaData;
59import com.android.contacts.group.GroupUtil;
Gary Mai69c182a2016-12-05 13:07:03 -080060import com.android.contacts.list.ContactListFilter;
61import com.android.contacts.list.ContactListFilterController.ContactListFilterListener;
Gary Mai0a49afa2016-12-05 15:53:58 -080062import com.android.contacts.list.ContactsIntentResolver;
63import com.android.contacts.list.ContactsRequest;
64import com.android.contacts.list.ContactsUnavailableFragment;
65import com.android.contacts.list.DefaultContactBrowseListFragment;
Gary Mai69c182a2016-12-05 13:07:03 -080066import com.android.contacts.list.ProviderStatusWatcher;
67import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
68import com.android.contacts.logging.Logger;
69import com.android.contacts.logging.ScreenEvent.ScreenType;
70import com.android.contacts.model.AccountTypeManager;
Marcus Hagerott396aab72016-12-12 12:00:21 -080071import com.android.contacts.model.account.AccountType;
Gary Mai69c182a2016-12-05 13:07:03 -080072import com.android.contacts.model.account.AccountWithDataSet;
73import com.android.contacts.util.AccountFilterUtil;
74import com.android.contacts.util.Constants;
75import com.android.contacts.util.ImplicitIntentsUtil;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070076import com.android.contacts.util.SyncUtil;
Gary Mai0a49afa2016-12-05 15:53:58 -080077import com.android.contacts.widget.FloatingActionButtonController;
Wenyi Wangf9905062016-09-14 10:07:59 -070078import com.android.contactsbind.FeatureHighlightHelper;
Wenyi Wang79675452016-08-17 10:43:28 -070079import com.android.contactsbind.ObjectFactory;
Tadashi G. Takaoka57cf30f2009-09-21 19:54:39 +090080
Marcus Hagerott396aab72016-12-12 12:00:21 -080081import java.util.Collections;
Brian Attwell20510ec2015-02-27 16:10:45 -080082import java.util.List;
Makoto Onuki6d9befe2011-07-17 11:00:12 -070083import java.util.concurrent.atomic.AtomicInteger;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070084
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080085/**
Brian Attwell2c1bfd02014-06-04 18:18:35 -070086 * Displays a list to browse contacts.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080087 */
Wenyi Wang32912eb2016-09-29 17:17:07 -070088public class PeopleActivity extends ContactsDrawerActivity {
Dmitri Plotnikov57d27da2009-09-28 18:06:11 -070089
Dave Santoro5e684a42011-06-10 13:23:35 -070090 private static final String TAG = "PeopleActivity";
Wenyi Wangca6018d2016-08-18 17:23:13 -070091 private static final String TAG_ALL = "contacts-all";
Wenyi Wang79675452016-08-17 10:43:28 -070092 private static final String TAG_UNAVAILABLE = "contacts-unavailable";
Wenyi Wangcc8f2722016-09-07 14:52:32 -070093 private static final String TAG_GROUP_VIEW = "contacts-groups";
John Shao52dd5d72016-10-06 15:16:14 -070094 public static final String TAG_ASSISTANT = "contacts-assistant";
95 public static final String TAG_SECOND_LEVEL = "second-level";
96 public static final String TAG_THIRD_LEVEL = "third-level";
97
98 public static final String TAG_DUPLICATES = "DuplicatesFragment";
Wenyi Wang79675452016-08-17 10:43:28 -070099 public static final String TAG_DUPLICATES_UTIL = "DuplicatesUtilFragment";
100
101 private static final String KEY_GROUP_URI = "groupUri";
Wenyi Wangca6018d2016-08-18 17:23:13 -0700102
Dmitri Plotnikovac0f7832010-04-22 13:26:52 -0700103 private ContactsIntentResolver mIntentResolver;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700104 private ContactsRequest mRequest;
Marcus Hagerott396aab72016-12-12 12:00:21 -0800105 private AccountTypeManager mAccountTypeManager;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700106
Brian Attwell865847b2015-04-20 14:40:17 -0700107 private FloatingActionButtonController mFloatingActionButtonController;
108 private View mFloatingActionButtonContainer;
109 private boolean wasLastFabAnimationScaleIn = false;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700110
Makoto Onukic2bd6132012-04-27 16:14:51 -0700111 private ProviderStatusWatcher mProviderStatusWatcher;
Brian Attwellc3d202c2015-01-08 15:01:03 -0800112 private Integer mProviderStatus;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800113
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700114 private BroadcastReceiver mSaveServiceListener;
115
Wenyi Wang79675452016-08-17 10:43:28 -0700116 private boolean mShouldSwitchToGroupView;
117
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700118 private CoordinatorLayout mLayoutRoot;
119
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700120 /**
121 * Showing a list of Contacts. Also used for showing search results in search mode.
122 */
Walter Jange9ea4f02016-05-10 09:39:46 -0700123 private DefaultContactBrowseListFragment mAllFragment;
Katherine Kuanb5760b92011-06-01 16:19:40 -0700124
Wenyi Wang79675452016-08-17 10:43:28 -0700125 private GroupMembersFragment mMembersFragment;
126 private Uri mGroupUri;
Katherine Kuan58fc5772011-07-04 10:08:32 -0700127
Makoto Onuki417ca492011-07-14 19:06:35 -0700128 /**
129 * True if this activity instance is a re-created one. i.e. set true after orientation change.
Makoto Onuki417ca492011-07-14 19:06:35 -0700130 */
131 private boolean mIsRecreatedInstance;
132
Wenyi Wang32912eb2016-09-29 17:17:07 -0700133 private boolean mShouldSwitchToAllContacts;
134
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700135 /** Sequential ID assigned to each instance; used for logging */
136 private final int mInstanceId;
137 private static final AtomicInteger sNextInstanceId = new AtomicInteger();
138
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700139 private Object mStatusChangeListenerHandle;
140
141 private final Handler mHandler = new Handler();
142
143 private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
144 public void onStatusChanged(int which) {
145 mHandler.post(new Runnable() {
146 public void run() {
147 onSyncStateUpdated();
148 }
149 });
150 }
151 };
152
153 // Update sync status for accounts in current ContactListFilter
154 private void onSyncStateUpdated() {
Wenyi Wanged9f9742016-09-08 13:50:39 -0700155 if (isAllFragmentInSearchMode() || isAllFragmentInSelectionMode()) {
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700156 return;
157 }
158
Wenyi Wang32912eb2016-09-29 17:17:07 -0700159 final ContactListFilter filter = mContactListFilterController.getFilter();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700160 if (filter != null) {
161 final SwipeRefreshLayout swipeRefreshLayout = mAllFragment.getSwipeRefreshLayout();
162 if (swipeRefreshLayout == null) {
163 if (Log.isLoggable(TAG, Log.DEBUG)) {
164 Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null");
165 }
166 return;
167 }
168
Marcus Hagerott396aab72016-12-12 12:00:21 -0800169 final List<AccountWithDataSet> accounts;
170 if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
171 filter.isGoogleAccountType()) {
172 accounts = Collections.singletonList(new AccountWithDataSet(filter.accountName,
173 filter.accountType, null));
174 } else if (filter.shouldShowSyncState()) {
175 accounts = mAccountTypeManager.getWritableGoogleAccounts();
176 } else {
177 accounts = Collections.emptyList();
178 }
179 if (SyncUtil.isAnySyncing(accounts)) {
180 return;
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700181 }
182 swipeRefreshLayout.setRefreshing(false);
183 }
184 }
185
yaolu395c3f82016-10-18 11:13:39 -0700186 public void showConnectionErrorMsg() {
187 Snackbar.make(mLayoutRoot, R.string.connection_error_message, Snackbar.LENGTH_LONG).show();
188 }
189
Wenyi Wang32912eb2016-09-29 17:17:07 -0700190 private final ContactListFilterListener mFilterListener = new ContactListFilterListener() {
191 @Override
192 public void onContactListFilterChanged() {
193 final ContactListFilter filter = mContactListFilterController.getFilter();
194 handleFilterChangeForFragment(filter);
195 handleFilterChangeForActivity(filter);
196 }
197 };
198
199 private final ProviderStatusListener mProviderStatusListener = new ProviderStatusListener() {
200 @Override
201 public void onProviderStatusChange() {
202 reloadGroupsAndFiltersIfNeeded();
203 updateViewConfiguration(false);
204 }
205 };
206
Katherine Kuan9856fce2011-06-01 10:24:09 -0700207 public PeopleActivity() {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700208 mInstanceId = sNextInstanceId.getAndIncrement();
Dmitri Plotnikov15406742010-05-07 09:22:49 -0700209 mIntentResolver = new ContactsIntentResolver(this);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700210 mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
Dmitri Plotnikov6178cb42010-04-20 11:26:05 -0700211 }
212
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700213 @Override
214 public String toString() {
215 // Shown on logcat
216 return String.format("%s@%d", getClass().getSimpleName(), mInstanceId);
217 }
218
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700219 private boolean areContactsAvailable() {
Wenyi Wang2f09e602015-10-28 11:34:23 -0700220 return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800221 }
222
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700223 @Override
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700224 protected void onCreate(Bundle savedState) {
Makoto Onuki49627cc2011-08-28 13:56:48 -0700225 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
226 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
227 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700228 super.onCreate(savedState);
Marcus Hagerott396aab72016-12-12 12:00:21 -0800229 mAccountTypeManager = AccountTypeManager.getInstance(this);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800230
Brian Attwellbdd32642015-05-08 17:03:15 -0700231 if (RequestPermissionsActivity.startPermissionActivity(this)) {
232 return;
233 }
234
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700235 if (!processIntent(false)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700236 finish();
237 return;
238 }
Daisuke Miyakawaa012aec2011-10-16 10:24:43 -0700239
Wenyi Wang32912eb2016-09-29 17:17:07 -0700240 mContactListFilterController.addListener(mFilterListener);
241 mProviderStatusWatcher.addListener(mProviderStatusListener);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700242
Makoto Onuki417ca492011-07-14 19:06:35 -0700243 mIsRecreatedInstance = (savedState != null);
Wenyi Wang40e79102016-06-01 20:43:56 -0700244
Wenyi Wang79675452016-08-17 10:43:28 -0700245 if (mIsRecreatedInstance) {
246 mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
247 }
248
Wenyi Wang587b8f22016-08-17 17:40:45 -0700249 createViewsAndFragments();
Andrew Lee4b1af3f2014-04-23 10:23:55 -0700250
Makoto Onuki49627cc2011-08-28 13:56:48 -0700251 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
252 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
253 }
Sai Cheemalapati5b221082014-06-27 14:45:43 -0700254 getWindow().setBackgroundDrawable(null);
Tingting Wangac9596e2016-08-02 22:24:24 -0700255 }
Tingting Wangdce1e682016-07-28 10:06:29 -0700256
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800257 @Override
258 protected void onNewIntent(Intent intent) {
Gary Mai4ac56292016-10-31 10:41:11 -0700259 final String action = intent.getAction();
260 if (GroupUtil.ACTION_CREATE_GROUP.equals(action)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700261 mGroupUri = intent.getData();
262 if (mGroupUri == null) {
263 toast(R.string.groupSavedErrorToast);
264 return;
265 }
266 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
yaolu9b6159c2016-10-24 23:31:49 -0700267 switchView(ContactsView.GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700268 mMembersFragment.toastForSaveAction(action);
Walter Jang13710d52016-07-08 14:36:20 -0700269 return;
270 }
271
Gary Mai4ac56292016-10-31 10:41:11 -0700272 if (isGroupDeleteAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700273 popSecondLevel();
Gary Mai4ac56292016-10-31 10:41:11 -0700274 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700275 mCurrentView = ContactsView.ALL_CONTACTS;
276 showFabWithAnimation(/* showFab */ true);
277 return;
278 }
279
Gary Mai4ac56292016-10-31 10:41:11 -0700280 if (isGroupSaveAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700281 mGroupUri = intent.getData();
282 if (mGroupUri == null) {
283 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700284 toast(R.string.groupSavedErrorToast);
285 return;
286 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700287 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
Gary Mai4ac56292016-10-31 10:41:11 -0700288 // ACTION_REMOVE_FROM_GROUP doesn't reload data, so it shouldn't cause b/32223934
289 // but it's necessary to use the previous fragment since
290 // GroupMembersFragment#mIsEditMode needs to be persisted between remove actions.
291 if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action)) {
292 switchToOrUpdateGroupView(action);
293 } else {
294 switchView(ContactsView.GROUP_VIEW);
295 }
296 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700297 }
298
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800299 setIntent(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700300
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700301 if (!processIntent(true)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700302 finish();
303 return;
304 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700305
Wenyi Wang79675452016-08-17 10:43:28 -0700306 mContactListFilterController.checkFilterValidity(false);
307
308 if (!isInSecondLevel()) {
309 // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
310 // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
311 // initially.
Wenyi Wanged9f9742016-09-08 13:50:39 -0700312 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ true);
Wenyi Wang79675452016-08-17 10:43:28 -0700313 mAllFragment.initializeActionBarAdapter(null);
314 }
Katherine Kuanbe79b8f2011-11-09 20:54:43 -0800315
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700316 initializeFabVisibility();
Makoto Onuki417ca492011-07-14 19:06:35 -0700317 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800318 }
319
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700320 private static boolean isGroupDeleteAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700321 return GroupUtil.ACTION_DELETE_GROUP.equals(action);
322 }
323
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700324 private static boolean isGroupSaveAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700325 return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
326 || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
327 || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
328 }
329
Wenyi Wang79675452016-08-17 10:43:28 -0700330 private void toast(int resId) {
331 if (resId >= 0) {
332 Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
333 }
334 }
335
Makoto Onuki417ca492011-07-14 19:06:35 -0700336 /**
337 * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
338 * is needed.
339 *
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700340 * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}.
Makoto Onuki417ca492011-07-14 19:06:35 -0700341 * @return {@code true} if {@link PeopleActivity} should continue running. {@code false}
342 * if it shouldn't, in which case the caller should finish() itself and shouldn't do
343 * farther initialization.
344 */
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700345 private boolean processIntent(boolean forNewIntent) {
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700346 // Extract relevant information from the intent
347 mRequest = mIntentResolver.resolveIntent(getIntent());
Makoto Onukiea146052011-07-25 10:34:15 -0700348 if (Log.isLoggable(TAG, Log.DEBUG)) {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700349 Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent
350 + " intent=" + getIntent() + " request=" + mRequest);
351 }
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700352 if (!mRequest.isValid()) {
353 setResult(RESULT_CANCELED);
Makoto Onuki417ca492011-07-14 19:06:35 -0700354 return false;
Dmitri Plotnikov59fb48e2010-04-26 17:09:19 -0700355 }
356
Walter Jang1110d672016-07-25 17:55:12 +0000357 switch (mRequest.getActionCode()) {
358 case ContactsRequest.ACTION_VIEW_CONTACT: {
Walter Jang0396cf72016-09-21 13:23:29 -0700359 ImplicitIntentsUtil.startQuickContact(
360 this, mRequest.getContactUri(), ScreenType.UNKNOWN);
Walter Jang1110d672016-07-25 17:55:12 +0000361 return false;
362 }
363 case ContactsRequest.ACTION_INSERT_GROUP: {
364 onCreateGroupMenuItemClicked();
365 return true;
366 }
Wenyi Wang79675452016-08-17 10:43:28 -0700367 case ContactsRequest.ACTION_VIEW_GROUP:
368 case ContactsRequest.ACTION_EDIT_GROUP: {
369 mShouldSwitchToGroupView = true;
370 return true;
371 }
Dmitri Plotnikov27b97bc2010-10-07 18:06:09 -0700372 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700373 return true;
374 }
375
Wenyi Wang587b8f22016-08-17 17:40:45 -0700376 private void createViewsAndFragments() {
Makoto Onuki417ca492011-07-14 19:06:35 -0700377 setContentView(R.layout.people_activity);
378
379 final FragmentManager fragmentManager = getFragmentManager();
380
Wenyi Wang79675452016-08-17 10:43:28 -0700381 setUpAllFragment(fragmentManager);
Makoto Onuki417ca492011-07-14 19:06:35 -0700382
Wenyi Wang17fe7982016-10-05 13:54:09 -0700383 mMembersFragment = (GroupMembersFragment) fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
Makoto Onuki417ca492011-07-14 19:06:35 -0700384
Brian Attwell865847b2015-04-20 14:40:17 -0700385 // Configure floating action button
386 mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
387 final ImageButton floatingActionButton
388 = (ImageButton) findViewById(R.id.floating_action_button);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700389 floatingActionButton.setOnClickListener(new View.OnClickListener() {
390 @Override
391 public void onClick(View v) {
Wenyi Wang79675452016-08-17 10:43:28 -0700392 AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(),
393 mContactListFilterController.getFilter());
Wenyi Wang587b8f22016-08-17 17:40:45 -0700394 }
395 });
Brian Attwell865847b2015-04-20 14:40:17 -0700396 mFloatingActionButtonController = new FloatingActionButtonController(this,
397 mFloatingActionButtonContainer, floatingActionButton);
Paul Soulos2b9563d2014-05-27 16:21:23 -0700398
Makoto Onuki417ca492011-07-14 19:06:35 -0700399 invalidateOptionsMenuIfNeeded();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700400
401 mLayoutRoot = (CoordinatorLayout) findViewById(R.id.root);
402
Wenyi Wang79675452016-08-17 10:43:28 -0700403 if (mShouldSwitchToGroupView && !mIsRecreatedInstance) {
404 mGroupUri = mRequest.getContactUri();
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700405 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700406 mShouldSwitchToGroupView = false;
407 }
408 }
409
410 private void setUpAllFragment(FragmentManager fragmentManager) {
411 mAllFragment = (DefaultContactBrowseListFragment)
412 fragmentManager.findFragmentByTag(TAG_ALL);
413
414 if (mAllFragment == null) {
415 mAllFragment = new DefaultContactBrowseListFragment();
416 mAllFragment.setAnimateOnLoad(true);
417 fragmentManager.beginTransaction()
418 .add(R.id.contacts_list_container, mAllFragment, TAG_ALL)
419 .commit();
420 fragmentManager.executePendingTransactions();
421 }
422
423 mAllFragment.setContactsAvailable(areContactsAvailable());
Wenyi Wangdf3e8492016-09-09 11:10:07 -0700424 mAllFragment.setListType(mContactListFilterController.getFilterListType());
Wenyi Wanged9f9742016-09-08 13:50:39 -0700425 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ false);
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700426 }
427
Dmitri Plotnikov6e850a02010-10-28 10:46:21 -0700428 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700429 protected void onPause() {
Makoto Onukic2bd6132012-04-27 16:14:51 -0700430 mProviderStatusWatcher.stop();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700431
432 LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener);
433
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700434 super.onPause();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700435
Walter Jang9adc9ef2016-11-02 18:50:38 -0700436 ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle);
437 onSyncStateUpdated();
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700438 }
439
440 @Override
Sean Midfordfc4f6922016-10-20 13:55:58 -0700441 public void onMultiWindowModeChanged(boolean entering) {
442 initializeHomeVisibility();
443 }
444
445 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700446 protected void onResume() {
447 super.onResume();
Josh Gargus697ab262012-05-04 11:11:34 -0700448
Wenyi Wang32912eb2016-09-29 17:17:07 -0700449 if (mShouldSwitchToAllContacts) {
450 switchToAllContacts();
451 }
452
Makoto Onukic2bd6132012-04-27 16:14:51 -0700453 mProviderStatusWatcher.start();
Josh Gargus697ab262012-05-04 11:11:34 -0700454 updateViewConfiguration(true);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700455
Walter Jang9adc9ef2016-11-02 18:50:38 -0700456 mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener(
457 ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
458 | ContentResolver.SYNC_OBSERVER_TYPE_PENDING
459 | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
460 mSyncStatusObserver);
461 onSyncStateUpdated();
462
Wenyi Wang587b8f22016-08-17 17:40:45 -0700463 initializeFabVisibility();
Sean Midfordfc4f6922016-10-20 13:55:58 -0700464 initializeHomeVisibility();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700465
466 mSaveServiceListener = new SaveServiceListener();
467 LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
Marcus Hagerott819214d2016-09-29 14:58:27 -0700468 new IntentFilter(ContactSaveService.BROADCAST_GROUP_DELETED));
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700469 }
470
471 @Override
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700472 protected void onDestroy() {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700473 mProviderStatusWatcher.removeListener(mProviderStatusListener);
474 mContactListFilterController.removeListener(mFilterListener);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700475 super.onDestroy();
476 }
477
Brian Attwell865847b2015-04-20 14:40:17 -0700478 private void initializeFabVisibility() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700479 mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE);
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700480 mFloatingActionButtonController.resetIn();
Wenyi Wang587b8f22016-08-17 17:40:45 -0700481 wasLastFabAnimationScaleIn = !shouldHideFab();
Brian Attwell865847b2015-04-20 14:40:17 -0700482 }
483
Sean Midfordfc4f6922016-10-20 13:55:58 -0700484 private void initializeHomeVisibility() {
485 // Remove the navigation icon if we return to the fragment in a search or select state
486 if (getToolbar() != null && (isAllFragmentInSelectionMode()
487 || isAllFragmentInSearchMode() || isGroupsFragmentInSelectionMode()
488 || isGroupsFragmentInSearchMode())) {
489 getToolbar().setNavigationIcon(null);
490 }
491 }
492
Wenyi Wang587b8f22016-08-17 17:40:45 -0700493 private boolean shouldHideFab() {
Wenyi Wang79675452016-08-17 10:43:28 -0700494 if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
495 || isInSecondLevel()) {
496 return true;
497 }
Wenyi Wanged9f9742016-09-08 13:50:39 -0700498 return isAllFragmentInSearchMode() || isAllFragmentInSelectionMode();
Wenyi Wangbf693302016-06-14 12:49:03 -0700499 }
500
Wenyi Wang587b8f22016-08-17 17:40:45 -0700501 public void showFabWithAnimation(boolean showFab) {
Brian Attwell865847b2015-04-20 14:40:17 -0700502 if (mFloatingActionButtonContainer == null) {
503 return;
504 }
505 if (showFab) {
506 if (!wasLastFabAnimationScaleIn) {
507 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
508 mFloatingActionButtonController.scaleIn(0);
509 }
510 wasLastFabAnimationScaleIn = true;
511
512 } else {
513 if (wasLastFabAnimationScaleIn) {
514 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
515 mFloatingActionButtonController.scaleOut();
516 }
517 wasLastFabAnimationScaleIn = false;
518 }
519 }
520
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700521 private void reloadGroupsAndFiltersIfNeeded() {
522 final int providerStatus = mProviderStatusWatcher.getProviderStatus();
523 final Menu menu = mNavigationView.getMenu();
524 final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
525 final SubMenu subMenu = groupsMenuItem.getSubMenu();
526
527 // Reload groups and filters if provider status changes to "normal" and there's no groups
528 // loaded or just a "Create new..." menu item is in the menu.
529 if (subMenu != null && subMenu.size() <= 1 && providerStatus == ProviderStatus.STATUS_NORMAL
530 && !mProviderStatus.equals(providerStatus)) {
531 loadGroupsAndFilters();
532 }
533 }
534
Josh Gargus697ab262012-05-04 11:11:34 -0700535 private void updateViewConfiguration(boolean forceUpdate) {
Brian Attwellc3d202c2015-01-08 15:01:03 -0800536 int providerStatus = mProviderStatusWatcher.getProviderStatus();
Makoto Onukid8fa7162012-05-16 13:45:48 -0700537 if (!forceUpdate && (mProviderStatus != null)
Brian Attwellc3d202c2015-01-08 15:01:03 -0800538 && (mProviderStatus.equals(providerStatus))) return;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800539 mProviderStatus = providerStatus;
540
Wenyi Wang79675452016-08-17 10:43:28 -0700541 final FragmentManager fragmentManager= getFragmentManager();
542 final FragmentTransaction transaction = fragmentManager.beginTransaction();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800543
Wenyi Wangf128ea82016-07-25 11:56:40 -0700544 // Change in CP2's provider status may not take effect immediately, see b/30566908.
545 // So we need to handle the case where provider status is STATUS_EMPTY and there is
546 // actually at least one real account (not "local" account) on device.
Wenyi Wang79675452016-08-17 10:43:28 -0700547 if (shouldShowList()) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700548 if (mAllFragment != null) {
Marcus Hagerott89c51292016-11-08 15:05:38 -0800549 final Fragment unavailableFragment = fragmentManager
550 .findFragmentByTag(TAG_UNAVAILABLE);
551 if (unavailableFragment != null) {
552 transaction.remove(unavailableFragment);
553 }
554 if (mAllFragment.isHidden()) {
555 transaction.show(mAllFragment);
556 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700557 mAllFragment.setContactsAvailable(areContactsAvailable());
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700558 mAllFragment.setEnabled(true);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800559 }
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800560 } else {
guanxiongliu5d7bb262016-01-29 16:43:45 -0800561 // Setting up the page so that the user can still use the app
562 // even without an account.
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700563 if (mAllFragment != null) {
564 mAllFragment.setEnabled(false);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800565 }
Marcus Hagerott89c51292016-11-08 15:05:38 -0800566 final ContactsUnavailableFragment fragment = new ContactsUnavailableFragment();
567 transaction.hide(mAllFragment);
568 transaction.replace(R.id.contacts_unavailable_container, fragment, TAG_UNAVAILABLE);
569 fragment.updateStatus(mProviderStatus);
Wenyi Wang79675452016-08-17 10:43:28 -0700570 }
571 if (!transaction.isEmpty()) {
572 transaction.commit();
573 fragmentManager.executePendingTransactions();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800574 }
575
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700576 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800577 }
578
Wenyi Wang79675452016-08-17 10:43:28 -0700579 private boolean shouldShowList() {
580 return mProviderStatus != null
Marcus Hagerott396aab72016-12-12 12:00:21 -0800581 && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY)
582 && mAccountTypeManager.hasNonLocalAccount())
583 || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
Wenyi Wangf128ea82016-07-25 11:56:40 -0700584 }
585
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700586 private void invalidateOptionsMenuIfNeeded() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700587 if (mAllFragment != null
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700588 && mAllFragment.getOptionsMenuContactsAvailable() != areContactsAvailable()) {
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700589 invalidateOptionsMenu();
Dmitri Plotnikov0cd01302010-12-17 18:41:57 -0800590 }
591 }
592
Dmitri Plotnikov8e86b752010-02-22 17:47:57 -0800593 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800594 public boolean onKeyDown(int keyCode, KeyEvent event) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800595 // Bring up the search UI if the user starts typing
596 final int unicodeChar = event.getUnicodeChar();
597 if ((unicodeChar != 0)
598 // If COMBINING_ACCENT is set, it's not a unicode character.
599 && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
600 && !Character.isWhitespace(unicodeChar)) {
Wenyi Wanged9f9742016-09-08 13:50:39 -0700601 if (mAllFragment.onKeyDown(unicodeChar)) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800602 return true;
Daniel Lehmann7bb2add2010-07-14 21:15:17 -0700603 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800604 }
605
606 return super.onKeyDown(keyCode, event);
607 }
608
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700609 @Override
610 public void onBackPressed() {
Jay Shrauner7712aef2015-09-25 14:14:28 -0700611 if (!isSafeToCommitTransactions()) {
Jay Shraunerc3fdc8f2015-09-16 10:29:52 -0700612 return;
613 }
614
Wenyi Wangf9905062016-09-14 10:07:59 -0700615 // Handle the back event in drawer first.
Wenyi Wangbb229242016-05-25 16:04:13 -0700616 if (mDrawer.isDrawerOpen(GravityCompat.START)) {
617 mDrawer.closeDrawer(GravityCompat.START);
Wenyi Wang51819e82016-09-12 11:57:51 -0700618 return;
Wenyi Wangf9905062016-09-14 10:07:59 -0700619 }
620
621 // Handle the back event in "second level".
622 if (isGroupView()) {
623 onBackPressedGroupView();
624 return;
625 }
626
John Shao52dd5d72016-10-06 15:16:14 -0700627 if (isAssistantView()) {
628 onBackPressedAssistantView();
Wenyi Wangf9905062016-09-14 10:07:59 -0700629 return;
630 }
631
632 // If feature highlight is present, let it handle the back event before mAllFragment.
633 if (FeatureHighlightHelper.tryRemoveHighlight(this)) {
634 return;
635 }
636
637 // Handle the back event in "first level" - mAllFragment.
638 if (maybeHandleInAllFragment()) {
639 return;
640 }
641
642 super.onBackPressed();
643 }
644
645 private void onBackPressedGroupView() {
646 if (mMembersFragment.isEditMode()) {
647 mMembersFragment.exitEditMode();
648 } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
649 mMembersFragment.getActionBarAdapter().setSelectionMode(false);
650 mMembersFragment.displayCheckBoxes(false);
651 } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
652 mMembersFragment.getActionBarAdapter().setSearchMode(false);
653 } else {
654 switchToAllContacts();
655 }
656 }
657
John Shao52dd5d72016-10-06 15:16:14 -0700658 private void onBackPressedAssistantView() {
659 if (!popThirdLevel()) {
660 switchToAllContacts();
661 } else {
662 setDrawerLockMode(/* enabled */ true);
663 }
664 }
665
Wenyi Wangf9905062016-09-14 10:07:59 -0700666 // Returns true if back event is handled in this method.
667 private boolean maybeHandleInAllFragment() {
668 if (isAllFragmentInSelectionMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700669 mAllFragment.getActionBarAdapter().setSelectionMode(false);
Wenyi Wangf9905062016-09-14 10:07:59 -0700670 return true;
671 }
672
673 if (isAllFragmentInSearchMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700674 mAllFragment.getActionBarAdapter().setSearchMode(false);
Walter Janga84fe612016-01-13 16:49:04 -0800675 if (mAllFragment.wasSearchResultClicked()) {
676 mAllFragment.resetSearchResultClicked();
677 } else {
Walter Jang62a20742016-02-24 17:04:12 -0800678 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
Walter Jang82c90332016-02-24 17:34:34 -0800679 Logger.logSearchEvent(mAllFragment.createSearchState());
Walter Janga84fe612016-01-13 16:49:04 -0800680 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700681 return true;
682 }
683
Wenyi Wang32912eb2016-09-29 17:17:07 -0700684 if (!AccountFilterUtil.isAllContactsFilter(mContactListFilterController.getFilter())
Wenyi Wang79675452016-08-17 10:43:28 -0700685 && !mAllFragment.isHidden()) {
686 // If mAllFragment is hidden, then mContactsUnavailableFragment is visible so we
687 // don't need to switch to all contacts.
Wenyi Wang40e79102016-06-01 20:43:56 -0700688 switchToAllContacts();
Wenyi Wangf9905062016-09-14 10:07:59 -0700689 return true;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700690 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700691
692 return false;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700693 }
694
Wenyi Wanged9f9742016-09-08 13:50:39 -0700695 private boolean isAllFragmentInSelectionMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700696 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700697 && mAllFragment.getActionBarAdapter().isSelectionMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700698 }
699
700 private boolean isAllFragmentInSearchMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700701 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700702 && mAllFragment.getActionBarAdapter().isSearchMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700703 }
704
Sean Midfordfc4f6922016-10-20 13:55:58 -0700705 private boolean isGroupsFragmentInSelectionMode() {
706 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
707 && mMembersFragment.getActionBarAdapter().isSelectionMode();
708 }
709
710 private boolean isGroupsFragmentInSearchMode() {
711 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
712 && mMembersFragment.getActionBarAdapter().isSearchMode();
713 }
714
Wenyi Wang79675452016-08-17 10:43:28 -0700715 @Override
716 protected void onSaveInstanceState(Bundle outState) {
717 super.onSaveInstanceState(outState);
718 outState.putParcelable(KEY_GROUP_URI, mGroupUri);
Tingting Wang2dc340c2016-07-05 22:31:58 -0700719 }
720
Wenyi Wangbb229242016-05-25 16:04:13 -0700721 @Override
Wenyi Wang79675452016-08-17 10:43:28 -0700722 protected void onRestoreInstanceState(Bundle savedInstanceState) {
723 super.onRestoreInstanceState(savedInstanceState);
724 mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI);
Tingting Wang1243cb42016-08-05 16:42:21 -0700725 }
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700726
Gary Mai4ac56292016-10-31 10:41:11 -0700727 private void onGroupDeleted(final Intent intent) {
Marcus Hagerott3c1153f2016-09-07 09:15:14 -0700728 if (!ContactSaveService.canUndo(intent)) return;
729
James Laskey6b712bc2016-11-22 11:02:09 -0800730 final AccessibilityManager am =
731 (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
James Laskey692c9612016-11-30 10:13:01 -0800732 //TODO set to INDEFINITE and track user interaction to dismiss b/33208886
733 final int accessibilityLength = 15000;
734 final int length = am.isEnabled() ? accessibilityLength : Snackbar.LENGTH_LONG;
James Laskey6b712bc2016-11-22 11:02:09 -0800735 final String message = getString(R.string.groupDeletedToast);
736
737 final Snackbar snackbar = Snackbar.make(mLayoutRoot, message, length)
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700738 .setAction(R.string.undo, new View.OnClickListener() {
739 @Override
740 public void onClick(View v) {
741 ContactSaveService.startService(PeopleActivity.this,
742 ContactSaveService.createUndoIntent(PeopleActivity.this, intent));
743 }
James Laskey6b712bc2016-11-22 11:02:09 -0800744 }).setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_action_text));
745
746 // Announce for a11y talkback
747 mLayoutRoot.announceForAccessibility(message);
748 mLayoutRoot.announceForAccessibility(getString(R.string.undo));
749
750 snackbar.show();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700751 }
752
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700753 private class SaveServiceListener extends BroadcastReceiver {
754 @Override
755 public void onReceive(Context context, Intent intent) {
756 switch (intent.getAction()) {
Marcus Hagerott819214d2016-09-29 14:58:27 -0700757 case ContactSaveService.BROADCAST_GROUP_DELETED:
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700758 onGroupDeleted(intent);
759 break;
760 }
761 }
762 }
Wenyi Wang79675452016-08-17 10:43:28 -0700763
764 @Override
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700765 protected void onGroupMenuItemClicked(long groupId, String title) {
Wenyi Wang79675452016-08-17 10:43:28 -0700766 if (isGroupView() && mMembersFragment != null
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700767 && mMembersFragment.isCurrentGroup(groupId)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700768 return;
769 }
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700770 mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700771 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700772 }
773
774 @Override
775 protected void onFilterMenuItemClicked(Intent intent) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700776 // We must pop second level first to "restart" mAllFragment, before changing filter.
Wenyi Wang79675452016-08-17 10:43:28 -0700777 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700778 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700779 showFabWithAnimation(/* showFab */ true);
Marcus Hagerott45451ea2016-10-25 20:05:26 -0700780 // HACK: swap the current filter to force listeners to update because the group
781 // member view no longer changes the filter. Fix for b/32223767
782 final ContactListFilter current = mContactListFilterController.getFilter();
783 mContactListFilterController.setContactListFilter(
784 AccountFilterUtil.createContactsFilter(this), false);
785 mContactListFilterController.setContactListFilter(current, false);
Wenyi Wang79675452016-08-17 10:43:28 -0700786 }
787 mCurrentView = ContactsView.ACCOUNT_VIEW;
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700788 super.onFilterMenuItemClicked(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700789 }
790
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700791 private void switchToOrUpdateGroupView(String action) {
Wenyi Wang17fe7982016-10-05 13:54:09 -0700792 // If group fragment is active and visible, we simply update it.
793 if (mMembersFragment != null && !mMembersFragment.isInactive()) {
Wenyi Wangf6606072016-10-03 17:34:53 -0700794 mMembersFragment.updateExistingGroupFragment(mGroupUri, action);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700795 } else {
796 switchView(ContactsView.GROUP_VIEW);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700797 }
Wenyi Wang79675452016-08-17 10:43:28 -0700798 }
799
800 @Override
John Shao52dd5d72016-10-06 15:16:14 -0700801 protected void launchAssistant() {
802 switchView(ContactsView.ASSISTANT);
Wenyi Wang79675452016-08-17 10:43:28 -0700803 }
804
805 private void switchView(ContactsView contactsView) {
Wenyi Wang79675452016-08-17 10:43:28 -0700806 mCurrentView = contactsView;
Wenyi Wang79675452016-08-17 10:43:28 -0700807
Wenyi Wang79675452016-08-17 10:43:28 -0700808 final FragmentManager fragmentManager = getFragmentManager();
809 final FragmentTransaction transaction = fragmentManager.beginTransaction();
810 if (isGroupView()) {
yaolu4c075092016-10-19 22:23:00 -0700811 mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700812 transaction.replace(
813 R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700814 } else if (isAssistantView()) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800815 Fragment uiFragment = fragmentManager.findFragmentByTag(TAG_ASSISTANT);
Sean Midfordb96df942016-11-11 17:54:49 -0800816 Fragment unavailableFragment = fragmentManager.findFragmentByTag(TAG_UNAVAILABLE);
John Shaoa3ce3c72016-10-11 14:58:57 -0700817 if (uiFragment == null) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800818 uiFragment = ObjectFactory.getAssistantFragment();
John Shaoa3ce3c72016-10-11 14:58:57 -0700819 }
Sean Midfordb96df942016-11-11 17:54:49 -0800820 if (unavailableFragment != null) {
821 transaction.remove(unavailableFragment);
822 }
John Shao5b1ffdc2016-11-08 13:51:00 -0800823 transaction.replace(R.id.contacts_list_container, uiFragment, TAG_ASSISTANT);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700824 resetToolBarStatusBarColor();
Wenyi Wang79675452016-08-17 10:43:28 -0700825 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700826 transaction.addToBackStack(TAG_SECOND_LEVEL);
Wenyi Wang79675452016-08-17 10:43:28 -0700827 transaction.commit();
828 fragmentManager.executePendingTransactions();
829
830 showFabWithAnimation(/* showFab */ false);
831 }
832
833 @Override
834 public void switchToAllContacts() {
Wenyi Wang79675452016-08-17 10:43:28 -0700835 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700836 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700837 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700838 mShouldSwitchToAllContacts = false;
Wenyi Wang79675452016-08-17 10:43:28 -0700839 mCurrentView = ContactsView.ALL_CONTACTS;
840 showFabWithAnimation(/* showFab */ true);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700841 mAllFragment.scrollToTop();
Wenyi Wang79675452016-08-17 10:43:28 -0700842
843 super.switchToAllContacts();
844 }
845
John Shao52dd5d72016-10-06 15:16:14 -0700846 private boolean popThirdLevel() {
847 return getFragmentManager().popBackStackImmediate(
848 TAG_THIRD_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
849 }
850
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700851 private void popSecondLevel() {
852 getFragmentManager().popBackStackImmediate(
853 TAG_SECOND_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
854 mMembersFragment = null;
Wenyi Wang92d7e512016-10-03 14:57:19 -0700855 resetToolBarStatusBarColor();
856 }
857
858 // Reset toolbar and status bar color to Contacts theme color.
859 private void resetToolBarStatusBarColor() {
860 findViewById(R.id.toolbar_frame).setBackgroundColor(
861 ContextCompat.getColor(this, R.color.primary_color));
862 updateStatusBarBackground(ContextCompat.getColor(this, R.color.primary_color_dark));
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700863 }
864
Wenyi Wang79675452016-08-17 10:43:28 -0700865 @Override
866 protected DefaultContactBrowseListFragment getAllFragment() {
867 return mAllFragment;
868 }
869
870 @Override
871 protected GroupMembersFragment getGroupFragment() {
872 return mMembersFragment;
873 }
874
875 @Override
Walter Jang5a496962016-09-09 18:32:50 -0700876 protected GroupMetaData getGroupMetaData() {
877 return mMembersFragment == null ? null : mMembersFragment.getGroupMetaData();
Wenyi Wang79675452016-08-17 10:43:28 -0700878 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700879
880 private void handleFilterChangeForFragment(ContactListFilter filter) {
James Laskey1842bb22016-10-20 14:38:04 -0700881 if (mAllFragment.canSetActionBar()) {
882 mAllFragment.setFilterAndUpdateTitle(filter);
883 // Scroll to top after filter is changed.
884 mAllFragment.scrollToTop();
885 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700886 }
887
888 private void handleFilterChangeForActivity(ContactListFilter filter) {
Marcus Hagerott74295d32016-10-26 10:46:28 -0700889 // The filter was changed while this activity was in the background. If we're in the
890 // assistant view Switch to the main contacts list when we resume to prevent
891 // b/31838582 and b/31829161
892 // TODO: this is a hack; we need to do some cleanup of the contact list filter stuff
893 if (isAssistantView() && filter.isContactsFilterType()) {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700894 mShouldSwitchToAllContacts = true;
895 }
896
Wenyi Wangcfe94652016-10-03 21:05:04 -0700897 // Check menu in navigation drawer.
Wenyi Wang32912eb2016-09-29 17:17:07 -0700898 updateFilterMenu(filter);
899
900 if (CompatUtils.isNCompatible()) {
901 getWindow().getDecorView()
902 .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
903 }
904 invalidateOptionsMenu();
905 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800906}