blob: c3308b56968a82b15d3722f8dd1d8b740ed7ab7f [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;
Xi Chen947c23d2016-06-30 20:23:52 -070056import com.android.contacts.common.Experiments;
Brian Attwellbdd32642015-05-08 17:03:15 -070057import com.android.contacts.common.activity.RequestPermissionsActivity;
Wenyi Wang32912eb2016-09-29 17:17:07 -070058import com.android.contacts.common.compat.CompatUtils;
Chiao Chenga0233a02012-11-01 16:41:08 -070059import com.android.contacts.common.list.ContactListFilter;
Wenyi Wang32912eb2016-09-29 17:17:07 -070060import com.android.contacts.common.list.ContactListFilterController.ContactListFilterListener;
Wenyi Wangbb229242016-05-25 16:04:13 -070061import com.android.contacts.common.list.ProviderStatusWatcher;
62import com.android.contacts.common.list.ProviderStatusWatcher.ProviderStatusListener;
Walter Janga84fe612016-01-13 16:49:04 -080063import com.android.contacts.common.logging.Logger;
Walter Jang62a20742016-02-24 17:04:12 -080064import com.android.contacts.common.logging.ScreenEvent.ScreenType;
Wenyi Wangbf693302016-06-14 12:49:03 -070065import com.android.contacts.common.model.AccountTypeManager;
66import com.android.contacts.common.model.account.AccountWithDataSet;
Wenyi Wang587b8f22016-08-17 17:40:45 -070067import com.android.contacts.common.util.AccountFilterUtil;
guanxiongliuf597ec62016-01-25 19:49:42 -080068import com.android.contacts.common.util.Constants;
guanxiongliu5d7bb262016-01-29 16:43:45 -080069import com.android.contacts.common.util.ImplicitIntentsUtil;
guanxiongliu5d7bb262016-01-29 16:43:45 -080070import com.android.contacts.common.widget.FloatingActionButtonController;
Wenyi Wang79675452016-08-17 10:43:28 -070071import com.android.contacts.group.GroupMembersFragment;
Walter Jang5a496962016-09-09 18:32:50 -070072import com.android.contacts.group.GroupMetaData;
Wenyi Wang79675452016-08-17 10:43:28 -070073import com.android.contacts.group.GroupUtil;
guanxiongliuf597ec62016-01-25 19:49:42 -080074import com.android.contacts.list.ContactsIntentResolver;
75import com.android.contacts.list.ContactsRequest;
76import com.android.contacts.list.ContactsUnavailableFragment;
Walter Jange9ea4f02016-05-10 09:39:46 -070077import com.android.contacts.list.DefaultContactBrowseListFragment;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070078import com.android.contacts.util.SyncUtil;
Wenyi Wangf9905062016-09-14 10:07:59 -070079import com.android.contactsbind.FeatureHighlightHelper;
Wenyi Wang79675452016-08-17 10:43:28 -070080import com.android.contactsbind.ObjectFactory;
Walter Jang6367d2a2016-08-15 14:51:18 -070081import com.android.contactsbind.experiments.Flags;
Tadashi G. Takaoka57cf30f2009-09-21 19:54:39 +090082
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;
106
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
169 final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
170 .getAccounts(/* contactsWritableOnly */ true);
171 final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
172 // If one of the accounts is active or pending, use spinning circle to indicate one of
173 // the syncs is in progress.
174 if (syncableAccounts != null && syncableAccounts.size() > 0) {
175 for (Account account: syncableAccounts) {
yaolu9d998592016-10-14 23:21:00 -0700176 if (SyncUtil.isSyncStatusPendingOrActive(account)) {
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700177 return;
178 }
179 }
180 }
181 swipeRefreshLayout.setRefreshing(false);
182 }
183 }
184
yaolu395c3f82016-10-18 11:13:39 -0700185 public void showConnectionErrorMsg() {
186 Snackbar.make(mLayoutRoot, R.string.connection_error_message, Snackbar.LENGTH_LONG).show();
187 }
188
Wenyi Wang32912eb2016-09-29 17:17:07 -0700189 private final ContactListFilterListener mFilterListener = new ContactListFilterListener() {
190 @Override
191 public void onContactListFilterChanged() {
192 final ContactListFilter filter = mContactListFilterController.getFilter();
193 handleFilterChangeForFragment(filter);
194 handleFilterChangeForActivity(filter);
195 }
196 };
197
198 private final ProviderStatusListener mProviderStatusListener = new ProviderStatusListener() {
199 @Override
200 public void onProviderStatusChange() {
201 reloadGroupsAndFiltersIfNeeded();
202 updateViewConfiguration(false);
203 }
204 };
205
Katherine Kuan9856fce2011-06-01 10:24:09 -0700206 public PeopleActivity() {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700207 mInstanceId = sNextInstanceId.getAndIncrement();
Dmitri Plotnikov15406742010-05-07 09:22:49 -0700208 mIntentResolver = new ContactsIntentResolver(this);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700209 mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
Dmitri Plotnikov6178cb42010-04-20 11:26:05 -0700210 }
211
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700212 @Override
213 public String toString() {
214 // Shown on logcat
215 return String.format("%s@%d", getClass().getSimpleName(), mInstanceId);
216 }
217
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700218 private boolean areContactsAvailable() {
Wenyi Wang2f09e602015-10-28 11:34:23 -0700219 return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800220 }
221
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700222 @Override
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700223 protected void onCreate(Bundle savedState) {
Makoto Onuki49627cc2011-08-28 13:56:48 -0700224 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
225 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
226 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700227 super.onCreate(savedState);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800228
Brian Attwellbdd32642015-05-08 17:03:15 -0700229 if (RequestPermissionsActivity.startPermissionActivity(this)) {
230 return;
231 }
232
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700233 if (!processIntent(false)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700234 finish();
235 return;
236 }
Daisuke Miyakawaa012aec2011-10-16 10:24:43 -0700237
Wenyi Wang32912eb2016-09-29 17:17:07 -0700238 mContactListFilterController.addListener(mFilterListener);
239 mProviderStatusWatcher.addListener(mProviderStatusListener);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700240
Makoto Onuki417ca492011-07-14 19:06:35 -0700241 mIsRecreatedInstance = (savedState != null);
Wenyi Wang40e79102016-06-01 20:43:56 -0700242
Wenyi Wang79675452016-08-17 10:43:28 -0700243 if (mIsRecreatedInstance) {
244 mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
245 }
246
Wenyi Wang587b8f22016-08-17 17:40:45 -0700247 createViewsAndFragments();
Andrew Lee4b1af3f2014-04-23 10:23:55 -0700248
Makoto Onuki49627cc2011-08-28 13:56:48 -0700249 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
250 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
251 }
Sai Cheemalapati5b221082014-06-27 14:45:43 -0700252 getWindow().setBackgroundDrawable(null);
Tingting Wangac9596e2016-08-02 22:24:24 -0700253 }
Tingting Wangdce1e682016-07-28 10:06:29 -0700254
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800255 @Override
256 protected void onNewIntent(Intent intent) {
Gary Mai4ac56292016-10-31 10:41:11 -0700257 final String action = intent.getAction();
258 if (GroupUtil.ACTION_CREATE_GROUP.equals(action)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700259 mGroupUri = intent.getData();
260 if (mGroupUri == null) {
261 toast(R.string.groupSavedErrorToast);
262 return;
263 }
264 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
yaolu9b6159c2016-10-24 23:31:49 -0700265 switchView(ContactsView.GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700266 mMembersFragment.toastForSaveAction(action);
Walter Jang13710d52016-07-08 14:36:20 -0700267 return;
268 }
269
Gary Mai4ac56292016-10-31 10:41:11 -0700270 if (isGroupDeleteAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700271 popSecondLevel();
Gary Mai4ac56292016-10-31 10:41:11 -0700272 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700273 mCurrentView = ContactsView.ALL_CONTACTS;
274 showFabWithAnimation(/* showFab */ true);
275 return;
276 }
277
Gary Mai4ac56292016-10-31 10:41:11 -0700278 if (isGroupSaveAction(action)) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700279 mGroupUri = intent.getData();
280 if (mGroupUri == null) {
281 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700282 toast(R.string.groupSavedErrorToast);
283 return;
284 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700285 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
Gary Mai4ac56292016-10-31 10:41:11 -0700286 // ACTION_REMOVE_FROM_GROUP doesn't reload data, so it shouldn't cause b/32223934
287 // but it's necessary to use the previous fragment since
288 // GroupMembersFragment#mIsEditMode needs to be persisted between remove actions.
289 if (GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action)) {
290 switchToOrUpdateGroupView(action);
291 } else {
292 switchView(ContactsView.GROUP_VIEW);
293 }
294 mMembersFragment.toastForSaveAction(action);
Wenyi Wang79675452016-08-17 10:43:28 -0700295 }
296
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800297 setIntent(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700298
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700299 if (!processIntent(true)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700300 finish();
301 return;
302 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700303
Wenyi Wang79675452016-08-17 10:43:28 -0700304 mContactListFilterController.checkFilterValidity(false);
305
306 if (!isInSecondLevel()) {
307 // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
308 // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
309 // initially.
Wenyi Wanged9f9742016-09-08 13:50:39 -0700310 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ true);
Wenyi Wang79675452016-08-17 10:43:28 -0700311 mAllFragment.initializeActionBarAdapter(null);
312 }
Katherine Kuanbe79b8f2011-11-09 20:54:43 -0800313
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700314 initializeFabVisibility();
Makoto Onuki417ca492011-07-14 19:06:35 -0700315 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800316 }
317
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700318 private static boolean isGroupDeleteAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700319 return GroupUtil.ACTION_DELETE_GROUP.equals(action);
320 }
321
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700322 private static boolean isGroupSaveAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700323 return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
324 || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
325 || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
326 }
327
Wenyi Wang79675452016-08-17 10:43:28 -0700328 private void toast(int resId) {
329 if (resId >= 0) {
330 Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
331 }
332 }
333
Makoto Onuki417ca492011-07-14 19:06:35 -0700334 /**
335 * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
336 * is needed.
337 *
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700338 * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}.
Makoto Onuki417ca492011-07-14 19:06:35 -0700339 * @return {@code true} if {@link PeopleActivity} should continue running. {@code false}
340 * if it shouldn't, in which case the caller should finish() itself and shouldn't do
341 * farther initialization.
342 */
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700343 private boolean processIntent(boolean forNewIntent) {
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700344 // Extract relevant information from the intent
345 mRequest = mIntentResolver.resolveIntent(getIntent());
Makoto Onukiea146052011-07-25 10:34:15 -0700346 if (Log.isLoggable(TAG, Log.DEBUG)) {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700347 Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent
348 + " intent=" + getIntent() + " request=" + mRequest);
349 }
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700350 if (!mRequest.isValid()) {
351 setResult(RESULT_CANCELED);
Makoto Onuki417ca492011-07-14 19:06:35 -0700352 return false;
Dmitri Plotnikov59fb48e2010-04-26 17:09:19 -0700353 }
354
Walter Jang1110d672016-07-25 17:55:12 +0000355 switch (mRequest.getActionCode()) {
356 case ContactsRequest.ACTION_VIEW_CONTACT: {
Walter Jang0396cf72016-09-21 13:23:29 -0700357 ImplicitIntentsUtil.startQuickContact(
358 this, mRequest.getContactUri(), ScreenType.UNKNOWN);
Walter Jang1110d672016-07-25 17:55:12 +0000359 return false;
360 }
361 case ContactsRequest.ACTION_INSERT_GROUP: {
362 onCreateGroupMenuItemClicked();
363 return true;
364 }
Wenyi Wang79675452016-08-17 10:43:28 -0700365 case ContactsRequest.ACTION_VIEW_GROUP:
366 case ContactsRequest.ACTION_EDIT_GROUP: {
367 mShouldSwitchToGroupView = true;
368 return true;
369 }
Dmitri Plotnikov27b97bc2010-10-07 18:06:09 -0700370 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700371 return true;
372 }
373
Wenyi Wang587b8f22016-08-17 17:40:45 -0700374 private void createViewsAndFragments() {
Makoto Onuki417ca492011-07-14 19:06:35 -0700375 setContentView(R.layout.people_activity);
376
377 final FragmentManager fragmentManager = getFragmentManager();
378
Wenyi Wang79675452016-08-17 10:43:28 -0700379 setUpAllFragment(fragmentManager);
Makoto Onuki417ca492011-07-14 19:06:35 -0700380
Wenyi Wang17fe7982016-10-05 13:54:09 -0700381 mMembersFragment = (GroupMembersFragment) fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
Makoto Onuki417ca492011-07-14 19:06:35 -0700382
Brian Attwell865847b2015-04-20 14:40:17 -0700383 // Configure floating action button
384 mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
385 final ImageButton floatingActionButton
386 = (ImageButton) findViewById(R.id.floating_action_button);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700387 floatingActionButton.setOnClickListener(new View.OnClickListener() {
388 @Override
389 public void onClick(View v) {
Wenyi Wang79675452016-08-17 10:43:28 -0700390 AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(),
391 mContactListFilterController.getFilter());
Wenyi Wang587b8f22016-08-17 17:40:45 -0700392 }
393 });
Brian Attwell865847b2015-04-20 14:40:17 -0700394 mFloatingActionButtonController = new FloatingActionButtonController(this,
395 mFloatingActionButtonContainer, floatingActionButton);
Paul Soulos2b9563d2014-05-27 16:21:23 -0700396
Makoto Onuki417ca492011-07-14 19:06:35 -0700397 invalidateOptionsMenuIfNeeded();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700398
399 mLayoutRoot = (CoordinatorLayout) findViewById(R.id.root);
400
Wenyi Wang79675452016-08-17 10:43:28 -0700401 if (mShouldSwitchToGroupView && !mIsRecreatedInstance) {
402 mGroupUri = mRequest.getContactUri();
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700403 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700404 mShouldSwitchToGroupView = false;
405 }
406 }
407
408 private void setUpAllFragment(FragmentManager fragmentManager) {
409 mAllFragment = (DefaultContactBrowseListFragment)
410 fragmentManager.findFragmentByTag(TAG_ALL);
411
412 if (mAllFragment == null) {
413 mAllFragment = new DefaultContactBrowseListFragment();
414 mAllFragment.setAnimateOnLoad(true);
415 fragmentManager.beginTransaction()
416 .add(R.id.contacts_list_container, mAllFragment, TAG_ALL)
417 .commit();
418 fragmentManager.executePendingTransactions();
419 }
420
421 mAllFragment.setContactsAvailable(areContactsAvailable());
Wenyi Wangdf3e8492016-09-09 11:10:07 -0700422 mAllFragment.setListType(mContactListFilterController.getFilterListType());
Wenyi Wanged9f9742016-09-08 13:50:39 -0700423 mAllFragment.setParameters(/* ContactsRequest */ mRequest, /* fromOnNewIntent */ false);
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700424 }
425
Dmitri Plotnikov6e850a02010-10-28 10:46:21 -0700426 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700427 protected void onPause() {
Makoto Onukic2bd6132012-04-27 16:14:51 -0700428 mProviderStatusWatcher.stop();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700429
430 LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener);
431
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700432 super.onPause();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700433
Walter Jang9adc9ef2016-11-02 18:50:38 -0700434 ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle);
435 onSyncStateUpdated();
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700436 }
437
438 @Override
Sean Midfordfc4f6922016-10-20 13:55:58 -0700439 public void onMultiWindowModeChanged(boolean entering) {
440 initializeHomeVisibility();
441 }
442
443 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700444 protected void onResume() {
445 super.onResume();
Josh Gargus697ab262012-05-04 11:11:34 -0700446
Wenyi Wang32912eb2016-09-29 17:17:07 -0700447 if (mShouldSwitchToAllContacts) {
448 switchToAllContacts();
449 }
450
Makoto Onukic2bd6132012-04-27 16:14:51 -0700451 mProviderStatusWatcher.start();
Josh Gargus697ab262012-05-04 11:11:34 -0700452 updateViewConfiguration(true);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700453
Walter Jang9adc9ef2016-11-02 18:50:38 -0700454 mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener(
455 ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
456 | ContentResolver.SYNC_OBSERVER_TYPE_PENDING
457 | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
458 mSyncStatusObserver);
459 onSyncStateUpdated();
460
Wenyi Wang587b8f22016-08-17 17:40:45 -0700461 initializeFabVisibility();
Sean Midfordfc4f6922016-10-20 13:55:58 -0700462 initializeHomeVisibility();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700463
464 mSaveServiceListener = new SaveServiceListener();
465 LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
Marcus Hagerott819214d2016-09-29 14:58:27 -0700466 new IntentFilter(ContactSaveService.BROADCAST_GROUP_DELETED));
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700467 }
468
469 @Override
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700470 protected void onDestroy() {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700471 mProviderStatusWatcher.removeListener(mProviderStatusListener);
472 mContactListFilterController.removeListener(mFilterListener);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700473 super.onDestroy();
474 }
475
Brian Attwell865847b2015-04-20 14:40:17 -0700476 private void initializeFabVisibility() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700477 mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE);
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700478 mFloatingActionButtonController.resetIn();
Wenyi Wang587b8f22016-08-17 17:40:45 -0700479 wasLastFabAnimationScaleIn = !shouldHideFab();
Brian Attwell865847b2015-04-20 14:40:17 -0700480 }
481
Sean Midfordfc4f6922016-10-20 13:55:58 -0700482 private void initializeHomeVisibility() {
483 // Remove the navigation icon if we return to the fragment in a search or select state
484 if (getToolbar() != null && (isAllFragmentInSelectionMode()
485 || isAllFragmentInSearchMode() || isGroupsFragmentInSelectionMode()
486 || isGroupsFragmentInSearchMode())) {
487 getToolbar().setNavigationIcon(null);
488 }
489 }
490
Wenyi Wang587b8f22016-08-17 17:40:45 -0700491 private boolean shouldHideFab() {
Wenyi Wang79675452016-08-17 10:43:28 -0700492 if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
493 || isInSecondLevel()) {
494 return true;
495 }
Wenyi Wanged9f9742016-09-08 13:50:39 -0700496 return isAllFragmentInSearchMode() || isAllFragmentInSelectionMode();
Wenyi Wangbf693302016-06-14 12:49:03 -0700497 }
498
Wenyi Wang587b8f22016-08-17 17:40:45 -0700499 public void showFabWithAnimation(boolean showFab) {
Brian Attwell865847b2015-04-20 14:40:17 -0700500 if (mFloatingActionButtonContainer == null) {
501 return;
502 }
503 if (showFab) {
504 if (!wasLastFabAnimationScaleIn) {
505 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
506 mFloatingActionButtonController.scaleIn(0);
507 }
508 wasLastFabAnimationScaleIn = true;
509
510 } else {
511 if (wasLastFabAnimationScaleIn) {
512 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
513 mFloatingActionButtonController.scaleOut();
514 }
515 wasLastFabAnimationScaleIn = false;
516 }
517 }
518
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700519 private void reloadGroupsAndFiltersIfNeeded() {
520 final int providerStatus = mProviderStatusWatcher.getProviderStatus();
521 final Menu menu = mNavigationView.getMenu();
522 final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
523 final SubMenu subMenu = groupsMenuItem.getSubMenu();
524
525 // Reload groups and filters if provider status changes to "normal" and there's no groups
526 // loaded or just a "Create new..." menu item is in the menu.
527 if (subMenu != null && subMenu.size() <= 1 && providerStatus == ProviderStatus.STATUS_NORMAL
528 && !mProviderStatus.equals(providerStatus)) {
529 loadGroupsAndFilters();
530 }
531 }
532
Josh Gargus697ab262012-05-04 11:11:34 -0700533 private void updateViewConfiguration(boolean forceUpdate) {
Brian Attwellc3d202c2015-01-08 15:01:03 -0800534 int providerStatus = mProviderStatusWatcher.getProviderStatus();
Makoto Onukid8fa7162012-05-16 13:45:48 -0700535 if (!forceUpdate && (mProviderStatus != null)
Brian Attwellc3d202c2015-01-08 15:01:03 -0800536 && (mProviderStatus.equals(providerStatus))) return;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800537 mProviderStatus = providerStatus;
538
Wenyi Wang79675452016-08-17 10:43:28 -0700539 final FragmentManager fragmentManager= getFragmentManager();
540 final FragmentTransaction transaction = fragmentManager.beginTransaction();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800541
Wenyi Wangf128ea82016-07-25 11:56:40 -0700542 // Change in CP2's provider status may not take effect immediately, see b/30566908.
543 // So we need to handle the case where provider status is STATUS_EMPTY and there is
544 // actually at least one real account (not "local" account) on device.
Wenyi Wang79675452016-08-17 10:43:28 -0700545 if (shouldShowList()) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700546 if (mAllFragment != null) {
Marcus Hagerott89c51292016-11-08 15:05:38 -0800547 final Fragment unavailableFragment = fragmentManager
548 .findFragmentByTag(TAG_UNAVAILABLE);
549 if (unavailableFragment != null) {
550 transaction.remove(unavailableFragment);
551 }
552 if (mAllFragment.isHidden()) {
553 transaction.show(mAllFragment);
554 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700555 mAllFragment.setContactsAvailable(areContactsAvailable());
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700556 mAllFragment.setEnabled(true);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800557 }
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800558 } else {
guanxiongliu5d7bb262016-01-29 16:43:45 -0800559 // Setting up the page so that the user can still use the app
560 // even without an account.
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700561 if (mAllFragment != null) {
562 mAllFragment.setEnabled(false);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800563 }
Marcus Hagerott89c51292016-11-08 15:05:38 -0800564 final ContactsUnavailableFragment fragment = new ContactsUnavailableFragment();
565 transaction.hide(mAllFragment);
566 transaction.replace(R.id.contacts_unavailable_container, fragment, TAG_UNAVAILABLE);
567 fragment.updateStatus(mProviderStatus);
Wenyi Wang79675452016-08-17 10:43:28 -0700568 }
569 if (!transaction.isEmpty()) {
570 transaction.commit();
571 fragmentManager.executePendingTransactions();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800572 }
573
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700574 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800575 }
576
Wenyi Wang79675452016-08-17 10:43:28 -0700577 private boolean shouldShowList() {
578 return mProviderStatus != null
579 && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) && hasNonLocalAccount())
580 || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
581 }
582
Wenyi Wangf128ea82016-07-25 11:56:40 -0700583 // Returns true if there are real accounts (not "local" account) in the list of accounts.
584 private boolean hasNonLocalAccount() {
585 final List<AccountWithDataSet> allAccounts =
586 AccountTypeManager.getInstance(this).getAccounts(/* contactWritableOnly */ false);
587 if (allAccounts == null || allAccounts.size() == 0) {
588 return false;
589 }
590 if (allAccounts.size() > 1) {
591 return true;
592 }
Marcus Hagerott949d4e82016-09-20 13:23:05 -0700593 return !allAccounts.get(0).isNullAccount();
Wenyi Wangf128ea82016-07-25 11:56:40 -0700594 }
595
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700596 private void invalidateOptionsMenuIfNeeded() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700597 if (mAllFragment != null
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700598 && mAllFragment.getOptionsMenuContactsAvailable() != areContactsAvailable()) {
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700599 invalidateOptionsMenu();
Dmitri Plotnikov0cd01302010-12-17 18:41:57 -0800600 }
601 }
602
Dmitri Plotnikov8e86b752010-02-22 17:47:57 -0800603 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800604 public boolean onKeyDown(int keyCode, KeyEvent event) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800605 // Bring up the search UI if the user starts typing
606 final int unicodeChar = event.getUnicodeChar();
607 if ((unicodeChar != 0)
608 // If COMBINING_ACCENT is set, it's not a unicode character.
609 && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
610 && !Character.isWhitespace(unicodeChar)) {
Wenyi Wanged9f9742016-09-08 13:50:39 -0700611 if (mAllFragment.onKeyDown(unicodeChar)) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800612 return true;
Daniel Lehmann7bb2add2010-07-14 21:15:17 -0700613 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800614 }
615
616 return super.onKeyDown(keyCode, event);
617 }
618
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700619 @Override
620 public void onBackPressed() {
Jay Shrauner7712aef2015-09-25 14:14:28 -0700621 if (!isSafeToCommitTransactions()) {
Jay Shraunerc3fdc8f2015-09-16 10:29:52 -0700622 return;
623 }
624
Wenyi Wangf9905062016-09-14 10:07:59 -0700625 // Handle the back event in drawer first.
Wenyi Wangbb229242016-05-25 16:04:13 -0700626 if (mDrawer.isDrawerOpen(GravityCompat.START)) {
627 mDrawer.closeDrawer(GravityCompat.START);
Wenyi Wang51819e82016-09-12 11:57:51 -0700628 return;
Wenyi Wangf9905062016-09-14 10:07:59 -0700629 }
630
631 // Handle the back event in "second level".
632 if (isGroupView()) {
633 onBackPressedGroupView();
634 return;
635 }
636
John Shao52dd5d72016-10-06 15:16:14 -0700637 if (isAssistantView()) {
638 onBackPressedAssistantView();
Wenyi Wangf9905062016-09-14 10:07:59 -0700639 return;
640 }
641
642 // If feature highlight is present, let it handle the back event before mAllFragment.
643 if (FeatureHighlightHelper.tryRemoveHighlight(this)) {
644 return;
645 }
646
647 // Handle the back event in "first level" - mAllFragment.
648 if (maybeHandleInAllFragment()) {
649 return;
650 }
651
652 super.onBackPressed();
653 }
654
655 private void onBackPressedGroupView() {
656 if (mMembersFragment.isEditMode()) {
657 mMembersFragment.exitEditMode();
658 } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
659 mMembersFragment.getActionBarAdapter().setSelectionMode(false);
660 mMembersFragment.displayCheckBoxes(false);
661 } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
662 mMembersFragment.getActionBarAdapter().setSearchMode(false);
663 } else {
664 switchToAllContacts();
665 }
666 }
667
John Shao52dd5d72016-10-06 15:16:14 -0700668 private void onBackPressedAssistantView() {
669 if (!popThirdLevel()) {
670 switchToAllContacts();
671 } else {
672 setDrawerLockMode(/* enabled */ true);
673 }
674 }
675
Wenyi Wangf9905062016-09-14 10:07:59 -0700676 // Returns true if back event is handled in this method.
677 private boolean maybeHandleInAllFragment() {
678 if (isAllFragmentInSelectionMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700679 mAllFragment.getActionBarAdapter().setSelectionMode(false);
Wenyi Wangf9905062016-09-14 10:07:59 -0700680 return true;
681 }
682
683 if (isAllFragmentInSearchMode()) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700684 mAllFragment.getActionBarAdapter().setSearchMode(false);
Walter Janga84fe612016-01-13 16:49:04 -0800685 if (mAllFragment.wasSearchResultClicked()) {
686 mAllFragment.resetSearchResultClicked();
687 } else {
Walter Jang62a20742016-02-24 17:04:12 -0800688 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
Walter Jang82c90332016-02-24 17:34:34 -0800689 Logger.logSearchEvent(mAllFragment.createSearchState());
Walter Janga84fe612016-01-13 16:49:04 -0800690 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700691 return true;
692 }
693
Wenyi Wang32912eb2016-09-29 17:17:07 -0700694 if (!AccountFilterUtil.isAllContactsFilter(mContactListFilterController.getFilter())
Wenyi Wang79675452016-08-17 10:43:28 -0700695 && !mAllFragment.isHidden()) {
696 // If mAllFragment is hidden, then mContactsUnavailableFragment is visible so we
697 // don't need to switch to all contacts.
Wenyi Wang40e79102016-06-01 20:43:56 -0700698 switchToAllContacts();
Wenyi Wangf9905062016-09-14 10:07:59 -0700699 return true;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700700 }
Wenyi Wangf9905062016-09-14 10:07:59 -0700701
702 return false;
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700703 }
704
Wenyi Wanged9f9742016-09-08 13:50:39 -0700705 private boolean isAllFragmentInSelectionMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700706 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700707 && mAllFragment.getActionBarAdapter().isSelectionMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700708 }
709
710 private boolean isAllFragmentInSearchMode() {
Sean Midfordfc4f6922016-10-20 13:55:58 -0700711 return mAllFragment != null && mAllFragment.getActionBarAdapter() != null
Wenyi Wang92d7e512016-10-03 14:57:19 -0700712 && mAllFragment.getActionBarAdapter().isSearchMode();
Wenyi Wanged9f9742016-09-08 13:50:39 -0700713 }
714
Sean Midfordfc4f6922016-10-20 13:55:58 -0700715 private boolean isGroupsFragmentInSelectionMode() {
716 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
717 && mMembersFragment.getActionBarAdapter().isSelectionMode();
718 }
719
720 private boolean isGroupsFragmentInSearchMode() {
721 return mMembersFragment != null && mMembersFragment.getActionBarAdapter() != null
722 && mMembersFragment.getActionBarAdapter().isSearchMode();
723 }
724
Wenyi Wang79675452016-08-17 10:43:28 -0700725 @Override
726 protected void onSaveInstanceState(Bundle outState) {
727 super.onSaveInstanceState(outState);
728 outState.putParcelable(KEY_GROUP_URI, mGroupUri);
Tingting Wang2dc340c2016-07-05 22:31:58 -0700729 }
730
Wenyi Wangbb229242016-05-25 16:04:13 -0700731 @Override
Wenyi Wang79675452016-08-17 10:43:28 -0700732 protected void onRestoreInstanceState(Bundle savedInstanceState) {
733 super.onRestoreInstanceState(savedInstanceState);
734 mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI);
Tingting Wang1243cb42016-08-05 16:42:21 -0700735 }
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700736
Gary Mai4ac56292016-10-31 10:41:11 -0700737 private void onGroupDeleted(final Intent intent) {
Marcus Hagerott3c1153f2016-09-07 09:15:14 -0700738 if (!ContactSaveService.canUndo(intent)) return;
739
James Laskey6b712bc2016-11-22 11:02:09 -0800740 final AccessibilityManager am =
741 (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE);
James Laskey692c9612016-11-30 10:13:01 -0800742 //TODO set to INDEFINITE and track user interaction to dismiss b/33208886
743 final int accessibilityLength = 15000;
744 final int length = am.isEnabled() ? accessibilityLength : Snackbar.LENGTH_LONG;
James Laskey6b712bc2016-11-22 11:02:09 -0800745 final String message = getString(R.string.groupDeletedToast);
746
747 final Snackbar snackbar = Snackbar.make(mLayoutRoot, message, length)
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700748 .setAction(R.string.undo, new View.OnClickListener() {
749 @Override
750 public void onClick(View v) {
751 ContactSaveService.startService(PeopleActivity.this,
752 ContactSaveService.createUndoIntent(PeopleActivity.this, intent));
753 }
James Laskey6b712bc2016-11-22 11:02:09 -0800754 }).setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_action_text));
755
756 // Announce for a11y talkback
757 mLayoutRoot.announceForAccessibility(message);
758 mLayoutRoot.announceForAccessibility(getString(R.string.undo));
759
760 snackbar.show();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700761 }
762
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700763 private class SaveServiceListener extends BroadcastReceiver {
764 @Override
765 public void onReceive(Context context, Intent intent) {
766 switch (intent.getAction()) {
Marcus Hagerott819214d2016-09-29 14:58:27 -0700767 case ContactSaveService.BROADCAST_GROUP_DELETED:
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700768 onGroupDeleted(intent);
769 break;
770 }
771 }
772 }
Wenyi Wang79675452016-08-17 10:43:28 -0700773
774 @Override
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700775 protected void onGroupMenuItemClicked(long groupId, String title) {
Wenyi Wang79675452016-08-17 10:43:28 -0700776 if (isGroupView() && mMembersFragment != null
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700777 && mMembersFragment.isCurrentGroup(groupId)) {
Wenyi Wang79675452016-08-17 10:43:28 -0700778 return;
779 }
Marcus Hagerottd6d5ad52016-10-25 19:25:38 -0700780 mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700781 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700782 }
783
784 @Override
785 protected void onFilterMenuItemClicked(Intent intent) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700786 // We must pop second level first to "restart" mAllFragment, before changing filter.
Wenyi Wang79675452016-08-17 10:43:28 -0700787 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700788 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700789 showFabWithAnimation(/* showFab */ true);
Marcus Hagerott45451ea2016-10-25 20:05:26 -0700790 // HACK: swap the current filter to force listeners to update because the group
791 // member view no longer changes the filter. Fix for b/32223767
792 final ContactListFilter current = mContactListFilterController.getFilter();
793 mContactListFilterController.setContactListFilter(
794 AccountFilterUtil.createContactsFilter(this), false);
795 mContactListFilterController.setContactListFilter(current, false);
Wenyi Wang79675452016-08-17 10:43:28 -0700796 }
797 mCurrentView = ContactsView.ACCOUNT_VIEW;
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700798 super.onFilterMenuItemClicked(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700799 }
800
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700801 private void switchToOrUpdateGroupView(String action) {
Wenyi Wang17fe7982016-10-05 13:54:09 -0700802 // If group fragment is active and visible, we simply update it.
803 if (mMembersFragment != null && !mMembersFragment.isInactive()) {
Wenyi Wangf6606072016-10-03 17:34:53 -0700804 mMembersFragment.updateExistingGroupFragment(mGroupUri, action);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700805 } else {
806 switchView(ContactsView.GROUP_VIEW);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700807 }
Wenyi Wang79675452016-08-17 10:43:28 -0700808 }
809
810 @Override
John Shao52dd5d72016-10-06 15:16:14 -0700811 protected void launchAssistant() {
812 switchView(ContactsView.ASSISTANT);
Wenyi Wang79675452016-08-17 10:43:28 -0700813 }
814
815 private void switchView(ContactsView contactsView) {
Wenyi Wang79675452016-08-17 10:43:28 -0700816 mCurrentView = contactsView;
Wenyi Wang79675452016-08-17 10:43:28 -0700817
Wenyi Wang79675452016-08-17 10:43:28 -0700818 final FragmentManager fragmentManager = getFragmentManager();
819 final FragmentTransaction transaction = fragmentManager.beginTransaction();
820 if (isGroupView()) {
yaolu4c075092016-10-19 22:23:00 -0700821 mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700822 transaction.replace(
823 R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
Gary Mai4ac56292016-10-31 10:41:11 -0700824 } else if (isAssistantView()) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800825 Fragment uiFragment = fragmentManager.findFragmentByTag(TAG_ASSISTANT);
Sean Midfordb96df942016-11-11 17:54:49 -0800826 Fragment unavailableFragment = fragmentManager.findFragmentByTag(TAG_UNAVAILABLE);
John Shaoa3ce3c72016-10-11 14:58:57 -0700827 if (uiFragment == null) {
John Shao5b1ffdc2016-11-08 13:51:00 -0800828 uiFragment = ObjectFactory.getAssistantFragment();
John Shaoa3ce3c72016-10-11 14:58:57 -0700829 }
Sean Midfordb96df942016-11-11 17:54:49 -0800830 if (unavailableFragment != null) {
831 transaction.remove(unavailableFragment);
832 }
John Shao5b1ffdc2016-11-08 13:51:00 -0800833 transaction.replace(R.id.contacts_list_container, uiFragment, TAG_ASSISTANT);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700834 resetToolBarStatusBarColor();
Wenyi Wang79675452016-08-17 10:43:28 -0700835 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700836 transaction.addToBackStack(TAG_SECOND_LEVEL);
Wenyi Wang79675452016-08-17 10:43:28 -0700837 transaction.commit();
838 fragmentManager.executePendingTransactions();
839
840 showFabWithAnimation(/* showFab */ false);
841 }
842
843 @Override
844 public void switchToAllContacts() {
Wenyi Wang79675452016-08-17 10:43:28 -0700845 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700846 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700847 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700848 mShouldSwitchToAllContacts = false;
Wenyi Wang79675452016-08-17 10:43:28 -0700849 mCurrentView = ContactsView.ALL_CONTACTS;
850 showFabWithAnimation(/* showFab */ true);
Wenyi Wang17fe7982016-10-05 13:54:09 -0700851 mAllFragment.scrollToTop();
Wenyi Wang79675452016-08-17 10:43:28 -0700852
853 super.switchToAllContacts();
854 }
855
John Shao52dd5d72016-10-06 15:16:14 -0700856 private boolean popThirdLevel() {
857 return getFragmentManager().popBackStackImmediate(
858 TAG_THIRD_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
859 }
860
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700861 private void popSecondLevel() {
862 getFragmentManager().popBackStackImmediate(
863 TAG_SECOND_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
864 mMembersFragment = null;
Wenyi Wang92d7e512016-10-03 14:57:19 -0700865 resetToolBarStatusBarColor();
866 }
867
868 // Reset toolbar and status bar color to Contacts theme color.
869 private void resetToolBarStatusBarColor() {
870 findViewById(R.id.toolbar_frame).setBackgroundColor(
871 ContextCompat.getColor(this, R.color.primary_color));
872 updateStatusBarBackground(ContextCompat.getColor(this, R.color.primary_color_dark));
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700873 }
874
Wenyi Wang79675452016-08-17 10:43:28 -0700875 @Override
876 protected DefaultContactBrowseListFragment getAllFragment() {
877 return mAllFragment;
878 }
879
880 @Override
881 protected GroupMembersFragment getGroupFragment() {
882 return mMembersFragment;
883 }
884
885 @Override
Walter Jang5a496962016-09-09 18:32:50 -0700886 protected GroupMetaData getGroupMetaData() {
887 return mMembersFragment == null ? null : mMembersFragment.getGroupMetaData();
Wenyi Wang79675452016-08-17 10:43:28 -0700888 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700889
890 private void handleFilterChangeForFragment(ContactListFilter filter) {
James Laskey1842bb22016-10-20 14:38:04 -0700891 if (mAllFragment.canSetActionBar()) {
892 mAllFragment.setFilterAndUpdateTitle(filter);
893 // Scroll to top after filter is changed.
894 mAllFragment.scrollToTop();
895 }
Wenyi Wang32912eb2016-09-29 17:17:07 -0700896 }
897
898 private void handleFilterChangeForActivity(ContactListFilter filter) {
Marcus Hagerott74295d32016-10-26 10:46:28 -0700899 // The filter was changed while this activity was in the background. If we're in the
900 // assistant view Switch to the main contacts list when we resume to prevent
901 // b/31838582 and b/31829161
902 // TODO: this is a hack; we need to do some cleanup of the contact list filter stuff
903 if (isAssistantView() && filter.isContactsFilterType()) {
Wenyi Wang32912eb2016-09-29 17:17:07 -0700904 mShouldSwitchToAllContacts = true;
905 }
906
Wenyi Wangcfe94652016-10-03 21:05:04 -0700907 // Check menu in navigation drawer.
Wenyi Wang32912eb2016-09-29 17:17:07 -0700908 updateFilterMenu(filter);
909
910 if (CompatUtils.isNCompatible()) {
911 getWindow().getDecorView()
912 .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
913 }
914 invalidateOptionsMenu();
915 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800916}