blob: 28891e55646abed6742b468a0fb1a7e8744976e6 [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 Hagerott75895e72016-12-12 17:21:57 -080071import com.android.contacts.model.account.AccountInfo;
Marcus Hagerott396aab72016-12-12 12:00:21 -080072import com.android.contacts.model.account.AccountType;
Gary Mai69c182a2016-12-05 13:07:03 -080073import com.android.contacts.model.account.AccountWithDataSet;
74import com.android.contacts.util.AccountFilterUtil;
75import com.android.contacts.util.Constants;
76import com.android.contacts.util.ImplicitIntentsUtil;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070077import com.android.contacts.util.SyncUtil;
Gary Mai0a49afa2016-12-05 15:53:58 -080078import com.android.contacts.widget.FloatingActionButtonController;
Wenyi Wangf9905062016-09-14 10:07:59 -070079import com.android.contactsbind.FeatureHighlightHelper;
Wenyi Wang79675452016-08-17 10:43:28 -070080import com.android.contactsbind.ObjectFactory;
Tadashi G. Takaoka57cf30f2009-09-21 19:54:39 +090081
Marcus Hagerott396aab72016-12-12 12:00:21 -080082import java.util.Collections;
Brian Attwell20510ec2015-02-27 16:10:45 -080083import java.util.List;
Makoto Onuki6d9befe2011-07-17 11:00:12 -070084import java.util.concurrent.atomic.AtomicInteger;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070085
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080086/**
Brian Attwell2c1bfd02014-06-04 18:18:35 -070087 * Displays a list to browse contacts.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080088 */
Wenyi Wang32912eb2016-09-29 17:17:07 -070089public class PeopleActivity extends ContactsDrawerActivity {
Dmitri Plotnikov57d27da2009-09-28 18:06:11 -070090
Dave Santoro5e684a42011-06-10 13:23:35 -070091 private static final String TAG = "PeopleActivity";
Wenyi Wangca6018d2016-08-18 17:23:13 -070092 private static final String TAG_ALL = "contacts-all";
Wenyi Wang79675452016-08-17 10:43:28 -070093 private static final String TAG_UNAVAILABLE = "contacts-unavailable";
Wenyi Wangcc8f2722016-09-07 14:52:32 -070094 private static final String TAG_GROUP_VIEW = "contacts-groups";
John Shao52dd5d72016-10-06 15:16:14 -070095 public static final String TAG_ASSISTANT = "contacts-assistant";
96 public static final String TAG_SECOND_LEVEL = "second-level";
97 public static final String TAG_THIRD_LEVEL = "third-level";
98
99 public static final String TAG_DUPLICATES = "DuplicatesFragment";
Wenyi Wang79675452016-08-17 10:43:28 -0700100 public static final String TAG_DUPLICATES_UTIL = "DuplicatesUtilFragment";
101
102 private static final String KEY_GROUP_URI = "groupUri";
Wenyi Wangca6018d2016-08-18 17:23:13 -0700103
Dmitri Plotnikovac0f7832010-04-22 13:26:52 -0700104 private ContactsIntentResolver mIntentResolver;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700105 private ContactsRequest mRequest;
Marcus Hagerott396aab72016-12-12 12:00:21 -0800106 private AccountTypeManager mAccountTypeManager;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700107
Brian Attwell865847b2015-04-20 14:40:17 -0700108 private FloatingActionButtonController mFloatingActionButtonController;
109 private View mFloatingActionButtonContainer;
110 private boolean wasLastFabAnimationScaleIn = false;
Dmitri Plotnikovfcfdffb2010-07-15 18:00:55 -0700111
Makoto Onukic2bd6132012-04-27 16:14:51 -0700112 private ProviderStatusWatcher mProviderStatusWatcher;
Brian Attwellc3d202c2015-01-08 15:01:03 -0800113 private Integer mProviderStatus;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800114
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700115 private BroadcastReceiver mSaveServiceListener;
116
Wenyi Wang79675452016-08-17 10:43:28 -0700117 private boolean mShouldSwitchToGroupView;
118
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700119 private CoordinatorLayout mLayoutRoot;
120
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700121 /**
122 * Showing a list of Contacts. Also used for showing search results in search mode.
123 */
Walter Jange9ea4f02016-05-10 09:39:46 -0700124 private DefaultContactBrowseListFragment mAllFragment;
Katherine Kuanb5760b92011-06-01 16:19:40 -0700125
Wenyi Wang79675452016-08-17 10:43:28 -0700126 private GroupMembersFragment mMembersFragment;
127 private Uri mGroupUri;
Katherine Kuan58fc5772011-07-04 10:08:32 -0700128
Makoto Onuki417ca492011-07-14 19:06:35 -0700129 /**
130 * True if this activity instance is a re-created one. i.e. set true after orientation change.
Makoto Onuki417ca492011-07-14 19:06:35 -0700131 */
132 private boolean mIsRecreatedInstance;
133
Wenyi Wang32912eb2016-09-29 17:17:07 -0700134 private boolean mShouldSwitchToAllContacts;
135
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700136 /** Sequential ID assigned to each instance; used for logging */
137 private final int mInstanceId;
138 private static final AtomicInteger sNextInstanceId = new AtomicInteger();
139
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700140 private Object mStatusChangeListenerHandle;
141
142 private final Handler mHandler = new Handler();
143
144 private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
145 public void onStatusChanged(int which) {
146 mHandler.post(new Runnable() {
147 public void run() {
148 onSyncStateUpdated();
149 }
150 });
151 }
152 };
153
154 // Update sync status for accounts in current ContactListFilter
155 private void onSyncStateUpdated() {
Wenyi Wanged9f9742016-09-08 13:50:39 -0700156 if (isAllFragmentInSearchMode() || isAllFragmentInSelectionMode()) {
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700157 return;
158 }
159
Wenyi Wang32912eb2016-09-29 17:17:07 -0700160 final ContactListFilter filter = mContactListFilterController.getFilter();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700161 if (filter != null) {
162 final SwipeRefreshLayout swipeRefreshLayout = mAllFragment.getSwipeRefreshLayout();
163 if (swipeRefreshLayout == null) {
164 if (Log.isLoggable(TAG, Log.DEBUG)) {
165 Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null");
166 }
167 return;
168 }
169
Marcus Hagerott396aab72016-12-12 12:00:21 -0800170 final List<AccountWithDataSet> accounts;
171 if (filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT &&
172 filter.isGoogleAccountType()) {
173 accounts = Collections.singletonList(new AccountWithDataSet(filter.accountName,
174 filter.accountType, null));
175 } else if (filter.shouldShowSyncState()) {
Marcus Hagerott75895e72016-12-12 17:21:57 -0800176 accounts = AccountInfo.extractAccounts(
177 mAccountTypeManager.getWritableGoogleAccounts());
Marcus Hagerott396aab72016-12-12 12:00:21 -0800178 } else {
179 accounts = Collections.emptyList();
180 }
181 if (SyncUtil.isAnySyncing(accounts)) {
182 return;
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700183 }
184 swipeRefreshLayout.setRefreshing(false);
185 }
186 }
187
yaolu395c3f82016-10-18 11:13:39 -0700188 public void showConnectionErrorMsg() {
189 Snackbar.make(mLayoutRoot, R.string.connection_error_message, Snackbar.LENGTH_LONG).show();
190 }
191
Wenyi Wang32912eb2016-09-29 17:17:07 -0700192 private final ContactListFilterListener mFilterListener = new ContactListFilterListener() {
193 @Override
194 public void onContactListFilterChanged() {
195 final ContactListFilter filter = mContactListFilterController.getFilter();
196 handleFilterChangeForFragment(filter);
197 handleFilterChangeForActivity(filter);
198 }
199 };
200
201 private final ProviderStatusListener mProviderStatusListener = new ProviderStatusListener() {
202 @Override
203 public void onProviderStatusChange() {
204 reloadGroupsAndFiltersIfNeeded();
205 updateViewConfiguration(false);
206 }
207 };
208
Katherine Kuan9856fce2011-06-01 10:24:09 -0700209 public PeopleActivity() {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700210 mInstanceId = sNextInstanceId.getAndIncrement();
Dmitri Plotnikov15406742010-05-07 09:22:49 -0700211 mIntentResolver = new ContactsIntentResolver(this);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700212 mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
Dmitri Plotnikov6178cb42010-04-20 11:26:05 -0700213 }
214
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700215 @Override
216 public String toString() {
217 // Shown on logcat
218 return String.format("%s@%d", getClass().getSimpleName(), mInstanceId);
219 }
220
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700221 private boolean areContactsAvailable() {
Wenyi Wang2f09e602015-10-28 11:34:23 -0700222 return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800223 }
224
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700225 @Override
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700226 protected void onCreate(Bundle savedState) {
Makoto Onuki49627cc2011-08-28 13:56:48 -0700227 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
228 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
229 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700230 super.onCreate(savedState);
Marcus Hagerott396aab72016-12-12 12:00:21 -0800231 mAccountTypeManager = AccountTypeManager.getInstance(this);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800232
Brian Attwellbdd32642015-05-08 17:03:15 -0700233 if (RequestPermissionsActivity.startPermissionActivity(this)) {
234 return;
235 }
236
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700237 if (!processIntent(false)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700238 finish();
239 return;
240 }
Daisuke Miyakawaa012aec2011-10-16 10:24:43 -0700241
Wenyi Wang32912eb2016-09-29 17:17:07 -0700242 mContactListFilterController.addListener(mFilterListener);
243 mProviderStatusWatcher.addListener(mProviderStatusListener);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700244
Makoto Onuki417ca492011-07-14 19:06:35 -0700245 mIsRecreatedInstance = (savedState != null);
Wenyi Wang40e79102016-06-01 20:43:56 -0700246
Wenyi Wang79675452016-08-17 10:43:28 -0700247 if (mIsRecreatedInstance) {
248 mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
249 }
250
Wenyi Wang587b8f22016-08-17 17:40:45 -0700251 createViewsAndFragments();
Andrew Lee4b1af3f2014-04-23 10:23:55 -0700252
Makoto Onuki49627cc2011-08-28 13:56:48 -0700253 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
254 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
255 }
Sai Cheemalapati5b221082014-06-27 14:45:43 -0700256 getWindow().setBackgroundDrawable(null);
Tingting Wangac9596e2016-08-02 22:24:24 -0700257 }
Tingting Wangdce1e682016-07-28 10:06:29 -0700258
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800259 @Override
260 protected void onNewIntent(Intent intent) {
Gary Mai4ac56292016-10-31 10:41:11 -0700261 final String action = intent.getAction();
262 if (GroupUtil.ACTION_CREATE_GROUP.equals(action)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700263 mGroupUri = intent.getData();
264 if (mGroupUri == null) {
265 toast(R.string.groupSavedErrorToast);
266 return;
267 }
268 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
yaolu9b6159c2016-10-24 23:31:49 -0700269 switchView(ContactsView.GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700270 mMembersFragment.toastForSaveAction(action);
Walter Jang13710d52016-07-08 14:36:20 -0700271 return;
272 }
273
Gary Mai4ac56292016-10-31 10:41:11 -0700274 if (isGroupDeleteAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700275 popSecondLevel();
Gary Mai4ac56292016-10-31 10:41:11 -0700276 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700277 mCurrentView = ContactsView.ALL_CONTACTS;
278 showFabWithAnimation(/* showFab */ true);
279 return;
280 }
281
Gary Mai4ac56292016-10-31 10:41:11 -0700282 if (isGroupSaveAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700283 mGroupUri = intent.getData();
284 if (mGroupUri == null) {
285 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700286 toast(R.string.groupSavedErrorToast);
287 return;
288 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700289 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
Gary Mai4ac56292016-10-31 10:41:11 -0700290 // ACTION_REMOVE_FROM_GROUP doesn't reload data, so it shouldn't cause b/32223934
291 // but it's necessary to use the previous fragment since
292 // GroupMembersFragment#mIsEditMode needs to be persisted between remove actions.
293 if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action)) {
294 switchToOrUpdateGroupView(action);
295 } else {
296 switchView(ContactsView.GROUP_VIEW);
297 }
298 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700299 }
300
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800301 setIntent(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700302
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700303 if (!processIntent(true)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700304 finish();
305 return;
306 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700307
Wenyi Wang79675452016-08-17 10:43:28 -0700308 mContactListFilterController.checkFilterValidity(false);
309
310 if (!isInSecondLevel()) {
311 // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
312 // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
313 // initially.
Wenyi Wanged9f9742016-09-08 13:50:39 -0700314 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ true);
Wenyi Wang79675452016-08-17 10:43:28 -0700315 mAllFragment.initializeActionBarAdapter(null);
316 }
Katherine Kuanbe79b8f2011-11-09 20:54:43 -0800317
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700318 initializeFabVisibility();
Makoto Onuki417ca492011-07-14 19:06:35 -0700319 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800320 }
321
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700322 private static boolean isGroupDeleteAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700323 return GroupUtil.ACTION_DELETE_GROUP.equals(action);
324 }
325
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700326 private static boolean isGroupSaveAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700327 return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
328 || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
329 || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
330 }
331
Wenyi Wang79675452016-08-17 10:43:28 -0700332 private void toast(int resId) {
333 if (resId >= 0) {
334 Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
335 }
336 }
337
Makoto Onuki417ca492011-07-14 19:06:35 -0700338 /**
339 * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
340 * is needed.
341 *
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700342 * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}.
Makoto Onuki417ca492011-07-14 19:06:35 -0700343 * @return {@code true} if {@link PeopleActivity} should continue running. {@code false}
344 * if it shouldn't, in which case the caller should finish() itself and shouldn't do
345 * farther initialization.
346 */
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700347 private boolean processIntent(boolean forNewIntent) {
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700348 // Extract relevant information from the intent
349 mRequest = mIntentResolver.resolveIntent(getIntent());
Makoto Onukiea146052011-07-25 10:34:15 -0700350 if (Log.isLoggable(TAG, Log.DEBUG)) {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700351 Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent
352 + " intent=" + getIntent() + " request=" + mRequest);
353 }
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700354 if (!mRequest.isValid()) {
355 setResult(RESULT_CANCELED);
Makoto Onuki417ca492011-07-14 19:06:35 -0700356 return false;
Dmitri Plotnikov59fb48e2010-04-26 17:09:19 -0700357 }
358
Walter Jang1110d672016-07-25 17:55:12 +0000359 switch (mRequest.getActionCode()) {
360 case ContactsRequest.ACTION_VIEW_CONTACT: {
Walter Jang0396cf72016-09-21 13:23:29 -0700361 ImplicitIntentsUtil.startQuickContact(
362 this, mRequest.getContactUri(), ScreenType.UNKNOWN);
Walter Jang1110d672016-07-25 17:55:12 +0000363 return false;
364 }
365 case ContactsRequest.ACTION_INSERT_GROUP: {
366 onCreateGroupMenuItemClicked();
367 return true;
368 }
Wenyi Wang79675452016-08-17 10:43:28 -0700369 case ContactsRequest.ACTION_VIEW_GROUP:
370 case ContactsRequest.ACTION_EDIT_GROUP: {
371 mShouldSwitchToGroupView = true;
372 return true;
373 }
Dmitri Plotnikov27b97bc2010-10-07 18:06:09 -0700374 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700375 return true;
376 }
377
Wenyi Wang587b8f22016-08-17 17:40:45 -0700378 private void createViewsAndFragments() {
Makoto Onuki417ca492011-07-14 19:06:35 -0700379 setContentView(R.layout.people_activity);
380
381 final FragmentManager fragmentManager = getFragmentManager();
382
Wenyi Wang79675452016-08-17 10:43:28 -0700383 setUpAllFragment(fragmentManager);
Makoto Onuki417ca492011-07-14 19:06:35 -0700384
Wenyi Wang17fe7982016-10-05 13:54:09 -0700385 mMembersFragment = (GroupMembersFragment) fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
Makoto Onuki417ca492011-07-14 19:06:35 -0700386
Brian Attwell865847b2015-04-20 14:40:17 -0700387 // Configure floating action button
388 mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
389 final ImageButton floatingActionButton
390 = (ImageButton) findViewById(R.id.floating_action_button);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700391 floatingActionButton.setOnClickListener(new View.OnClickListener() {
392 @Override
393 public void onClick(View v) {
Wenyi Wang79675452016-08-17 10:43:28 -0700394 AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(),
395 mContactListFilterController.getFilter());
Wenyi Wang587b8f22016-08-17 17:40:45 -0700396 }
397 });
Brian Attwell865847b2015-04-20 14:40:17 -0700398 mFloatingActionButtonController = new FloatingActionButtonController(this,
399 mFloatingActionButtonContainer, floatingActionButton);
Paul Soulos2b9563d2014-05-27 16:21:23 -0700400
Makoto Onuki417ca492011-07-14 19:06:35 -0700401 invalidateOptionsMenuIfNeeded();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700402
403 mLayoutRoot = (CoordinatorLayout) findViewById(R.id.root);
404
Wenyi Wang79675452016-08-17 10:43:28 -0700405 if (mShouldSwitchToGroupView && !mIsRecreatedInstance) {
406 mGroupUri = mRequest.getContactUri();
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700407 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700408 mShouldSwitchToGroupView = false;
409 }
410 }
411
412 private void setUpAllFragment(FragmentManager fragmentManager) {
413 mAllFragment = (DefaultContactBrowseListFragment)
414 fragmentManager.findFragmentByTag(TAG_ALL);
415
416 if (mAllFragment == null) {
417 mAllFragment = new DefaultContactBrowseListFragment();
418 mAllFragment.setAnimateOnLoad(true);
419 fragmentManager.beginTransaction()
420 .add(R.id.contacts_list_container, mAllFragment, TAG_ALL)
421 .commit();
422 fragmentManager.executePendingTransactions();
423 }
424
425 mAllFragment.setContactsAvailable(areContactsAvailable());
Wenyi Wangdf3e8492016-09-09 11:10:07 -0700426 mAllFragment.setListType(mContactListFilterController.getFilterListType());
Wenyi Wanged9f9742016-09-08 13:50:39 -0700427 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ false);
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700428 }
429
Dmitri Plotnikov6e850a02010-10-28 10:46:21 -0700430 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700431 protected void onPause() {
Makoto Onukic2bd6132012-04-27 16:14:51 -0700432 mProviderStatusWatcher.stop();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700433
434 LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener);
435
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700436 super.onPause();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700437
Walter Jang9adc9ef2016-11-02 18:50:38 -0700438 ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle);
439 onSyncStateUpdated();
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700440 }
441
442 @Override
Sean Midfordfc4f6922016-10-20 13:55:58 -0700443 public void onMultiWindowModeChanged(boolean entering) {
444 initializeHomeVisibility();
445 }
446
447 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700448 protected void onResume() {
449 super.onResume();
Josh Gargus697ab262012-05-04 11:11:34 -0700450
Wenyi Wang32912eb2016-09-29 17:17:07 -0700451 if (mShouldSwitchToAllContacts) {
452 switchToAllContacts();
453 }
454
Makoto Onukic2bd6132012-04-27 16:14:51 -0700455 mProviderStatusWatcher.start();
Josh Gargus697ab262012-05-04 11:11:34 -0700456 updateViewConfiguration(true);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700457
Walter Jang9adc9ef2016-11-02 18:50:38 -0700458 mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener(
459 ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
460 | ContentResolver.SYNC_OBSERVER_TYPE_PENDING
461 | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
462 mSyncStatusObserver);
463 onSyncStateUpdated();
464
Wenyi Wang587b8f22016-08-17 17:40:45 -0700465 initializeFabVisibility();
Sean Midfordfc4f6922016-10-20 13:55:58 -0700466 initializeHomeVisibility();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700467
468 mSaveServiceListener = new SaveServiceListener();
469 LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
Marcus Hagerott819214d2016-09-29 14:58:27 -0700470 new IntentFilter(ContactSaveService.BROADCAST_GROUP_DELETED));
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700471 }
472
473 @Override
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700474 protected void onDestroy() {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700475 mProviderStatusWatcher.removeListener(mProviderStatusListener);
476 mContactListFilterController.removeListener(mFilterListener);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700477 super.onDestroy();
478 }
479
Brian Attwell865847b2015-04-20 14:40:17 -0700480 private void initializeFabVisibility() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700481 mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE);
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700482 mFloatingActionButtonController.resetIn();
Wenyi Wang587b8f22016-08-17 17:40:45 -0700483 wasLastFabAnimationScaleIn = !shouldHideFab();
Brian Attwell865847b2015-04-20 14:40:17 -0700484 }
485
Sean Midfordfc4f6922016-10-20 13:55:58 -0700486 private void initializeHomeVisibility() {
487 // Remove the navigation icon if we return to the fragment in a search or select state
488 if (getToolbar() != null && (isAllFragmentInSelectionMode()
489 || isAllFragmentInSearchMode() || isGroupsFragmentInSelectionMode()
490 || isGroupsFragmentInSearchMode())) {
491 getToolbar().setNavigationIcon(null);
492 }
493 }
494
Wenyi Wang587b8f22016-08-17 17:40:45 -0700495 private boolean shouldHideFab() {
Wenyi Wang79675452016-08-17 10:43:28 -0700496 if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
497 || isInSecondLevel()) {
498 return true;
499 }
Wenyi Wanged9f9742016-09-08 13:50:39 -0700500 return isAllFragmentInSearchMode() || isAllFragmentInSelectionMode();
Wenyi Wangbf693302016-06-14 12:49:03 -0700501 }
502
Wenyi Wang587b8f22016-08-17 17:40:45 -0700503 public void showFabWithAnimation(boolean showFab) {
Brian Attwell865847b2015-04-20 14:40:17 -0700504 if (mFloatingActionButtonContainer == null) {
505 return;
506 }
507 if (showFab) {
508 if (!wasLastFabAnimationScaleIn) {
509 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
510 mFloatingActionButtonController.scaleIn(0);
511 }
512 wasLastFabAnimationScaleIn = true;
513
514 } else {
515 if (wasLastFabAnimationScaleIn) {
516 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
517 mFloatingActionButtonController.scaleOut();
518 }
519 wasLastFabAnimationScaleIn = false;
520 }
521 }
522
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700523 private void reloadGroupsAndFiltersIfNeeded() {
524 final int providerStatus = mProviderStatusWatcher.getProviderStatus();
525 final Menu menu = mNavigationView.getMenu();
526 final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
527 final SubMenu subMenu = groupsMenuItem.getSubMenu();
528
529 // Reload groups and filters if provider status changes to "normal" and there's no groups
530 // loaded or just a "Create new..." menu item is in the menu.
531 if (subMenu != null && subMenu.size() <= 1 && providerStatus == ProviderStatus.STATUS_NORMAL
532 && !mProviderStatus.equals(providerStatus)) {
533 loadGroupsAndFilters();
534 }
535 }
536
Josh Gargus697ab262012-05-04 11:11:34 -0700537 private void updateViewConfiguration(boolean forceUpdate) {
Brian Attwellc3d202c2015-01-08 15:01:03 -0800538 int providerStatus = mProviderStatusWatcher.getProviderStatus();
Makoto Onukid8fa7162012-05-16 13:45:48 -0700539 if (!forceUpdate && (mProviderStatus != null)
Brian Attwellc3d202c2015-01-08 15:01:03 -0800540 && (mProviderStatus.equals(providerStatus))) return;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800541 mProviderStatus = providerStatus;
542
Wenyi Wang79675452016-08-17 10:43:28 -0700543 final FragmentManager fragmentManager= getFragmentManager();
544 final FragmentTransaction transaction = fragmentManager.beginTransaction();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800545
Wenyi Wangf128ea82016-07-25 11:56:40 -0700546 // Change in CP2's provider status may not take effect immediately, see b/30566908.
547 // So we need to handle the case where provider status is STATUS_EMPTY and there is
548 // actually at least one real account (not "local" account) on device.
Wenyi Wang79675452016-08-17 10:43:28 -0700549 if (shouldShowList()) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700550 if (mAllFragment != null) {
Marcus Hagerott89c51292016-11-08 15:05:38 -0800551 final Fragment unavailableFragment = fragmentManager
552 .findFragmentByTag(TAG_UNAVAILABLE);
553 if (unavailableFragment != null) {
554 transaction.remove(unavailableFragment);
555 }
556 if (mAllFragment.isHidden()) {
557 transaction.show(mAllFragment);
558 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700559 mAllFragment.setContactsAvailable(areContactsAvailable());
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700560 mAllFragment.setEnabled(true);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800561 }
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800562 } else {
guanxiongliu5d7bb262016-01-29 16:43:45 -0800563 // Setting up the page so that the user can still use the app
564 // even without an account.
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700565 if (mAllFragment != null) {
566 mAllFragment.setEnabled(false);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800567 }
Marcus Hagerott89c51292016-11-08 15:05:38 -0800568 final ContactsUnavailableFragment fragment = new ContactsUnavailableFragment();
569 transaction.hide(mAllFragment);
570 transaction.replace(R.id.contacts_unavailable_container, fragment, TAG_UNAVAILABLE);
571 fragment.updateStatus(mProviderStatus);
Wenyi Wang79675452016-08-17 10:43:28 -0700572 }
573 if (!transaction.isEmpty()) {
574 transaction.commit();
575 fragmentManager.executePendingTransactions();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800576 }
577
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700578 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800579 }
580
Wenyi Wang79675452016-08-17 10:43:28 -0700581 private boolean shouldShowList() {
582 return mProviderStatus != null
Marcus Hagerott396aab72016-12-12 12:00:21 -0800583 && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY)
584 && mAccountTypeManager.hasNonLocalAccount())
585 || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
Wenyi Wangf128ea82016-07-25 11:56:40 -0700586 }
587
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700588 private void invalidateOptionsMenuIfNeeded() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700589 if (mAllFragment != null
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700590 && mAllFragment.getOptionsMenuContactsAvailable() != areContactsAvailable()) {
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700591 invalidateOptionsMenu();
Dmitri Plotnikov0cd01302010-12-17 18:41:57 -0800592 }
593 }
594
Dmitri Plotnikov8e86b752010-02-22 17:47:57 -0800595 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800596 public boolean onKeyDown(int keyCode, KeyEvent event) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800597 // Bring up the search UI if the user starts typing
598 final int unicodeChar = event.getUnicodeChar();
599 if ((unicodeChar != 0)
600 // If COMBINING_ACCENT is set, it's not a unicode character.
601 && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
602 && !Character.isWhitespace(unicodeChar)) {
Wenyi Wanged9f9742016-09-08 13:50:39 -0700603 if (mAllFragment.onKeyDown(unicodeChar)) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800604 return true;
Daniel Lehmann7bb2add2010-07-14 21:15:17 -0700605 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800606 }
607
608 return super.onKeyDown(keyCode, event);
609 }
610
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700611 @Override
612 public void onBackPressed() {
Jay Shrauner7712aef2015-09-25 14:14:28 -0700613 if (!isSafeToCommitTransactions()) {
Jay Shraunerc3fdc8f2015-09-16 10:29:52 -0700614 return;
615 }
616
Wenyi Wangf9905062016-09-14 10:07:59 -0700617 // Handle the back event in drawer first.
Wenyi Wangbb229242016-05-25 16:04:13 -0700618 if (mDrawer.isDrawerOpen(GravityCompat.START)) {
619 mDrawer.closeDrawer(GravityCompat.START);
Wenyi Wang51819e82016-09-12 11:57:51 -0700620 return;
Wenyi Wangf9905062016-09-14 10:07:59 -0700621 }
622
623 // Handle the back event in "second level".
624 if (isGroupView()) {
625 onBackPressedGroupView();
626 return;
627 }
628
John Shao52dd5d72016-10-06 15:16:14 -0700629 if (isAssistantView()) {
630 onBackPressedAssistantView();
Wenyi Wangf9905062016-09-14 10:07:59 -0700631 return;
632 }
633
634 // If feature highlight is present, let it handle the back event before mAllFragment.
635 if (FeatureHighlightHelper.tryRemoveHighlight(this)) {
636 return;
637 }
638
639 // Handle the back event in "first level" - mAllFragment.
640 if (maybeHandleInAllFragment()) {
641 return;
642 }
643
644 super.onBackPressed();
645 }
646
647 private void onBackPressedGroupView() {
648 if (mMembersFragment.isEditMode()) {
649 mMembersFragment.exitEditMode();
650 } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
651 mMembersFragment.getActionBarAdapter().setSelectionMode(false);
652 mMembersFragment.displayCheckBoxes(false);
653 } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
654 mMembersFragment.getActionBarAdapter().setSearchMode(false);
655 } else {
656 switchToAllContacts();
657 }
658 }
659
John Shao52dd5d72016-10-06 15:16:14 -0700660 private void onBackPressedAssistantView() {
661 if (!popThirdLevel()) {
662 switchToAllContacts();
663 } else {
664 setDrawerLockMode(/* enabled */ true);
665 }
666 }
667
Wenyi Wangf9905062016-09-14 10:07:59 -0700668 // Returns true if back event is handled in this method.
669 private boolean maybeHandleInAllFragment() {
670 if (isAllFragmentInSelectionMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700671 mAllFragment.getActionBarAdapter().setSelectionMode(false);
Wenyi Wangf9905062016-09-14 10:07:59 -0700672 return true;
673 }
674
675 if (isAllFragmentInSearchMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700676 mAllFragment.getActionBarAdapter().setSearchMode(false);
Walter Janga84fe612016-01-13 16:49:04 -0800677 if (mAllFragment.wasSearchResultClicked()) {
678 mAllFragment.resetSearchResultClicked();
679 } else {
Walter Jang62a20742016-02-24 17:04:12 -0800680 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
Walter Jang82c90332016-02-24 17:34:34 -0800681 Logger.logSearchEvent(mAllFragment.createSearchState());
Walter Janga84fe612016-01-13 16:49:04 -0800682 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700683 return true;
684 }
685
Wenyi Wang32912eb2016-09-29 17:17:07 -0700686 if (!AccountFilterUtil.isAllContactsFilter(mContactListFilterController.getFilter())
Wenyi Wang79675452016-08-17 10:43:28 -0700687 && !mAllFragment.isHidden()) {
688 // If mAllFragment is hidden, then mContactsUnavailableFragment is visible so we
689 // don't need to switch to all contacts.
Wenyi Wang40e79102016-06-01 20:43:56 -0700690 switchToAllContacts();
Wenyi Wangf9905062016-09-14 10:07:59 -0700691 return true;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700692 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700693
694 return false;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700695 }
696
Wenyi Wanged9f9742016-09-08 13:50:39 -0700697 private boolean isAllFragmentInSelectionMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700698 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700699 && mAllFragment.getActionBarAdapter().isSelectionMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700700 }
701
702 private boolean isAllFragmentInSearchMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700703 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700704 && mAllFragment.getActionBarAdapter().isSearchMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700705 }
706
Sean Midfordfc4f6922016-10-20 13:55:58 -0700707 private boolean isGroupsFragmentInSelectionMode() {
708 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
709 && mMembersFragment.getActionBarAdapter().isSelectionMode();
710 }
711
712 private boolean isGroupsFragmentInSearchMode() {
713 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
714 && mMembersFragment.getActionBarAdapter().isSearchMode();
715 }
716
Wenyi Wang79675452016-08-17 10:43:28 -0700717 @Override
718 protected void onSaveInstanceState(Bundle outState) {
719 super.onSaveInstanceState(outState);
720 outState.putParcelable(KEY_GROUP_URI, mGroupUri);
Tingting Wang2dc340c2016-07-05 22:31:58 -0700721 }
722
Wenyi Wangbb229242016-05-25 16:04:13 -0700723 @Override
Wenyi Wang79675452016-08-17 10:43:28 -0700724 protected void onRestoreInstanceState(Bundle savedInstanceState) {
725 super.onRestoreInstanceState(savedInstanceState);
726 mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI);
Tingting Wang1243cb42016-08-05 16:42:21 -0700727 }
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700728
Gary Mai4ac56292016-10-31 10:41:11 -0700729 private void onGroupDeleted(final Intent intent) {
Marcus Hagerott3c1153f2016-09-07 09:15:14 -0700730 if (!ContactSaveService.canUndo(intent)) return;
731
James Laskey6b712bc2016-11-22 11:02:09 -0800732 final AccessibilityManager am =
733 (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
James Laskey692c9612016-11-30 10:13:01 -0800734 //TODO set to INDEFINITE and track user interaction to dismiss b/33208886
735 final int accessibilityLength = 15000;
736 final int length = am.isEnabled() ? accessibilityLength : Snackbar.LENGTH_LONG;
James Laskey6b712bc2016-11-22 11:02:09 -0800737 final String message = getString(R.string.groupDeletedToast);
738
739 final Snackbar snackbar = Snackbar.make(mLayoutRoot, message, length)
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700740 .setAction(R.string.undo, new View.OnClickListener() {
741 @Override
742 public void onClick(View v) {
743 ContactSaveService.startService(PeopleActivity.this,
744 ContactSaveService.createUndoIntent(PeopleActivity.this, intent));
745 }
James Laskey6b712bc2016-11-22 11:02:09 -0800746 }).setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_action_text));
747
748 // Announce for a11y talkback
749 mLayoutRoot.announceForAccessibility(message);
750 mLayoutRoot.announceForAccessibility(getString(R.string.undo));
751
752 snackbar.show();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700753 }
754
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700755 private class SaveServiceListener extends BroadcastReceiver {
756 @Override
757 public void onReceive(Context context, Intent intent) {
758 switch (intent.getAction()) {
Marcus Hagerott819214d2016-09-29 14:58:27 -0700759 case ContactSaveService.BROADCAST_GROUP_DELETED:
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700760 onGroupDeleted(intent);
761 break;
762 }
763 }
764 }
Wenyi Wang79675452016-08-17 10:43:28 -0700765
766 @Override
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700767 protected void onGroupMenuItemClicked(long groupId, String title) {
Wenyi Wang79675452016-08-17 10:43:28 -0700768 if (isGroupView() && mMembersFragment != null
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700769 && mMembersFragment.isCurrentGroup(groupId)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700770 return;
771 }
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700772 mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700773 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700774 }
775
776 @Override
777 protected void onFilterMenuItemClicked(Intent intent) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700778 // We must pop second level first to "restart" mAllFragment, before changing filter.
Wenyi Wang79675452016-08-17 10:43:28 -0700779 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700780 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700781 showFabWithAnimation(/* showFab */ true);
Marcus Hagerott45451ea2016-10-25 20:05:26 -0700782 // HACK: swap the current filter to force listeners to update because the group
783 // member view no longer changes the filter. Fix for b/32223767
784 final ContactListFilter current = mContactListFilterController.getFilter();
785 mContactListFilterController.setContactListFilter(
786 AccountFilterUtil.createContactsFilter(this), false);
787 mContactListFilterController.setContactListFilter(current, false);
Wenyi Wang79675452016-08-17 10:43:28 -0700788 }
789 mCurrentView = ContactsView.ACCOUNT_VIEW;
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700790 super.onFilterMenuItemClicked(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700791 }
792
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700793 private void switchToOrUpdateGroupView(String action) {
Wenyi Wang17fe7982016-10-05 13:54:09 -0700794 // If group fragment is active and visible, we simply update it.
795 if (mMembersFragment != null && !mMembersFragment.isInactive()) {
Wenyi Wangf6606072016-10-03 17:34:53 -0700796 mMembersFragment.updateExistingGroupFragment(mGroupUri, action);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700797 } else {
798 switchView(ContactsView.GROUP_VIEW);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700799 }
Wenyi Wang79675452016-08-17 10:43:28 -0700800 }
801
802 @Override
John Shao52dd5d72016-10-06 15:16:14 -0700803 protected void launchAssistant() {
804 switchView(ContactsView.ASSISTANT);
Wenyi Wang79675452016-08-17 10:43:28 -0700805 }
806
807 private void switchView(ContactsView contactsView) {
Wenyi Wang79675452016-08-17 10:43:28 -0700808 mCurrentView = contactsView;
Wenyi Wang79675452016-08-17 10:43:28 -0700809
Wenyi Wang79675452016-08-17 10:43:28 -0700810 final FragmentManager fragmentManager = getFragmentManager();
811 final FragmentTransaction transaction = fragmentManager.beginTransaction();
812 if (isGroupView()) {
yaolu4c075092016-10-19 22:23:00 -0700813 mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700814 transaction.replace(
815 R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700816 } else if (isAssistantView()) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800817 Fragment uiFragment = fragmentManager.findFragmentByTag(TAG_ASSISTANT);
Sean Midfordb96df942016-11-11 17:54:49 -0800818 Fragment unavailableFragment = fragmentManager.findFragmentByTag(TAG_UNAVAILABLE);
John Shaoa3ce3c72016-10-11 14:58:57 -0700819 if (uiFragment == null) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800820 uiFragment = ObjectFactory.getAssistantFragment();
John Shaoa3ce3c72016-10-11 14:58:57 -0700821 }
Sean Midfordb96df942016-11-11 17:54:49 -0800822 if (unavailableFragment != null) {
823 transaction.remove(unavailableFragment);
824 }
John Shao5b1ffdc2016-11-08 13:51:00 -0800825 transaction.replace(R.id.contacts_list_container, uiFragment, TAG_ASSISTANT);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700826 resetToolBarStatusBarColor();
Wenyi Wang79675452016-08-17 10:43:28 -0700827 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700828 transaction.addToBackStack(TAG_SECOND_LEVEL);
Wenyi Wang79675452016-08-17 10:43:28 -0700829 transaction.commit();
830 fragmentManager.executePendingTransactions();
831
832 showFabWithAnimation(/* showFab */ false);
833 }
834
835 @Override
836 public void switchToAllContacts() {
Wenyi Wang79675452016-08-17 10:43:28 -0700837 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700838 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700839 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700840 mShouldSwitchToAllContacts = false;
Wenyi Wang79675452016-08-17 10:43:28 -0700841 mCurrentView = ContactsView.ALL_CONTACTS;
842 showFabWithAnimation(/* showFab */ true);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700843 mAllFragment.scrollToTop();
Wenyi Wang79675452016-08-17 10:43:28 -0700844
845 super.switchToAllContacts();
846 }
847
John Shao52dd5d72016-10-06 15:16:14 -0700848 private boolean popThirdLevel() {
849 return getFragmentManager().popBackStackImmediate(
850 TAG_THIRD_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
851 }
852
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700853 private void popSecondLevel() {
854 getFragmentManager().popBackStackImmediate(
855 TAG_SECOND_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
856 mMembersFragment = null;
Wenyi Wang92d7e512016-10-03 14:57:19 -0700857 resetToolBarStatusBarColor();
858 }
859
860 // Reset toolbar and status bar color to Contacts theme color.
861 private void resetToolBarStatusBarColor() {
862 findViewById(R.id.toolbar_frame).setBackgroundColor(
863 ContextCompat.getColor(this, R.color.primary_color));
864 updateStatusBarBackground(ContextCompat.getColor(this, R.color.primary_color_dark));
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700865 }
866
Wenyi Wang79675452016-08-17 10:43:28 -0700867 @Override
868 protected DefaultContactBrowseListFragment getAllFragment() {
869 return mAllFragment;
870 }
871
872 @Override
873 protected GroupMembersFragment getGroupFragment() {
874 return mMembersFragment;
875 }
876
877 @Override
Walter Jang5a496962016-09-09 18:32:50 -0700878 protected GroupMetaData getGroupMetaData() {
879 return mMembersFragment == null ? null : mMembersFragment.getGroupMetaData();
Wenyi Wang79675452016-08-17 10:43:28 -0700880 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700881
882 private void handleFilterChangeForFragment(ContactListFilter filter) {
James Laskey1842bb22016-10-20 14:38:04 -0700883 if (mAllFragment.canSetActionBar()) {
884 mAllFragment.setFilterAndUpdateTitle(filter);
885 // Scroll to top after filter is changed.
886 mAllFragment.scrollToTop();
887 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700888 }
889
890 private void handleFilterChangeForActivity(ContactListFilter filter) {
Marcus Hagerott74295d32016-10-26 10:46:28 -0700891 // The filter was changed while this activity was in the background. If we're in the
892 // assistant view Switch to the main contacts list when we resume to prevent
893 // b/31838582 and b/31829161
894 // TODO: this is a hack; we need to do some cleanup of the contact list filter stuff
895 if (isAssistantView() && filter.isContactsFilterType()) {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700896 mShouldSwitchToAllContacts = true;
897 }
898
Wenyi Wangcfe94652016-10-03 21:05:04 -0700899 // Check menu in navigation drawer.
Wenyi Wang32912eb2016-09-29 17:17:07 -0700900 updateFilterMenu(filter);
901
902 if (CompatUtils.isNCompatible()) {
903 getWindow().getDecorView()
904 .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
905 }
906 invalidateOptionsMenu();
907 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800908}