blob: 5e957e7470ebd83f56a534c18c6227977b7a5762 [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;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070023import android.content.ContentResolver;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070024import android.content.BroadcastReceiver;
Wenyi Wang79675452016-08-17 10:43:28 -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;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070028import android.content.SyncStatusObserver;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070029import android.content.IntentFilter;
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;
Wenyi Wang79675452016-08-17 10:43:28 -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;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070037import android.support.v4.content.LocalBroadcastManager;
Walter Jang758f5652016-04-05 09:29:56 -070038import android.support.v4.view.GravityCompat;
Xi Chen947c23d2016-06-30 20:23:52 -070039import android.support.v4.widget.SwipeRefreshLayout;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070040import android.util.Log;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070041import android.view.Gravity;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070042import 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;
48import android.view.ViewGroup;
Paul Soulos2b9563d2014-05-27 16:21:23 -070049import android.widget.ImageButton;
Jay Shraunerd391f842014-11-26 11:14:24 -080050import android.widget.Toast;
Chiao Chenge0b2f1e2012-06-12 13:07:56 -070051
Cody Thomasf32dc992016-05-11 10:56:04 -070052import com.android.contacts.ContactSaveService;
Wenyi Wangbb229242016-05-25 16:04:13 -070053import com.android.contacts.ContactsDrawerActivity;
Dmitri Plotnikov27834b22010-07-01 14:10:08 -070054import com.android.contacts.R;
Xi Chen947c23d2016-06-30 20:23:52 -070055import com.android.contacts.common.Experiments;
Brian Attwellbdd32642015-05-08 17:03:15 -070056import com.android.contacts.common.activity.RequestPermissionsActivity;
Chiao Cheng051f41d2012-12-04 15:42:42 -080057import com.android.contacts.common.interactions.ImportExportDialogFragment;
Chiao Chenga0233a02012-11-01 16:41:08 -070058import com.android.contacts.common.list.ContactListFilter;
Chiao Chenga0233a02012-11-01 16:41:08 -070059import com.android.contacts.common.list.DirectoryListLoader;
Wenyi Wangbb229242016-05-25 16:04:13 -070060import com.android.contacts.common.list.ProviderStatusWatcher;
61import com.android.contacts.common.list.ProviderStatusWatcher.ProviderStatusListener;
Walter Janga84fe612016-01-13 16:49:04 -080062import com.android.contacts.common.logging.Logger;
Walter Jang62a20742016-02-24 17:04:12 -080063import com.android.contacts.common.logging.ScreenEvent.ScreenType;
Wenyi Wangbf693302016-06-14 12:49:03 -070064import com.android.contacts.common.model.AccountTypeManager;
65import com.android.contacts.common.model.account.AccountWithDataSet;
Wenyi Wang587b8f22016-08-17 17:40:45 -070066import com.android.contacts.common.util.AccountFilterUtil;
guanxiongliuf597ec62016-01-25 19:49:42 -080067import com.android.contacts.common.util.Constants;
guanxiongliu5d7bb262016-01-29 16:43:45 -080068import com.android.contacts.common.util.ImplicitIntentsUtil;
guanxiongliu5d7bb262016-01-29 16:43:45 -080069import com.android.contacts.common.widget.FloatingActionButtonController;
guanxiongliuf597ec62016-01-25 19:49:42 -080070import com.android.contacts.editor.EditorIntents;
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;
guanxiongliuf597ec62016-01-25 19:49:42 -080078import com.android.contacts.list.OnContactsUnavailableActionListener;
Brian Attwell8a6f4ad2014-06-06 21:54:53 -070079import com.android.contacts.quickcontact.QuickContactActivity;
Xi Chen4a7a9ea2016-07-20 11:23:30 -070080import com.android.contacts.util.SyncUtil;
Wenyi Wang79675452016-08-17 10:43:28 -070081import com.android.contactsbind.ObjectFactory;
Walter Jang6367d2a2016-08-15 14:51:18 -070082import com.android.contactsbind.experiments.Flags;
Marcus Hagerottbea2b852016-08-11 14:55:52 -070083import com.android.contacts.widget.FloatingActionButtonBehavior;
Tadashi G. Takaoka57cf30f2009-09-21 19:54:39 +090084
Brian Attwell20510ec2015-02-27 16:10:45 -080085import java.util.List;
Makoto Onuki6d9befe2011-07-17 11:00:12 -070086import java.util.concurrent.atomic.AtomicInteger;
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -070087
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080088/**
Brian Attwell2c1bfd02014-06-04 18:18:35 -070089 * Displays a list to browse contacts.
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -080090 */
Wenyi Wang587b8f22016-08-17 17:40:45 -070091public class PeopleActivity extends ContactsDrawerActivity implements ProviderStatusListener {
Dmitri Plotnikov57d27da2009-09-28 18:06:11 -070092
Dave Santoro5e684a42011-06-10 13:23:35 -070093 private static final String TAG = "PeopleActivity";
Wenyi Wangca6018d2016-08-18 17:23:13 -070094 private static final String TAG_ALL = "contacts-all";
Wenyi Wang79675452016-08-17 10:43:28 -070095 private static final String TAG_UNAVAILABLE = "contacts-unavailable";
Wenyi Wangcc8f2722016-09-07 14:52:32 -070096 private static final String TAG_GROUP_VIEW = "contacts-groups";
Wenyi Wang79675452016-08-17 10:43:28 -070097 private static final String TAG_DUPLICATES = "contacts-duplicates";
Wenyi Wangcc8f2722016-09-07 14:52:32 -070098 private static final String TAG_SECOND_LEVEL = "second-level";
Wenyi Wang79675452016-08-17 10:43:28 -070099 // Tag for DuplicatesUtilFragment.java
100 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
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800111 private ContactsUnavailableFragment mContactsUnavailableFragment;
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.
131 * This is set in {@link #onCreate} for later use in {@link #onStart}.
132 */
133 private boolean mIsRecreatedInstance;
134
135 /**
136 * If {@link #configureFragments(boolean)} is already called. Used to avoid calling it twice
137 * in {@link #onStart}.
138 * (This initialization only needs to be done once in onStart() when the Activity was just
139 * created from scratch -- i.e. onCreate() was just called)
140 */
141 private boolean mFragmentInitialized;
142
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700143 /** Sequential ID assigned to each instance; used for logging */
144 private final int mInstanceId;
145 private static final AtomicInteger sNextInstanceId = new AtomicInteger();
146
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700147 private Object mStatusChangeListenerHandle;
148
149 private final Handler mHandler = new Handler();
150
151 private SyncStatusObserver mSyncStatusObserver = new SyncStatusObserver() {
152 public void onStatusChanged(int which) {
153 mHandler.post(new Runnable() {
154 public void run() {
155 onSyncStateUpdated();
156 }
157 });
158 }
159 };
160
161 // Update sync status for accounts in current ContactListFilter
162 private void onSyncStateUpdated() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700163 if (mAllFragment.getActionBarAdapter().isSearchMode()
164 || mAllFragment.getActionBarAdapter().isSelectionMode()) {
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700165 return;
166 }
167
Wenyi Wang587b8f22016-08-17 17:40:45 -0700168 final ContactListFilter filter = mAllFragment.getFilter();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700169 if (filter != null) {
170 final SwipeRefreshLayout swipeRefreshLayout = mAllFragment.getSwipeRefreshLayout();
171 if (swipeRefreshLayout == null) {
172 if (Log.isLoggable(TAG, Log.DEBUG)) {
173 Log.d(TAG, "Can not load swipeRefreshLayout, swipeRefreshLayout is null");
174 }
175 return;
176 }
177
178 final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(this)
179 .getAccounts(/* contactsWritableOnly */ true);
180 final List<Account> syncableAccounts = filter.getSyncableAccounts(accounts);
181 // If one of the accounts is active or pending, use spinning circle to indicate one of
182 // the syncs is in progress.
183 if (syncableAccounts != null && syncableAccounts.size() > 0) {
184 for (Account account: syncableAccounts) {
Xi Chena455bd52016-07-25 17:00:22 -0700185 if (SyncUtil.isSyncStatusPendingOrActive(account)
186 || SyncUtil.isUnsyncableGoogleAccount(account)) {
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700187 swipeRefreshLayout.setRefreshing(true);
188 return;
189 }
190 }
191 }
192 swipeRefreshLayout.setRefreshing(false);
193 }
194 }
195
Katherine Kuan9856fce2011-06-01 10:24:09 -0700196 public PeopleActivity() {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700197 mInstanceId = sNextInstanceId.getAndIncrement();
Dmitri Plotnikov15406742010-05-07 09:22:49 -0700198 mIntentResolver = new ContactsIntentResolver(this);
Makoto Onukic2bd6132012-04-27 16:14:51 -0700199 mProviderStatusWatcher = ProviderStatusWatcher.getInstance(this);
Dmitri Plotnikov6178cb42010-04-20 11:26:05 -0700200 }
201
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700202 @Override
203 public String toString() {
204 // Shown on logcat
205 return String.format("%s@%d", getClass().getSimpleName(), mInstanceId);
206 }
207
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700208 private boolean areContactsAvailable() {
Wenyi Wang2f09e602015-10-28 11:34:23 -0700209 return (mProviderStatus != null) && mProviderStatus.equals(ProviderStatus.STATUS_NORMAL);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800210 }
211
Makoto Onuki50445e92011-07-12 10:28:12 -0700212 /**
213 * Initialize fragments that are (or may not be) in the layout.
214 *
215 * For the fragments that are in the layout, we initialize them in
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700216 * {@link #createViewsAndFragments()} after inflating the layout.
Makoto Onuki50445e92011-07-12 10:28:12 -0700217 *
Brian Attwell2c1bfd02014-06-04 18:18:35 -0700218 * However, the {@link ContactsUnavailableFragment} is a special fragment which may not
219 * be in the layout, so we have to do the initialization here.
220 *
221 * The ContactsUnavailableFragment is always created at runtime.
Makoto Onuki50445e92011-07-12 10:28:12 -0700222 */
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800223 @Override
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700224 public void onAttachFragment(Fragment fragment) {
Brian Attwell2c1bfd02014-06-04 18:18:35 -0700225 if (fragment instanceof ContactsUnavailableFragment) {
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800226 mContactsUnavailableFragment = (ContactsUnavailableFragment)fragment;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800227 mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
228 new ContactsUnavailableFragmentListener());
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700229 }
230 }
231
232 @Override
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700233 protected void onCreate(Bundle savedState) {
Makoto Onuki49627cc2011-08-28 13:56:48 -0700234 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
235 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate start");
236 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700237 super.onCreate(savedState);
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800238
Brian Attwellbdd32642015-05-08 17:03:15 -0700239 if (RequestPermissionsActivity.startPermissionActivity(this)) {
240 return;
241 }
242
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700243 if (!processIntent(false)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700244 finish();
245 return;
246 }
Daisuke Miyakawaa012aec2011-10-16 10:24:43 -0700247
Makoto Onukic2bd6132012-04-27 16:14:51 -0700248 mProviderStatusWatcher.addListener(this);
249
Makoto Onuki417ca492011-07-14 19:06:35 -0700250 mIsRecreatedInstance = (savedState != null);
Wenyi Wang40e79102016-06-01 20:43:56 -0700251
Wenyi Wang79675452016-08-17 10:43:28 -0700252 if (mIsRecreatedInstance) {
253 mGroupUri = savedState.getParcelable(KEY_GROUP_URI);
254 }
255
Wenyi Wang587b8f22016-08-17 17:40:45 -0700256 createViewsAndFragments();
Andrew Lee4b1af3f2014-04-23 10:23:55 -0700257
Makoto Onuki49627cc2011-08-28 13:56:48 -0700258 if (Log.isLoggable(Constants.PERFORMANCE_TAG, Log.DEBUG)) {
259 Log.d(Constants.PERFORMANCE_TAG, "PeopleActivity.onCreate finish");
260 }
Sai Cheemalapati5b221082014-06-27 14:45:43 -0700261 getWindow().setBackgroundDrawable(null);
Tingting Wangac9596e2016-08-02 22:24:24 -0700262 }
Tingting Wangdce1e682016-07-28 10:06:29 -0700263
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800264 @Override
265 protected void onNewIntent(Intent intent) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700266 if (GroupUtil.ACTION_CREATE_GROUP.equals(intent.getAction())) {
Wenyi Wang79675452016-08-17 10:43:28 -0700267 mGroupUri = intent.getData();
268 if (mGroupUri == null) {
269 toast(R.string.groupSavedErrorToast);
270 return;
271 }
272 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700273 switchToOrUpdateGroupView(intent.getAction());
Walter Jang13710d52016-07-08 14:36:20 -0700274 return;
275 }
276
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700277 if (isGroupDeleteAction(intent.getAction())) {
Wenyi Wang79675452016-08-17 10:43:28 -0700278 toast(R.string.groupDeletedToast);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700279 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700280 mCurrentView = ContactsView.ALL_CONTACTS;
281 showFabWithAnimation(/* showFab */ true);
282 return;
283 }
284
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700285 if (isGroupSaveAction(intent.getAction())) {
286 mGroupUri = intent.getData();
287 if (mGroupUri == null) {
288 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700289 toast(R.string.groupSavedErrorToast);
290 return;
291 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700292 if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "Received group URI " + mGroupUri);
293 switchToOrUpdateGroupView(intent.getAction());
Wenyi Wang79675452016-08-17 10:43:28 -0700294 }
295
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800296 setIntent(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700297
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700298 if (!processIntent(true)) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700299 finish();
300 return;
301 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700302
Wenyi Wang79675452016-08-17 10:43:28 -0700303 mContactListFilterController.checkFilterValidity(false);
304
305 if (!isInSecondLevel()) {
306 // Re-initialize ActionBarAdapter because {@link #onNewIntent(Intent)} doesn't invoke
307 // {@link Fragment#onActivityCreated(Bundle)} where we initialize ActionBarAdapter
308 // initially.
309 mAllFragment.setContactsRequest(mRequest);
310 mAllFragment.initializeActionBarAdapter(null);
311 }
Katherine Kuanbe79b8f2011-11-09 20:54:43 -0800312
Makoto Onuki417ca492011-07-14 19:06:35 -0700313 // Re-configure fragments.
314 configureFragments(true /* from request */);
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700315 initializeFabVisibility();
Makoto Onuki417ca492011-07-14 19:06:35 -0700316 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800317 }
318
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700319 private static boolean isGroupDeleteAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700320 return GroupUtil.ACTION_DELETE_GROUP.equals(action);
321 }
322
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700323 private static boolean isGroupSaveAction(String action) {
Wenyi Wang79675452016-08-17 10:43:28 -0700324 return GroupUtil.ACTION_UPDATE_GROUP.equals(action)
325 || GroupUtil.ACTION_ADD_TO_GROUP.equals(action)
326 || GroupUtil.ACTION_REMOVE_FROM_GROUP.equals(action);
327 }
328
Wenyi Wang79675452016-08-17 10:43:28 -0700329 private void toast(int resId) {
330 if (resId >= 0) {
331 Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
332 }
333 }
334
Makoto Onuki417ca492011-07-14 19:06:35 -0700335 /**
336 * Resolve the intent and initialize {@link #mRequest}, and launch another activity if redirect
337 * is needed.
338 *
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700339 * @param forNewIntent set true if it's called from {@link #onNewIntent(Intent)}.
Makoto Onuki417ca492011-07-14 19:06:35 -0700340 * @return {@code true} if {@link PeopleActivity} should continue running. {@code false}
341 * if it shouldn't, in which case the caller should finish() itself and shouldn't do
342 * farther initialization.
343 */
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700344 private boolean processIntent(boolean forNewIntent) {
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700345 // Extract relevant information from the intent
346 mRequest = mIntentResolver.resolveIntent(getIntent());
Makoto Onukiea146052011-07-25 10:34:15 -0700347 if (Log.isLoggable(TAG, Log.DEBUG)) {
Makoto Onuki6d9befe2011-07-17 11:00:12 -0700348 Log.d(TAG, this + " processIntent: forNewIntent=" + forNewIntent
349 + " intent=" + getIntent() + " request=" + mRequest);
350 }
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700351 if (!mRequest.isValid()) {
352 setResult(RESULT_CANCELED);
Makoto Onuki417ca492011-07-14 19:06:35 -0700353 return false;
Dmitri Plotnikov59fb48e2010-04-26 17:09:19 -0700354 }
355
Walter Jang1110d672016-07-25 17:55:12 +0000356 switch (mRequest.getActionCode()) {
357 case ContactsRequest.ACTION_VIEW_CONTACT: {
358 final Intent intent = ImplicitIntentsUtil.composeQuickContactIntent(
John Shao41c68862016-08-17 21:02:41 -0700359 PeopleActivity.this, mRequest.getContactUri(),
360 QuickContactActivity.MODE_FULLY_EXPANDED);
Walter Jang1110d672016-07-25 17:55:12 +0000361 intent.putExtra(QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE, ScreenType.UNKNOWN);
362 ImplicitIntentsUtil.startActivityInApp(this, intent);
363 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 Wangcc8f2722016-09-07 14:52:32 -0700385 if (isGroupView()) {
Wenyi Wang79675452016-08-17 10:43:28 -0700386 mMembersFragment = (GroupMembersFragment)
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700387 fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700388 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700389
Brian Attwell865847b2015-04-20 14:40:17 -0700390 // Configure floating action button
391 mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
392 final ImageButton floatingActionButton
393 = (ImageButton) findViewById(R.id.floating_action_button);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700394 floatingActionButton.setOnClickListener(new View.OnClickListener() {
395 @Override
396 public void onClick(View v) {
Wenyi Wang79675452016-08-17 10:43:28 -0700397 AccountFilterUtil.startEditorIntent(PeopleActivity.this, getIntent(),
398 mContactListFilterController.getFilter());
Wenyi Wang587b8f22016-08-17 17:40:45 -0700399 }
400 });
Brian Attwell865847b2015-04-20 14:40:17 -0700401 mFloatingActionButtonController = new FloatingActionButtonController(this,
402 mFloatingActionButtonContainer, floatingActionButton);
Paul Soulos2b9563d2014-05-27 16:21:23 -0700403
Makoto Onuki417ca492011-07-14 19:06:35 -0700404 invalidateOptionsMenuIfNeeded();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700405
406 mLayoutRoot = (CoordinatorLayout) findViewById(R.id.root);
407
408 // Setup the FAB to animate upwards when a snackbar is shown in this activity.
409 // Normally the layout_behavior attribute could be used for this but for some reason it
410 // throws a ClassNotFoundException so the layout parameters are set programmatically.
411 final CoordinatorLayout.LayoutParams fabParams = new CoordinatorLayout.LayoutParams(
412 (ViewGroup.MarginLayoutParams) mFloatingActionButtonContainer.getLayoutParams());
413 fabParams.setBehavior(new FloatingActionButtonBehavior());
414 fabParams.gravity = Gravity.BOTTOM | Gravity.END;
415 mFloatingActionButtonContainer.setLayoutParams(fabParams);
Wenyi Wang79675452016-08-17 10:43:28 -0700416
417 if (mShouldSwitchToGroupView && !mIsRecreatedInstance) {
418 mGroupUri = mRequest.getContactUri();
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700419 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700420 mShouldSwitchToGroupView = false;
421 }
422 }
423
424 private void setUpAllFragment(FragmentManager fragmentManager) {
425 mAllFragment = (DefaultContactBrowseListFragment)
426 fragmentManager.findFragmentByTag(TAG_ALL);
427
428 if (mAllFragment == null) {
429 mAllFragment = new DefaultContactBrowseListFragment();
430 mAllFragment.setAnimateOnLoad(true);
431 fragmentManager.beginTransaction()
432 .add(R.id.contacts_list_container, mAllFragment, TAG_ALL)
433 .commit();
434 fragmentManager.executePendingTransactions();
435 }
436
437 mAllFragment.setContactsAvailable(areContactsAvailable());
438 mAllFragment.setListType();
439 mAllFragment.setContactsRequest(mRequest);
Makoto Onuki417ca492011-07-14 19:06:35 -0700440 }
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800441
Makoto Onuki417ca492011-07-14 19:06:35 -0700442 @Override
443 protected void onStart() {
Wenyi Wang79675452016-08-17 10:43:28 -0700444 if (!mFragmentInitialized && (!isInSecondLevel())) {
Makoto Onuki417ca492011-07-14 19:06:35 -0700445 mFragmentInitialized = true;
446 /* Configure fragments if we haven't.
447 *
448 * Note it's a one-shot initialization, so we want to do this in {@link #onCreate}.
449 *
450 * However, because this method may indirectly touch views in fragments but fragments
451 * created in {@link #configureContentView} using a {@link FragmentTransaction} will NOT
452 * have views until {@link Activity#onCreate} finishes (they would if they were inflated
453 * from a layout), we need to do it here in {@link #onStart()}.
454 *
455 * (When {@link Fragment#onCreateView} is called is different in the former case and
456 * in the latter case, unfortunately.)
457 *
458 * Also, we skip most of the work in it if the activity is a re-created one.
459 * (so the argument.)
460 */
461 configureFragments(!mIsRecreatedInstance);
Dmitri Plotnikovfe42e552010-05-14 14:50:32 -0700462 }
Makoto Onuki417ca492011-07-14 19:06:35 -0700463 super.onStart();
Dmitri Plotnikovcaf0bc72010-09-03 15:16:21 -0700464 }
465
Dmitri Plotnikov6e850a02010-10-28 10:46:21 -0700466 @Override
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700467 protected void onPause() {
Makoto Onukic2bd6132012-04-27 16:14:51 -0700468 mProviderStatusWatcher.stop();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700469
470 LocalBroadcastManager.getInstance(this).unregisterReceiver(mSaveServiceListener);
471
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700472 super.onPause();
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700473
474 if (Flags.getInstance(this).getBoolean(Experiments.PULL_TO_REFRESH)) {
475 ContentResolver.removeStatusChangeListener(mStatusChangeListenerHandle);
476 onSyncStateUpdated();
477 }
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700478 }
479
480 @Override
481 protected void onResume() {
482 super.onResume();
Josh Gargus697ab262012-05-04 11:11:34 -0700483
Makoto Onukic2bd6132012-04-27 16:14:51 -0700484 mProviderStatusWatcher.start();
Josh Gargus697ab262012-05-04 11:11:34 -0700485 updateViewConfiguration(true);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700486
Xi Chen4a7a9ea2016-07-20 11:23:30 -0700487 if (Flags.getInstance(this).getBoolean(Experiments.PULL_TO_REFRESH)) {
488 mStatusChangeListenerHandle = ContentResolver.addStatusChangeListener(
489 ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE
490 | ContentResolver.SYNC_OBSERVER_TYPE_PENDING
491 | ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS,
492 mSyncStatusObserver);
493 onSyncStateUpdated();
494 }
Wenyi Wang79675452016-08-17 10:43:28 -0700495 if (!isInSecondLevel()) {
496 mAllFragment.maybeShowHamburgerFeatureHighlight();
497 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700498 initializeFabVisibility();
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700499
500 mSaveServiceListener = new SaveServiceListener();
501 LocalBroadcastManager.getInstance(this).registerReceiver(mSaveServiceListener,
502 new IntentFilter(ContactSaveService.BROADCAST_ACTION_GROUP_DELETED));
Dmitri Plotnikov174fdc22010-10-29 13:55:01 -0700503 }
504
505 @Override
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700506 protected void onDestroy() {
Makoto Onukic2bd6132012-04-27 16:14:51 -0700507 mProviderStatusWatcher.removeListener(this);
Makoto Onuki4d788fc2011-07-12 10:00:10 -0700508 super.onDestroy();
509 }
510
Dmitri Plotnikov955846e2010-11-11 22:31:28 -0800511 private void configureFragments(boolean fromRequest) {
Dmitri Plotnikov009676f2010-10-08 12:13:57 -0700512 if (fromRequest) {
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700513 ContactListFilter filter = null;
514 int actionCode = mRequest.getActionCode();
Makoto Onuki53b427b2011-07-17 11:42:32 -0700515 boolean searchMode = mRequest.isSearchMode();
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700516 switch (actionCode) {
517 case ContactsRequest.ACTION_ALL_CONTACTS:
Wenyi Wang587b8f22016-08-17 17:40:45 -0700518 filter = AccountFilterUtil.createContactsFilter(this);
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700519 break;
520 case ContactsRequest.ACTION_CONTACTS_WITH_PHONES:
Katherine Kuanbe18de02011-06-07 12:38:29 -0700521 filter = ContactListFilter.createFilterWithType(
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700522 ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY);
523 break;
524
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700525 case ContactsRequest.ACTION_FREQUENT:
526 case ContactsRequest.ACTION_STREQUENT:
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700527 case ContactsRequest.ACTION_STARRED:
Frank Sposaro9e095d22011-07-07 15:18:38 -0700528 case ContactsRequest.ACTION_VIEW_CONTACT:
Daniel Lehmann52aa32d2012-03-08 17:29:27 -0800529 default:
Daniel Lehmann52aa32d2012-03-08 17:29:27 -0800530 break;
Makoto Onukiea146052011-07-25 10:34:15 -0700531 }
Dmitri Plotnikov91ab5b42010-10-08 15:26:31 -0700532
533 if (filter != null) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700534 mAllFragment.setContactListFilter(filter);
Makoto Onuki53b427b2011-07-17 11:42:32 -0700535 searchMode = false;
Dmitri Plotnikov009676f2010-10-08 12:13:57 -0700536 }
Dmitri Plotnikovd9591042010-11-23 09:25:03 -0800537
538 if (mRequest.getContactUri() != null) {
Makoto Onuki53b427b2011-07-17 11:42:32 -0700539 searchMode = false;
Dmitri Plotnikovd9591042010-11-23 09:25:03 -0800540 }
541
Wenyi Wang79675452016-08-17 10:43:28 -0700542 if (!isInSecondLevel()) {
543 mAllFragment.getActionBarAdapter().setSearchMode(searchMode);
544 configureContactListFragmentForRequest();
545 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700546 }
547
Wenyi Wang79675452016-08-17 10:43:28 -0700548 if (!isInSecondLevel()) {
549 mAllFragment.configureContactListFragment();
550 }
Dmitri Plotnikov92a6fdf2010-07-09 13:19:33 -0700551 }
552
Brian Attwell865847b2015-04-20 14:40:17 -0700553 private void initializeFabVisibility() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700554 mFloatingActionButtonContainer.setVisibility(shouldHideFab() ? View.GONE : View.VISIBLE);
Brian Attwell9cfa24c2015-05-04 12:31:37 -0700555 mFloatingActionButtonController.resetIn();
Wenyi Wang587b8f22016-08-17 17:40:45 -0700556 wasLastFabAnimationScaleIn = !shouldHideFab();
Brian Attwell865847b2015-04-20 14:40:17 -0700557 }
558
Wenyi Wang587b8f22016-08-17 17:40:45 -0700559 private boolean shouldHideFab() {
Wenyi Wang79675452016-08-17 10:43:28 -0700560 if (mAllFragment != null && mAllFragment.getActionBarAdapter() == null
561 || isInSecondLevel()) {
562 return true;
563 }
Wenyi Wang587b8f22016-08-17 17:40:45 -0700564 return mAllFragment.getActionBarAdapter().isSearchMode()
565 || mAllFragment.getActionBarAdapter().isSelectionMode();
Wenyi Wangbf693302016-06-14 12:49:03 -0700566 }
567
Wenyi Wang587b8f22016-08-17 17:40:45 -0700568 public void showFabWithAnimation(boolean showFab) {
Brian Attwell865847b2015-04-20 14:40:17 -0700569 if (mFloatingActionButtonContainer == null) {
570 return;
571 }
572 if (showFab) {
573 if (!wasLastFabAnimationScaleIn) {
574 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
575 mFloatingActionButtonController.scaleIn(0);
576 }
577 wasLastFabAnimationScaleIn = true;
578
579 } else {
580 if (wasLastFabAnimationScaleIn) {
581 mFloatingActionButtonContainer.setVisibility(View.VISIBLE);
582 mFloatingActionButtonController.scaleOut();
583 }
584 wasLastFabAnimationScaleIn = false;
585 }
586 }
587
Makoto Onuki1db00f62011-10-19 12:40:12 -0700588 private void setQueryTextToFragment(String query) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700589 mAllFragment.setQueryString(query, true);
Makoto Onuki1db00f62011-10-19 12:40:12 -0700590 mAllFragment.setVisibleScrollbarEnabled(!mAllFragment.isSearchMode());
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700591 }
592
Katherine Kuan0ff0e312011-06-08 17:43:51 -0700593 private void configureContactListFragmentForRequest() {
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800594 Uri contactUri = mRequest.getContactUri();
595 if (contactUri != null) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700596 mAllFragment.setSelectedContactUri(contactUri);
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800597 }
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700598
Wenyi Wang587b8f22016-08-17 17:40:45 -0700599 setQueryTextToFragment(mAllFragment.getActionBarAdapter().getQueryString());
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700600
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800601 if (mRequest.isDirectorySearchEnabled()) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700602 mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800603 } else {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700604 mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
Dmitri Plotnikovfa49a662011-01-13 11:04:56 -0800605 }
Dmitri Plotnikov08e1c4e2010-07-02 17:57:51 -0700606 }
607
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800608 @Override
609 public void onProviderStatusChange() {
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700610 reloadGroupsAndFiltersIfNeeded();
Josh Gargus697ab262012-05-04 11:11:34 -0700611 updateViewConfiguration(false);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800612 }
613
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700614 private void reloadGroupsAndFiltersIfNeeded() {
615 final int providerStatus = mProviderStatusWatcher.getProviderStatus();
616 final Menu menu = mNavigationView.getMenu();
617 final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
618 final SubMenu subMenu = groupsMenuItem.getSubMenu();
619
620 // Reload groups and filters if provider status changes to "normal" and there's no groups
621 // loaded or just a "Create new..." menu item is in the menu.
622 if (subMenu != null && subMenu.size() <= 1 && providerStatus == ProviderStatus.STATUS_NORMAL
623 && !mProviderStatus.equals(providerStatus)) {
624 loadGroupsAndFilters();
625 }
626 }
627
Josh Gargus697ab262012-05-04 11:11:34 -0700628 private void updateViewConfiguration(boolean forceUpdate) {
Brian Attwellc3d202c2015-01-08 15:01:03 -0800629 int providerStatus = mProviderStatusWatcher.getProviderStatus();
Makoto Onukid8fa7162012-05-16 13:45:48 -0700630 if (!forceUpdate && (mProviderStatus != null)
Brian Attwellc3d202c2015-01-08 15:01:03 -0800631 && (mProviderStatus.equals(providerStatus))) return;
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800632 mProviderStatus = providerStatus;
633
Wenyi Wang79675452016-08-17 10:43:28 -0700634 final FragmentManager fragmentManager= getFragmentManager();
635 final FragmentTransaction transaction = fragmentManager.beginTransaction();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800636
Wenyi Wangf128ea82016-07-25 11:56:40 -0700637 // Change in CP2's provider status may not take effect immediately, see b/30566908.
638 // So we need to handle the case where provider status is STATUS_EMPTY and there is
639 // actually at least one real account (not "local" account) on device.
Wenyi Wang79675452016-08-17 10:43:28 -0700640 if (shouldShowList()) {
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700641 if (mAllFragment != null) {
Wenyi Wang79675452016-08-17 10:43:28 -0700642 transaction.show(mAllFragment);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700643 mAllFragment.setContactsAvailable(areContactsAvailable());
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700644 mAllFragment.setEnabled(true);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800645 }
Wenyi Wang79675452016-08-17 10:43:28 -0700646 if (mContactsUnavailableFragment != null) {
647 transaction.hide(mContactsUnavailableFragment);
648 }
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800649 } else {
guanxiongliu5d7bb262016-01-29 16:43:45 -0800650 // Setting up the page so that the user can still use the app
651 // even without an account.
Daisuke Miyakawa95c5c2a2011-07-08 10:33:21 -0700652 if (mAllFragment != null) {
653 mAllFragment.setEnabled(false);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700654 transaction.hide(mAllFragment);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800655 }
656 if (mContactsUnavailableFragment == null) {
657 mContactsUnavailableFragment = new ContactsUnavailableFragment();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800658 mContactsUnavailableFragment.setOnContactsUnavailableActionListener(
659 new ContactsUnavailableFragmentListener());
Wenyi Wang79675452016-08-17 10:43:28 -0700660 transaction.add(R.id.contacts_list_container, mContactsUnavailableFragment,
661 TAG_UNAVAILABLE);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800662 }
Wenyi Wang79675452016-08-17 10:43:28 -0700663 transaction.show(mContactsUnavailableFragment);
Makoto Onukid8fa7162012-05-16 13:45:48 -0700664 mContactsUnavailableFragment.updateStatus(mProviderStatus);
Wenyi Wang79675452016-08-17 10:43:28 -0700665 }
666 if (!transaction.isEmpty()) {
667 transaction.commit();
668 fragmentManager.executePendingTransactions();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800669 }
670
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700671 invalidateOptionsMenuIfNeeded();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800672 }
673
Wenyi Wang79675452016-08-17 10:43:28 -0700674 private boolean shouldShowList() {
675 return mProviderStatus != null
676 && ((mProviderStatus.equals(ProviderStatus.STATUS_EMPTY) && hasNonLocalAccount())
677 || mProviderStatus.equals(ProviderStatus.STATUS_NORMAL));
678 }
679
Wenyi Wangf128ea82016-07-25 11:56:40 -0700680 // Returns true if there are real accounts (not "local" account) in the list of accounts.
681 private boolean hasNonLocalAccount() {
682 final List<AccountWithDataSet> allAccounts =
683 AccountTypeManager.getInstance(this).getAccounts(/* contactWritableOnly */ false);
684 if (allAccounts == null || allAccounts.size() == 0) {
685 return false;
686 }
687 if (allAccounts.size() > 1) {
688 return true;
689 }
690 return !allAccounts.get(0).isLocalAccount();
691 }
692
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800693 private class ContactsUnavailableFragmentListener
694 implements OnContactsUnavailableActionListener {
Chiao Cheng70f77ea2012-05-31 13:33:58 -0700695 ContactsUnavailableFragmentListener() {}
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800696
697 @Override
698 public void onCreateNewContactAction() {
Brian Attwellc6100ff2015-02-19 21:35:36 -0800699 ImplicitIntentsUtil.startActivityInApp(PeopleActivity.this,
John Shao41c68862016-08-17 21:02:41 -0700700 EditorIntents.createCompactInsertContactIntent(PeopleActivity.this));
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800701 }
702
703 @Override
704 public void onAddAccountAction() {
Walter Jang5e19c232016-07-14 12:38:04 -0700705 final Intent intent = ImplicitIntentsUtil.getIntentForAddingGoogleAccount();
Brian Attwellc6100ff2015-02-19 21:35:36 -0800706 ImplicitIntentsUtil.startActivityOutsideApp(PeopleActivity.this, intent);
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800707 }
708
709 @Override
710 public void onImportContactsFromFileAction() {
Wenyi Wang9379f4a2015-09-25 10:30:19 -0700711 showImportExportDialogFragment();
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800712 }
Dmitri Plotnikov8b826462010-11-17 14:52:24 -0800713 }
714
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700715 private void invalidateOptionsMenuIfNeeded() {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700716 if (mAllFragment != null
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700717 && mAllFragment.getOptionsMenuContactsAvailable() != areContactsAvailable()) {
Katherine Kuan8268bbe2011-06-10 17:48:21 -0700718 invalidateOptionsMenu();
Dmitri Plotnikov0cd01302010-12-17 18:41:57 -0800719 }
720 }
721
Wenyi Wang9379f4a2015-09-25 10:30:19 -0700722 private void showImportExportDialogFragment(){
Wenyi Wang46203dc2016-04-13 10:24:10 -0700723 ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
724 PeopleActivity.class, ImportExportDialogFragment.EXPORT_MODE_ALL_CONTACTS);
Wenyi Wang9379f4a2015-09-25 10:30:19 -0700725 }
726
Dmitri Plotnikov8e86b752010-02-22 17:47:57 -0800727 @Override
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800728 public boolean onKeyDown(int keyCode, KeyEvent event) {
Dmitri Plotnikov1ce1e7c2010-05-13 16:41:00 -0700729 // TODO move to the fragment
Dmitri Plotnikovdb3d1432010-02-09 17:45:47 -0800730
Brian Attwell20510ec2015-02-27 16:10:45 -0800731 // Bring up the search UI if the user starts typing
732 final int unicodeChar = event.getUnicodeChar();
733 if ((unicodeChar != 0)
734 // If COMBINING_ACCENT is set, it's not a unicode character.
735 && ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) == 0)
736 && !Character.isWhitespace(unicodeChar)) {
Wenyi Wang587b8f22016-08-17 17:40:45 -0700737 if (mAllFragment.getActionBarAdapter().isSelectionMode()) {
Brian Attwell20510ec2015-02-27 16:10:45 -0800738 // Ignore keyboard input when in selection mode.
739 return true;
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800740 }
Brian Attwell20510ec2015-02-27 16:10:45 -0800741 String query = new String(new int[]{unicodeChar}, 0, 1);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700742 if (!mAllFragment.getActionBarAdapter().isSearchMode()) {
743 mAllFragment.getActionBarAdapter().setSearchMode(true);
744 mAllFragment.getActionBarAdapter().setQueryString(query);
Brian Attwell20510ec2015-02-27 16:10:45 -0800745 return true;
Daniel Lehmann7bb2add2010-07-14 21:15:17 -0700746 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800747 }
748
749 return super.onKeyDown(keyCode, event);
750 }
751
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700752 @Override
753 public void onBackPressed() {
Jay Shrauner7712aef2015-09-25 14:14:28 -0700754 if (!isSafeToCommitTransactions()) {
Jay Shraunerc3fdc8f2015-09-16 10:29:52 -0700755 return;
756 }
757
Wenyi Wangbb229242016-05-25 16:04:13 -0700758 if (mDrawer.isDrawerOpen(GravityCompat.START)) {
759 mDrawer.closeDrawer(GravityCompat.START);
Wenyi Wang79675452016-08-17 10:43:28 -0700760 } else if (isGroupView()) {
761 if (mMembersFragment.isEditMode()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700762 mMembersFragment.exitEditMode();
Wenyi Wang79675452016-08-17 10:43:28 -0700763 } else if (mMembersFragment.getActionBarAdapter().isSelectionMode()) {
764 mMembersFragment.getActionBarAdapter().setSelectionMode(false);
765 mMembersFragment.displayCheckBoxes(false);
766 } else if (mMembersFragment.getActionBarAdapter().isSearchMode()) {
767 mMembersFragment.getActionBarAdapter().setSearchMode(false);
768 } else {
769 switchToAllContacts();
770 }
771 } else if (isDuplicatesView()) {
772 switchToAllContacts();
Wenyi Wang587b8f22016-08-17 17:40:45 -0700773 } else if (mAllFragment.getActionBarAdapter().isSelectionMode()) {
774 mAllFragment.getActionBarAdapter().setSelectionMode(false);
Brian Attwell20510ec2015-02-27 16:10:45 -0800775 mAllFragment.displayCheckBoxes(false);
Wenyi Wang587b8f22016-08-17 17:40:45 -0700776 } else if (mAllFragment.getActionBarAdapter().isSearchMode()) {
777 mAllFragment.getActionBarAdapter().setSearchMode(false);
Walter Janga84fe612016-01-13 16:49:04 -0800778 if (mAllFragment.wasSearchResultClicked()) {
779 mAllFragment.resetSearchResultClicked();
780 } else {
Walter Jang62a20742016-02-24 17:04:12 -0800781 Logger.logScreenView(this, ScreenType.SEARCH_EXIT);
Walter Jang82c90332016-02-24 17:34:34 -0800782 Logger.logSearchEvent(mAllFragment.createSearchState());
Walter Janga84fe612016-01-13 16:49:04 -0800783 }
Wenyi Wang79675452016-08-17 10:43:28 -0700784 } else if (!AccountFilterUtil.isAllContactsFilter(mAllFragment.getFilter())
785 && !mAllFragment.isHidden()) {
786 // If mAllFragment is hidden, then mContactsUnavailableFragment is visible so we
787 // don't need to switch to all contacts.
Wenyi Wang40e79102016-06-01 20:43:56 -0700788 switchToAllContacts();
Dmitri Plotnikovab4d29f2010-10-28 12:43:54 -0700789 } else {
790 super.onBackPressed();
791 }
792 }
793
Wenyi Wang79675452016-08-17 10:43:28 -0700794 @Override
795 protected void onSaveInstanceState(Bundle outState) {
796 super.onSaveInstanceState(outState);
797 outState.putParcelable(KEY_GROUP_URI, mGroupUri);
Tingting Wang2dc340c2016-07-05 22:31:58 -0700798 }
799
Wenyi Wangbb229242016-05-25 16:04:13 -0700800 @Override
Wenyi Wang79675452016-08-17 10:43:28 -0700801 protected void onRestoreInstanceState(Bundle savedInstanceState) {
802 super.onRestoreInstanceState(savedInstanceState);
803 mGroupUri = savedInstanceState.getParcelable(KEY_GROUP_URI);
Tingting Wang1243cb42016-08-05 16:42:21 -0700804 }
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700805
806 private void onGroupDeleted(Intent intent) {
Marcus Hagerott3c1153f2016-09-07 09:15:14 -0700807 if (!ContactSaveService.canUndo(intent)) return;
808
Marcus Hagerottbea2b852016-08-11 14:55:52 -0700809 Snackbar.make(mLayoutRoot, getString(R.string.groupDeletedToast), Snackbar.LENGTH_LONG)
810 .setAction(R.string.undo, new View.OnClickListener() {
811 @Override
812 public void onClick(View v) {
813 ContactSaveService.startService(PeopleActivity.this,
814 ContactSaveService.createUndoIntent(PeopleActivity.this, intent));
815 }
816 }).show();
817 }
818
819
820 private class SaveServiceListener extends BroadcastReceiver {
821 @Override
822 public void onReceive(Context context, Intent intent) {
823 switch (intent.getAction()) {
824 case ContactSaveService.BROADCAST_ACTION_GROUP_DELETED:
825 onGroupDeleted(intent);
826 break;
827 }
828 }
829 }
Wenyi Wang79675452016-08-17 10:43:28 -0700830
831 @Override
832 protected void onGroupMenuItemClicked(long groupId, String title) {
833 if (isGroupView() && mMembersFragment != null
834 && mMembersFragment.isCurrentGroup(groupId)) {
835 return;
836 }
837 mGroupUri = ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupId);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700838 switchToOrUpdateGroupView(GroupUtil.ACTION_SWITCH_GROUP);
Wenyi Wang79675452016-08-17 10:43:28 -0700839 }
840
841 @Override
842 protected void onFilterMenuItemClicked(Intent intent) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700843 // We must pop second level first to "restart" mAllFragment, before changing filter.
Wenyi Wang79675452016-08-17 10:43:28 -0700844 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700845 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700846 showFabWithAnimation(/* showFab */ true);
847 }
848 mCurrentView = ContactsView.ACCOUNT_VIEW;
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700849 super.onFilterMenuItemClicked(intent);
Wenyi Wang79675452016-08-17 10:43:28 -0700850 }
851
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700852 private void switchToOrUpdateGroupView(String action) {
853 if (mMembersFragment != null) {
854 mCurrentView = ContactsView.GROUP_VIEW;
855 mMembersFragment.updateDisplayedGroup(mGroupUri, action);
856 } else {
857 switchView(ContactsView.GROUP_VIEW);
858 }
Wenyi Wang79675452016-08-17 10:43:28 -0700859 }
860
861 @Override
862 protected void launchFindDuplicates() {
863 switchView(ContactsView.DUPLICATES);
864 }
865
866 private void switchView(ContactsView contactsView) {
Wenyi Wang79675452016-08-17 10:43:28 -0700867 mCurrentView = contactsView;
868 setUpNewFragment();
869 }
870
Wenyi Wang79675452016-08-17 10:43:28 -0700871 private void setUpNewFragment() {
872 final FragmentManager fragmentManager = getFragmentManager();
873 final FragmentTransaction transaction = fragmentManager.beginTransaction();
874 if (isGroupView()) {
875 mMembersFragment = GroupMembersFragment.newInstance(mGroupUri);
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700876 transaction.replace(
877 R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
Wenyi Wang79675452016-08-17 10:43:28 -0700878 } else if (isDuplicatesView()) {
879 final Fragment duplicatesFragment = ObjectFactory.getDuplicatesFragment();
880 final Fragment duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700881 if (duplicatesFragment != null && duplicatesUtilFragment != null) {
882 duplicatesUtilFragment.setTargetFragment(duplicatesFragment, /* requestCode */ 0);
883 transaction.replace(
884 R.id.contacts_list_container, duplicatesFragment, TAG_DUPLICATES);
885 transaction.add(duplicatesUtilFragment, TAG_DUPLICATES_UTIL);
886 }
Wenyi Wang79675452016-08-17 10:43:28 -0700887 }
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700888 transaction.addToBackStack(TAG_SECOND_LEVEL);
Wenyi Wang79675452016-08-17 10:43:28 -0700889 transaction.commit();
890 fragmentManager.executePendingTransactions();
891
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700892 resetFilter();
Wenyi Wang79675452016-08-17 10:43:28 -0700893 showFabWithAnimation(/* showFab */ false);
894 }
895
896 @Override
897 public void switchToAllContacts() {
Wenyi Wang79675452016-08-17 10:43:28 -0700898 if (isInSecondLevel()) {
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700899 popSecondLevel();
Wenyi Wang79675452016-08-17 10:43:28 -0700900 }
901 mCurrentView = ContactsView.ALL_CONTACTS;
902 showFabWithAnimation(/* showFab */ true);
903
904 super.switchToAllContacts();
905 }
906
Wenyi Wangcc8f2722016-09-07 14:52:32 -0700907 private void popSecondLevel() {
908 getFragmentManager().popBackStackImmediate(
909 TAG_SECOND_LEVEL, FragmentManager.POP_BACK_STACK_INCLUSIVE);
910 mMembersFragment = null;
911 }
912
Wenyi Wang79675452016-08-17 10:43:28 -0700913 @Override
914 protected DefaultContactBrowseListFragment getAllFragment() {
915 return mAllFragment;
916 }
917
918 @Override
919 protected GroupMembersFragment getGroupFragment() {
920 return mMembersFragment;
921 }
922
923 @Override
Walter Jang5a496962016-09-09 18:32:50 -0700924 protected GroupMetaData getGroupMetaData() {
925 return mMembersFragment == null ? null : mMembersFragment.getGroupMetaData();
Wenyi Wang79675452016-08-17 10:43:28 -0700926 }
The Android Open Source Project7aa0e4c2009-03-03 19:32:21 -0800927}