summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Jang <wjang@google.com>2016-04-05 09:29:56 -0700
committerWalter Jang <wjang@google.com>2016-04-05 13:32:28 -0700
commit758f56580b973894213569b61b1ae23b293071c2 (patch)
tree5260b0b91547a3c578bdafac9ffa8736535e8b6e
parentf568b30b5a4b009e10a8b97117f5c720bbfab43d (diff)
downloadpackages_apps_Contacts-758f56580b973894213569b61b1ae23b293071c2.tar.gz
packages_apps_Contacts-758f56580b973894213569b61b1ae23b293071c2.tar.bz2
packages_apps_Contacts-758f56580b973894213569b61b1ae23b293071c2.zip
Add groups to the side navigation bar
Just launch the old group details Activity for now. Bug 18641067 Change-Id: I213c88213240d5281edfeda1bc5da9180506520b
-rw-r--r--res/values/ids.xml3
-rw-r--r--res/values/strings.xml5
-rw-r--r--src/com/android/contacts/activities/PeopleActivity.java69
-rw-r--r--src/com/android/contacts/group/GroupBrowseListAdapter.java40
-rw-r--r--src/com/android/contacts/group/GroupUtil.java82
-rw-r--r--src/com/android/contacts/group/GroupsFragment.java103
6 files changed, 250 insertions, 52 deletions
diff --git a/res/values/ids.xml b/res/values/ids.xml
index 7f6a51fcc..efc45fc65 100644
--- a/res/values/ids.xml
+++ b/res/values/ids.xml
@@ -43,4 +43,7 @@
<!-- An ID to be used for contents of a custom dialog so that its state be preserved -->
<item type="id" name="custom_dialog_content" />
+
+ <!-- Menu group ID for the contact groups -->
+ <item type="id" name="menu_groups" />
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3bf17376d..b926129b5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -294,6 +294,11 @@
<!-- The text displayed when the contacts list is empty while displaying all contacts [CHAR LIMIT=NONE] -->
<string name="noContacts">No contacts</string>
+ <!-- Group name menu item title when there is at least one group member. [CHAR LIMIT=NONE] -->
+ <string name="group_name_menu_item">
+ <xliff:g id="group_name">%s</xliff:g> (<xliff:g id="count">%d</xliff:g>)
+ </string>
+
<!-- The text displayed when the groups list is empty while displaying all groups [CHAR LIMIT=NONE] -->
<string name="noGroups">No groups.</string>
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 66a29deab..c3d3277df 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -36,9 +36,9 @@ import android.provider.ContactsContract.QuickContact;
import android.provider.Settings;
import android.support.design.widget.NavigationView;
import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.GravityCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
-import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
@@ -55,14 +55,13 @@ import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.Toast;
-
import com.android.contacts.AppCompatContactsActivity;
import com.android.contacts.R;
import com.android.contacts.activities.ActionBarAdapter.TabState;
import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.activity.RequestPermissionsActivity;
-import com.android.contacts.common.compat.TelecomManagerUtil;
import com.android.contacts.common.compat.BlockedNumberContractCompat;
+import com.android.contacts.common.compat.TelecomManagerUtil;
import com.android.contacts.common.dialog.ClearFrequentsDialog;
import com.android.contacts.common.interactions.ImportExportDialogFragment;
import com.android.contacts.common.list.ContactEntryListFragment;
@@ -81,6 +80,10 @@ import com.android.contacts.common.util.ViewUtil;
import com.android.contacts.common.widget.FloatingActionButtonController;
import com.android.contacts.commonbind.ObjectFactory;
import com.android.contacts.editor.EditorIntents;
+import com.android.contacts.group.GroupListItem;
+import com.android.contacts.group.GroupUtil;
+import com.android.contacts.group.GroupsFragment;
+import com.android.contacts.group.GroupsFragment.GroupsListener;
import com.android.contacts.interactions.ContactDeletionInteraction;
import com.android.contacts.interactions.ContactMultiDeletionInteraction;
import com.android.contacts.interactions.ContactMultiDeletionInteraction.MultiContactDeleteListener;
@@ -114,6 +117,7 @@ public class PeopleActivity extends AppCompatContactsActivity implements
ActionBarAdapter.Listener,
DialogManager.DialogShowingViewActivity,
ContactListFilterController.ContactListFilterListener,
+ GroupsListener,
ProviderStatusListener,
MultiContactDeleteListener,
JoinContactsListener,
@@ -152,6 +156,7 @@ public class PeopleActivity extends AppCompatContactsActivity implements
*/
private MultiSelectContactsListFragment mAllFragment;
private ContactTileListFragment mFavoritesFragment;
+ private GroupsFragment mGroupsFragment;
/** ViewPager for swipe */
private ViewPager mTabPager;
@@ -160,6 +165,8 @@ public class PeopleActivity extends AppCompatContactsActivity implements
private String[] mTabTitles;
private final TabPagerListener mTabPagerListener = new TabPagerListener();
+ private NavigationView mNavigationView;
+
private boolean mEnableDebugMenuOptions;
/**
@@ -340,10 +347,10 @@ public class PeopleActivity extends AppCompatContactsActivity implements
drawer.setDrawerListener(toggle);
toggle.syncState();
- final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
- navigationView.setNavigationItemSelectedListener(this);
+ mNavigationView = (NavigationView) findViewById(R.id.nav_view);
+ mNavigationView.setNavigationItemSelectedListener(this);
- final Menu menu = navigationView.getMenu();
+ final Menu menu = mNavigationView.getMenu();
if (HelpUtils.isHelpAndFeedbackAvailable()) {
final MenuItem menuItem = menu.add(/* groupId */ R.id.misc, /* itemId */ R.id.nav_help,
/* order */ Menu.NONE, /* titleRes */ R.string.menu_help);
@@ -352,6 +359,7 @@ public class PeopleActivity extends AppCompatContactsActivity implements
final String FAVORITE_TAG = "tab-pager-favorite";
final String ALL_TAG = "tab-pager-all";
+ final String GROUPS_TAG = "groups";
// Create the fragments and add as children of the view pager.
// The pager adapter will only change the visibility; it'll never create/destroy
@@ -363,13 +371,20 @@ public class PeopleActivity extends AppCompatContactsActivity implements
fragmentManager.findFragmentByTag(FAVORITE_TAG);
mAllFragment = (MultiSelectContactsListFragment)
fragmentManager.findFragmentByTag(ALL_TAG);
+ mGroupsFragment = (GroupsFragment)
+ fragmentManager.findFragmentByTag(GROUPS_TAG);
if (mFavoritesFragment == null) {
mFavoritesFragment = new ContactTileListFragment();
- mAllFragment = new MultiSelectContactsListFragment();
-
transaction.add(R.id.tab_pager, mFavoritesFragment, FAVORITE_TAG);
+
+ mAllFragment = new MultiSelectContactsListFragment();
transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);
+
+ if (areGroupWritableAccountsAvailable()) {
+ mGroupsFragment = new GroupsFragment();
+ transaction.add(mGroupsFragment, GROUPS_TAG);
+ }
}
mFavoritesFragment.setListener(mFavoritesFragmentListener);
@@ -377,10 +392,15 @@ public class PeopleActivity extends AppCompatContactsActivity implements
mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
mAllFragment.setCheckBoxListListener(new CheckBoxListListener());
+ if (areGroupWritableAccountsAvailable()) {
+ mGroupsFragment.setListener(this);
+ }
+
// Hide all fragments for now. We adjust visibility when we get onSelectedTabChanged()
// from ActionBarAdapter.
transaction.hide(mFavoritesFragment);
transaction.hide(mAllFragment);
+ // Groups fragment has no UI, no need to hide it
transaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
@@ -893,6 +913,26 @@ public class PeopleActivity extends AppCompatContactsActivity implements
}
@Override
+ public void onGroupsLoaded(List<GroupListItem> groupListItems) {
+ final Menu menu = mNavigationView.getMenu();
+ menu.removeGroup(R.id.menu_groups);
+ if (groupListItems == null || groupListItems.isEmpty()) {
+ return;
+ }
+ for (GroupListItem groupListItem : groupListItems) {
+ if (groupListItem.isFirstGroupInAccount()) {
+ menu.addSubMenu(groupListItem.getAccountName());
+ }
+ final String title = groupListItem.getMemberCount() == 0 ? groupListItem.getTitle()
+ : getString(R.string.group_name_menu_item, groupListItem.getTitle(),
+ groupListItem.getMemberCount());
+ final MenuItem menuItem =
+ menu.add(R.id.menu_groups, Menu.NONE, Menu.CATEGORY_SYSTEM, title);
+ menuItem.setIntent(GroupUtil.createViewGroupIntent(this, groupListItem.getGroupId()));
+ }
+ }
+
+ @Override
public void onProviderStatusChange() {
updateViewConfiguration(false);
}
@@ -1164,13 +1204,6 @@ public class PeopleActivity extends AppCompatContactsActivity implements
}
}
- private void makeMenuItemEnabled(Menu menu, int itemId, boolean visible) {
- final MenuItem item = menu.findItem(itemId);
- if (item != null) {
- item.setEnabled(visible);
- }
- }
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDisableOptionItemSelected) {
@@ -1242,7 +1275,7 @@ public class PeopleActivity extends AppCompatContactsActivity implements
return true;
}
}
- return false;
+ return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@@ -1254,6 +1287,10 @@ public class PeopleActivity extends AppCompatContactsActivity implements
startActivity(new Intent(this, ContactsPreferenceActivity.class));
} else if (id == R.id.nav_help) {
HelpUtils.launchHelpAndFeedbackForMainScreen(this);
+ } else if (item.getIntent() != null) {
+ ImplicitIntentsUtil.startActivityInApp(this, item.getIntent());
+ } else {
+ Log.w(TAG, "Unhandled navigation view item selection");
}
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index 48751e72d..71b235cea 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -61,7 +61,7 @@ public class GroupBrowseListAdapter extends BaseAdapter {
if (mSelectedGroupUri == null && cursor != null && cursor.getCount() > 0) {
GroupListItem firstItem = getItem(0);
long groupId = (firstItem == null) ? 0 : firstItem.getGroupId();
- mSelectedGroupUri = getGroupUriFromId(groupId);
+ mSelectedGroupUri = GroupUtil.getGroupUriFromId(groupId);
}
notifyDataSetChanged();
@@ -76,7 +76,7 @@ public class GroupBrowseListAdapter extends BaseAdapter {
mCursor.moveToPosition(-1);
while (mCursor.moveToNext()) {
long groupId = mCursor.getLong(GroupListLoader.GROUP_ID);
- Uri uri = getGroupUriFromId(groupId);
+ Uri uri = GroupUtil.getGroupUriFromId(groupId);
if (mSelectedGroupUri.equals(uri)) {
return index;
}
@@ -113,35 +113,7 @@ public class GroupBrowseListAdapter extends BaseAdapter {
@Override
public GroupListItem getItem(int position) {
- if (mCursor == null || mCursor.isClosed() || !mCursor.moveToPosition(position)) {
- return null;
- }
- String accountName = mCursor.getString(GroupListLoader.ACCOUNT_NAME);
- String accountType = mCursor.getString(GroupListLoader.ACCOUNT_TYPE);
- String dataSet = mCursor.getString(GroupListLoader.DATA_SET);
- long groupId = mCursor.getLong(GroupListLoader.GROUP_ID);
- String title = mCursor.getString(GroupListLoader.TITLE);
- int memberCount = mCursor.getInt(GroupListLoader.MEMBER_COUNT);
-
- // Figure out if this is the first group for this account name / account type pair by
- // checking the previous entry. This is to determine whether or not we need to display an
- // account header in this item.
- int previousIndex = position - 1;
- boolean isFirstGroupInAccount = true;
- if (previousIndex >= 0 && mCursor.moveToPosition(previousIndex)) {
- String previousGroupAccountName = mCursor.getString(GroupListLoader.ACCOUNT_NAME);
- String previousGroupAccountType = mCursor.getString(GroupListLoader.ACCOUNT_TYPE);
- String previousGroupDataSet = mCursor.getString(GroupListLoader.DATA_SET);
-
- if (accountName.equals(previousGroupAccountName) &&
- accountType.equals(previousGroupAccountType) &&
- Objects.equal(dataSet, previousGroupDataSet)) {
- isFirstGroupInAccount = false;
- }
- }
-
- return new GroupListItem(accountName, accountType, dataSet, groupId, title,
- isFirstGroupInAccount, memberCount);
+ return GroupUtil.getGroupListItem(mCursor, position);
}
@Override
@@ -180,7 +152,7 @@ public class GroupBrowseListAdapter extends BaseAdapter {
}
// Bind the group data
- Uri groupUri = getGroupUriFromId(entry.getGroupId());
+ Uri groupUri = GroupUtil.getGroupUriFromId(entry.getGroupId());
String memberCountString = mContext.getResources().getQuantityString(
R.plurals.group_list_num_contacts_in_group, entry.getMemberCount(),
entry.getMemberCount());
@@ -201,10 +173,6 @@ public class GroupBrowseListAdapter extends BaseAdapter {
viewCache.accountName.setText(entry.getAccountName());
}
- private static Uri getGroupUriFromId(long groupId) {
- return ContentUris.withAppendedId(Groups.CONTENT_URI, groupId);
- }
-
/**
* Cache of the children views of a contact detail entry represented by a
* {@link GroupListItem}
diff --git a/src/com/android/contacts/group/GroupUtil.java b/src/com/android/contacts/group/GroupUtil.java
new file mode 100644
index 000000000..f5b7db11f
--- /dev/null
+++ b/src/com/android/contacts/group/GroupUtil.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.group;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.Groups;
+
+import com.android.contacts.GroupListLoader;
+import com.android.contacts.activities.GroupDetailActivity;
+import com.google.common.base.Objects;
+
+/**
+ * Group utility methods.
+ */
+public final class GroupUtil {
+
+ private GroupUtil() {
+ }
+
+ /** Returns a {@link GroupListItem} read from the given cursor and position. */
+ static GroupListItem getGroupListItem(Cursor cursor, int position) {
+ if (cursor == null || cursor.isClosed() || !cursor.moveToPosition(position)) {
+ return null;
+ }
+ String accountName = cursor.getString(GroupListLoader.ACCOUNT_NAME);
+ String accountType = cursor.getString(GroupListLoader.ACCOUNT_TYPE);
+ String dataSet = cursor.getString(GroupListLoader.DATA_SET);
+ long groupId = cursor.getLong(GroupListLoader.GROUP_ID);
+ String title = cursor.getString(GroupListLoader.TITLE);
+ int memberCount = cursor.getInt(GroupListLoader.MEMBER_COUNT);
+
+ // Figure out if this is the first group for this account name / account type pair by
+ // checking the previous entry. This is to determine whether or not we need to display an
+ // account header in this item.
+ int previousIndex = position - 1;
+ boolean isFirstGroupInAccount = true;
+ if (previousIndex >= 0 && cursor.moveToPosition(previousIndex)) {
+ String previousGroupAccountName = cursor.getString(GroupListLoader.ACCOUNT_NAME);
+ String previousGroupAccountType = cursor.getString(GroupListLoader.ACCOUNT_TYPE);
+ String previousGroupDataSet = cursor.getString(GroupListLoader.DATA_SET);
+
+ if (accountName.equals(previousGroupAccountName) &&
+ accountType.equals(previousGroupAccountType) &&
+ Objects.equal(dataSet, previousGroupDataSet)) {
+ isFirstGroupInAccount = false;
+ }
+ }
+
+ return new GroupListItem(accountName, accountType, dataSet, groupId, title,
+ isFirstGroupInAccount, memberCount);
+ }
+
+ /** Returns an Intent to view the details of the group identified by the given Uri. */
+ public static Intent createViewGroupIntent(Context context, long groupId) {
+ final Intent intent = new Intent(context, GroupDetailActivity.class);
+ intent.setData(getGroupUriFromId(groupId));
+ return intent;
+ }
+
+ /** TODO: Make it private after {@link GroupBrowseListAdapter} is removed. */
+ static Uri getGroupUriFromId(long groupId) {
+ return ContentUris.withAppendedId(Groups.CONTENT_URI, groupId);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/contacts/group/GroupsFragment.java b/src/com/android/contacts/group/GroupsFragment.java
new file mode 100644
index 000000000..15529c7bb
--- /dev/null
+++ b/src/com/android/contacts/group/GroupsFragment.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.group;
+
+import android.app.Fragment;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+
+import com.android.contacts.GroupListLoader;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Loads groups and group metadata for all accounts.
+ */
+public final class GroupsFragment extends Fragment {
+
+ private static final int LOADER_GROUPS = 1;
+
+ /**
+ * Callbacks for hosts of the {@link GroupsFragment}.
+ */
+ public interface GroupsListener {
+
+ /**
+ * Invoked after groups and group metadata have been loaded.
+ */
+ void onGroupsLoaded(List<GroupListItem> groupListItems);
+ }
+
+ /**
+ * Group meta data loader listener.
+ */
+ private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
+ new LoaderManager.LoaderCallbacks<Cursor>() {
+
+ @Override
+ public CursorLoader onCreateLoader(int id, Bundle args) {
+ return new GroupListLoader(mContext);
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mGroupListItems.clear();
+ for (int i = 0; i < data.getCount(); i++) {
+ if (data.moveToNext()) {
+ mGroupListItems.add(GroupUtil.getGroupListItem(data, i));
+ }
+ }
+ if (mListener != null) {
+ mListener.onGroupsLoaded(mGroupListItems);
+ }
+ }
+
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+ };
+
+ private Context mContext;
+ private List<GroupListItem> mGroupListItems = new ArrayList<>();
+ private GroupsListener mListener;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mContext = context;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mContext = null;
+ }
+
+ @Override
+ public void onStart() {
+ getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
+ super.onStart();
+ }
+
+ public void setListener(GroupsListener listener) {
+ mListener = listener;
+ }
+}