blob: a8c895671423ebd8d4132662a26578896563465a [file] [log] [blame]
Wenyi Wangbb229242016-05-25 16:04:13 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
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
17package com.android.contacts;
18
19import android.app.FragmentManager;
20import android.app.FragmentTransaction;
21import android.content.Context;
22import android.content.Intent;
23import android.graphics.Color;
24import android.graphics.PorterDuff;
25import android.os.Bundle;
26import android.support.annotation.LayoutRes;
27import android.support.design.widget.NavigationView;
28import android.support.v4.view.GravityCompat;
29import android.support.v4.widget.DrawerLayout;
30import android.support.v7.app.ActionBarDrawerToggle;
31import android.support.v7.app.AppCompatActivity;
32import android.support.v7.widget.Toolbar;
33import android.telecom.TelecomManager;
34import android.util.Log;
35import android.view.LayoutInflater;
36import android.view.Menu;
37import android.view.MenuItem;
38import android.view.SubMenu;
39import android.view.ViewGroup;
40
41import com.android.contacts.common.ContactsUtils;
42import com.android.contacts.common.compat.BlockedNumberContractCompat;
Wenyi Wangbb229242016-05-25 16:04:13 -070043import com.android.contacts.common.compat.TelecomManagerUtil;
44import com.android.contacts.common.list.ContactListFilter;
45import com.android.contacts.common.list.ContactListFilterController;
46import com.android.contacts.common.preference.ContactsPreferenceActivity;
47import com.android.contacts.common.util.AccountFilterUtil;
48import com.android.contacts.common.util.ImplicitIntentsUtil;
49import com.android.contacts.common.util.ViewUtil;
50import com.android.contacts.editor.ContactEditorFragment;
51import com.android.contacts.group.GroupListItem;
Wenyi Wangf8a5ab42016-05-25 16:04:13 -070052import com.android.contacts.group.GroupMetadata;
Wenyi Wangbb229242016-05-25 16:04:13 -070053import com.android.contacts.group.GroupUtil;
54import com.android.contacts.group.GroupsFragment;
55import com.android.contacts.group.GroupsFragment.GroupsListener;
56import com.android.contacts.interactions.AccountFiltersFragment;
57import com.android.contacts.interactions.AccountFiltersFragment.AccountFiltersListener;
58import com.android.contacts.quickcontact.QuickContactActivity;
59import com.android.contacts.util.PhoneCapabilityTester;
60import com.android.contactsbind.Assistants;
61import com.android.contactsbind.HelpUtils;
62
Wenyi Wangf8a5ab42016-05-25 16:04:13 -070063import java.util.HashMap;
64import java.util.Iterator;
Wenyi Wangbb229242016-05-25 16:04:13 -070065import java.util.List;
Wenyi Wangf8a5ab42016-05-25 16:04:13 -070066import java.util.Map;
67import java.util.Map.Entry;
Wenyi Wangbb229242016-05-25 16:04:13 -070068
69/**
70 * A common superclass for Contacts activities with a navigation drawer.
71 */
72public abstract class ContactsDrawerActivity extends AppCompatContactsActivity implements
73 AccountFiltersListener,
74 GroupsListener,
75 NavigationView.OnNavigationItemSelectedListener {
76
77 protected static String TAG = "ContactsDrawerActivity";
78
79 protected static final String GROUPS_TAG = "groups";
80 protected static final String FILTERS_TAG = "filters";
81
82 protected ContactListFilterController mContactListFilterController;
83 protected DrawerLayout mDrawer;
84 protected Toolbar mToolbar;
85 protected NavigationView mNavigationView;
86 protected GroupsFragment mGroupsFragment;
87 protected AccountFiltersFragment mAccountFiltersFragment;
88
Wenyi Wangf8a5ab42016-05-25 16:04:13 -070089 // Checkable menu item lookup maps. Every map declared here should be added to
90 // clearCheckedMenus() so that they can be cleared.
91 // TODO find a better way to handle selected menu item state, when swicthing to fragments.
92 protected Map<Long, MenuItem> mGroupMenuMap = new HashMap<>();
93 protected Map<ContactListFilter, MenuItem> mFilterMenuMap = new HashMap<>();
94 protected Map<Integer, MenuItem> mIdMenuMap = new HashMap<>();
95
Wenyi Wangbb229242016-05-25 16:04:13 -070096 @Override
97 protected void onCreate(Bundle savedState) {
98 super.onCreate(savedState);
99
100 mContactListFilterController = ContactListFilterController.getInstance(this);
101 mContactListFilterController.checkFilterValidity(false);
102
103 super.setContentView(R.layout.contacts_drawer_activity);
104
105 // Set up the action bar.
106 mToolbar = getView(R.id.toolbar);
107 setSupportActionBar(mToolbar);
108
109 // Add shadow under toolbar.
110 ViewUtil.addRectangularOutlineProvider(findViewById(R.id.toolbar_parent), getResources());
111
112 // Set up hamburger button.
113 mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
114 final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mDrawer, mToolbar,
115 R.string.navigation_drawer_open, R.string.navigation_drawer_close);
116 mDrawer.setDrawerListener(toggle);
117 toggle.syncState();
118
119 // Set up hamburger menu items.
120 mNavigationView = (NavigationView) findViewById(R.id.nav_view);
121 mNavigationView.setNavigationItemSelectedListener(this);
122
123 final Menu menu = mNavigationView.getMenu();
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700124
125 final MenuItem allContacts = menu.findItem(R.id.nav_all_contacts);
126 mIdMenuMap.put(R.id.nav_all_contacts, allContacts);
127
Wenyi Wangbb229242016-05-25 16:04:13 -0700128 final boolean showBlockedNumbers = PhoneCapabilityTester.isPhone(this)
129 && ContactsUtils.FLAG_N_FEATURE
130 && BlockedNumberContractCompat.canCurrentUserBlockNumbers(this);
131
132 if (!showBlockedNumbers) {
133 menu.removeItem(R.id.nav_blocked_numbers);
134 }
135
136 if (Assistants.getDuplicatesActivityIntent(this) == null) {
137 menu.removeItem(R.id.nav_find_duplicates);
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700138 } else {
139 final MenuItem findDup = menu.findItem(R.id.nav_find_duplicates);
140 mIdMenuMap.put(R.id.nav_find_duplicates, findDup);
Wenyi Wangbb229242016-05-25 16:04:13 -0700141 }
142
143 if (!HelpUtils.isHelpAndFeedbackAvailable()) {
144 menu.removeItem(R.id.nav_help);
145 }
146
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700147 loadGroupsAndFilters();
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700148
149 if (isDuplicatesActivity()) {
150 clearCheckedMenus();
151 mIdMenuMap.get(R.id.nav_find_duplicates).setCheckable(true);
152 mIdMenuMap.get(R.id.nav_find_duplicates).setChecked(true);
153 }
154 }
155
156 /**
157 * Returns true if child class is DuplicatesActivity
158 */
159 protected boolean isDuplicatesActivity() {
160 return false;
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700161 }
162
163 // Set up fragment manager to load groups and filters.
164 protected void loadGroupsAndFilters() {
Wenyi Wangbb229242016-05-25 16:04:13 -0700165 final FragmentManager fragmentManager = getFragmentManager();
166 final FragmentTransaction transaction = fragmentManager.beginTransaction();
167 addGroupsAndFiltersFragments(transaction);
168 transaction.commitAllowingStateLoss();
169 fragmentManager.executePendingTransactions();
170 }
171
172 @Override
173 public void setContentView(@LayoutRes int layoutResID) {
174 final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
175 if (parent != null) {
176 parent.removeAllViews();
177 }
178 LayoutInflater.from(this).inflate(layoutResID, parent);
179 }
180
181 protected void addGroupsAndFiltersFragments(FragmentTransaction transaction) {
182 final FragmentManager fragmentManager = getFragmentManager();
183 mGroupsFragment = (GroupsFragment) fragmentManager.findFragmentByTag(GROUPS_TAG);
184 mAccountFiltersFragment = (AccountFiltersFragment)
185 fragmentManager.findFragmentByTag(FILTERS_TAG);
186
187 if (mGroupsFragment == null && ContactsUtils.areGroupWritableAccountsAvailable(this)) {
188 mGroupsFragment = new GroupsFragment();
189 transaction.add(mGroupsFragment, GROUPS_TAG);
190 }
191
192 if (mAccountFiltersFragment == null) {
193 mAccountFiltersFragment = new AccountFiltersFragment();
194 transaction.add(mAccountFiltersFragment, FILTERS_TAG);
195 }
196
197 if (ContactsUtils.areGroupWritableAccountsAvailable(this) && mGroupsFragment != null) {
198 mGroupsFragment.setListener(this);
199 }
200 mAccountFiltersFragment.setListener(this);
201 }
202
203 @Override
204 public void onGroupsLoaded(List<GroupListItem> groupListItems) {
205 final Menu menu = mNavigationView.getMenu();
206 final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
207 final SubMenu subMenu = groupsMenuItem.getSubMenu();
208 subMenu.removeGroup(R.id.nav_groups_items);
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700209 mGroupMenuMap = new HashMap<>();
Wenyi Wangbb229242016-05-25 16:04:13 -0700210
211 if (groupListItems != null) {
212 // Add each group
213 for (final GroupListItem groupListItem : groupListItems) {
214 if (GroupUtil.isEmptyFFCGroup(groupListItem)) {
215 continue;
216 }
217 final String title = groupListItem.getTitle();
218 final MenuItem menuItem =
219 subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE, title);
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700220 mGroupMenuMap.put(groupListItem.getGroupId(), menuItem);
Wenyi Wangbb229242016-05-25 16:04:13 -0700221 menuItem.setIcon(R.drawable.ic_menu_label);
222 menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
223 @Override
224 public boolean onMenuItemClick(MenuItem item) {
225 onGroupMenuItemClicked(groupListItem.getGroupId());
226 return true;
227 }
228 });
229 }
230 }
231
Wenyi Wangcb117bd2016-06-17 13:26:57 -0700232 // Don't show "Create new..." menu if there's no group-writable accounts available.
233 if (!ContactsUtils.areGroupWritableAccountsAvailable(this)) {
234 return;
235 }
236
Wenyi Wangbb229242016-05-25 16:04:13 -0700237 // Create a menu item in the sub menu to add new groups
238 final MenuItem menuItem = subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE,
239 getString(R.string.menu_new_group_action_bar));
Wenyi Wang8cd7c5c2016-06-16 14:03:42 -0700240 menuItem.setIcon(R.drawable.ic_add);
Wenyi Wangbb229242016-05-25 16:04:13 -0700241 menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
242 @Override
243 public boolean onMenuItemClick(MenuItem item) {
244 onCreateGroupMenuItemClicked();
245 return true;
246 }
247 });
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700248
249 if (getGroupMetadata() != null) {
250 updateGroupMenu(getGroupMetadata());
251 }
252 }
253
254 protected void updateGroupMenu(GroupMetadata groupMetadata) {
255 clearCheckedMenus();
256 if (groupMetadata != null && mGroupMenuMap != null
257 && mGroupMenuMap.get(groupMetadata.groupId) != null) {
258 mGroupMenuMap.get(groupMetadata.groupId).setCheckable(true);
259 mGroupMenuMap.get(groupMetadata.groupId).setChecked(true);
260 }
261 }
262
263 /**
264 * Returns group metadata if the child class is {@link GroupMembersActivity}, and null
265 * otherwise.
266 */
267 protected GroupMetadata getGroupMetadata() {
268 return null;
Wenyi Wangbb229242016-05-25 16:04:13 -0700269 }
270
271 protected void onGroupMenuItemClicked(long groupId) {
272 final Intent intent = GroupUtil.createViewGroupIntent(this, groupId);
273 startActivity(intent);
274 }
275
276 protected void onCreateGroupMenuItemClicked() {
277 startActivity(GroupUtil.createAddGroupIntent(this));
278 mDrawer.closeDrawer(GravityCompat.START);
279 }
280
281 @Override
282 public void onFiltersLoaded(List<ContactListFilter> accountFilterItems) {
283 final Menu menu = mNavigationView.getMenu();
284 final MenuItem filtersMenuItem = menu.findItem(R.id.nav_filters);
285 final SubMenu subMenu = filtersMenuItem.getSubMenu();
286 subMenu.removeGroup(R.id.nav_filters_items);
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700287 mFilterMenuMap = new HashMap<>();
Wenyi Wangbb229242016-05-25 16:04:13 -0700288
289 if (accountFilterItems == null || accountFilterItems.size() < 2) {
290 return;
291 }
292
293 for (int i = 0; i < accountFilterItems.size(); i++) {
294 final ContactListFilter filter = accountFilterItems.get(i);
295 final String accountName = filter.accountName;
296 final MenuItem menuItem = subMenu.add(R.id.nav_filters_items, Menu.NONE, Menu.NONE,
297 accountName);
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700298 mFilterMenuMap.put(filter, menuItem);
Wenyi Wangbb229242016-05-25 16:04:13 -0700299 final Intent intent = new Intent();
300 intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
301 menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
302 @Override
303 public boolean onMenuItemClick(MenuItem item) {
304 mDrawer.closeDrawer(GravityCompat.START);
305 AccountFilterUtil.handleAccountFilterResult(mContactListFilterController,
306 AppCompatActivity.RESULT_OK, intent);
307 if (shouldFinish()) {
308 finish();
309 }
310 return true;
311 }
312 });
313 menuItem.setIcon(filter.icon);
314 // Get rid of the default memu item overlay and show original account icons.
315 menuItem.getIcon().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
316 }
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700317
318 if (getContactListFilter() != null) {
319 updateFilterMenu(getContactListFilter());
320 }
321 }
322
323 protected void updateFilterMenu(ContactListFilter filter) {
324 clearCheckedMenus();
325 if (filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
326 if (mIdMenuMap != null && mIdMenuMap.get(R.id.nav_all_contacts) != null) {
327 mIdMenuMap.get(R.id.nav_all_contacts).setCheckable(true);
328 mIdMenuMap.get(R.id.nav_all_contacts).setChecked(true);
329 }
330 } else {
331 if (mFilterMenuMap != null && mFilterMenuMap.get(filter) != null) {
332 mFilterMenuMap.get(filter).setCheckable(true);
333 mFilterMenuMap.get(filter).setChecked(true);
334 }
335 }
Wenyi Wangbb229242016-05-25 16:04:13 -0700336 }
337
338 /**
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700339 * Returns the current filter if the child class is {@link PeopleActivity}, and null otherwise.
340 */
341 protected ContactListFilter getContactListFilter() {
342 return null;
343 }
344
345 /**
346 * Returns true if the child activity should finish after launching another activity.
Wenyi Wangbb229242016-05-25 16:04:13 -0700347 */
348 protected abstract boolean shouldFinish();
349
350 @Override
351 public boolean onNavigationItemSelected(MenuItem item) {
352 final int id = item.getItemId();
353
354 if (id == R.id.nav_settings) {
355 startActivity(createPreferenceIntent());
356 } else if (id == R.id.nav_help) {
357 HelpUtils.launchHelpAndFeedbackForMainScreen(this);
358 } else if (id == R.id.nav_all_contacts) {
359 switchToAllContacts();
360 } else if (id == R.id.nav_blocked_numbers) {
361 final Intent intent = TelecomManagerUtil.createManageBlockedNumbersIntent(
362 (TelecomManager) getSystemService(Context.TELECOM_SERVICE));
363 ImplicitIntentsUtil.startActivityInApp(this, intent);
364 } else if (id == R.id.nav_find_duplicates) {
365 launchFindDuplicates();
366 } else if (item.getIntent() != null) {
367 ImplicitIntentsUtil.startActivityInApp(this, item.getIntent());
368 } else {
369 Log.w(TAG, "Unhandled navigation view item selection");
370 }
371
372 mDrawer.closeDrawer(GravityCompat.START);
373 return true;
374 }
375
376 private Intent createPreferenceIntent() {
377 final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
378 intent.putExtra(ContactsPreferenceActivity.EXTRA_NEW_LOCAL_PROFILE,
379 ContactEditorFragment.INTENT_EXTRA_NEW_LOCAL_PROFILE);
380 intent.putExtra(ContactsPreferenceActivity.EXTRA_MODE_FULLY_EXPANDED,
381 QuickContactActivity.MODE_FULLY_EXPANDED);
382 intent.putExtra(ContactsPreferenceActivity.EXTRA_PREVIOUS_SCREEN_TYPE,
383 QuickContactActivity.EXTRA_PREVIOUS_SCREEN_TYPE);
384 return intent;
385 }
386
387 protected void switchToAllContacts() {
388 final Intent intent = new Intent();
389 final ContactListFilter filter = createAllAccountsFilter();
390 intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
391 AccountFilterUtil.handleAccountFilterResult(
392 mContactListFilterController, AppCompatActivity.RESULT_OK, intent);
393 }
394
395 protected void launchFindDuplicates() {
396 ImplicitIntentsUtil.startActivityInAppIfPossible(this,
397 Assistants.getDuplicatesActivityIntent(this));
398 }
399
400 protected ContactListFilter createAllAccountsFilter() {
401 return ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
402 }
403
Wenyi Wangf8a5ab42016-05-25 16:04:13 -0700404 private void clearCheckedMenus() {
405 clearCheckedMenu(mFilterMenuMap);
406 clearCheckedMenu(mGroupMenuMap);
407 clearCheckedMenu(mIdMenuMap);
408 }
409
410 private void clearCheckedMenu(Map<?, MenuItem> map) {
411 final Iterator it = map.entrySet().iterator();
412 while (it.hasNext()) {
413 Entry pair = (Entry)it.next();
414 map.get(pair.getKey()).setCheckable(false);
415 map.get(pair.getKey()).setChecked(false);
416 }
417 }
Wenyi Wangbb229242016-05-25 16:04:13 -0700418}