1 /* 2 * Copyright (C) 2017 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 17 package com.android.contacts.drawer; 18 19 import android.app.Activity; 20 import android.graphics.PorterDuff; 21 import android.support.annotation.LayoutRes; 22 import android.view.LayoutInflater; 23 import android.view.View; 24 import android.view.ViewGroup; 25 import android.widget.BaseAdapter; 26 import android.widget.ImageView; 27 import android.widget.TextView; 28 29 import com.android.contacts.R; 30 import com.android.contacts.activities.PeopleActivity.ContactsView; 31 import com.android.contacts.group.GroupListItem; 32 import com.android.contacts.list.ContactListFilter; 33 import com.android.contacts.model.account.AccountDisplayInfo; 34 import com.android.contacts.model.account.AccountDisplayInfoFactory; 35 import com.android.contacts.util.SharedPreferenceUtil; 36 import com.android.contactsbind.ObjectFactory; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 41 public class DrawerAdapter extends BaseAdapter { 42 43 private static final int VIEW_TYPE_PRIMARY_ITEM = 0; 44 private static final int VIEW_TYPE_MISC_ITEM = 1; 45 private static final int VIEW_TYPE_HEADER_ITEM = 2; 46 private static final int VIEW_TYPE_GROUP_ENTRY = 3; 47 private static final int VIEW_TYPE_ACCOUNT_ENTRY = 4; 48 private static final int VIEW_TYPE_CREATE_LABEL = 5; 49 private static final int VIEW_TYPE_NAV_SPACER = 6; 50 private static final int VIEW_TYPE_STATUS_SPACER = 7; 51 private static final int VIEW_TYPE_NAV_DIVIDER = 8; 52 53 // This count must be updated if we add more view types. 54 private static final int VIEW_TYPE_COUNT = 9; 55 56 private static final int TYPEFACE_STYLE_ACTIVATE = R.style.DrawerItemTextActiveStyle; 57 private static final int TYPEFACE_STYLE_INACTIVE = R.style.DrawerItemTextInactiveStyle; 58 59 private final Activity mActivity; 60 private final LayoutInflater mInflater; 61 private ContactsView mSelectedView; 62 private boolean mAreGroupWritableAccountsAvailable; 63 64 // The group/account that was last clicked. 65 private long mSelectedGroupId; 66 private ContactListFilter mSelectedAccount; 67 68 // Adapter elements, ordered in this way mItemsList. The ordering is based on: 69 // [Status bar spacer item] 70 // [Navigation spacer item] 71 // [Primary items] (Contacts, Suggestions) 72 // [Group Header] 73 // [Groups] 74 // [Create Label button] 75 // [Account Header] 76 // [Accounts] 77 // [Misc items] (a divider, Settings, Help & Feedback) 78 // [Navigation spacer item] 79 private StatusBarSpacerItem mStatusBarSpacerItem = null; 80 private NavSpacerItem mNavSpacerItem = null; 81 private List<PrimaryItem> mPrimaryItems = new ArrayList<>(); 82 private HeaderItem mGroupHeader = null; 83 private List<GroupEntryItem> mGroupEntries = new ArrayList<>(); 84 private BaseDrawerItem mCreateLabelButton = null; 85 private HeaderItem mAccountHeader = null; 86 private List<AccountEntryItem> mAccountEntries = new ArrayList<>(); 87 private List<BaseDrawerItem> mMiscItems = new ArrayList<>(); 88 89 private List<BaseDrawerItem> mItemsList = new ArrayList<>(); 90 private AccountDisplayInfoFactory mAccountDisplayFactory; 91 DrawerAdapter(Activity activity)92 public DrawerAdapter(Activity activity) { 93 super(); 94 mInflater = LayoutInflater.from(activity); 95 mActivity = activity; 96 initializeDrawerMenuItems(); 97 } 98 initializeDrawerMenuItems()99 private void initializeDrawerMenuItems() { 100 // Spacer item for dividing sections in drawer 101 mNavSpacerItem = new NavSpacerItem(R.id.nav_drawer_spacer); 102 mStatusBarSpacerItem = new StatusBarSpacerItem(R.id.nav_status_bar_spacer); 103 // Primary items 104 mPrimaryItems.add(new PrimaryItem(R.id.nav_all_contacts, R.string.contactsList, 105 R.drawable.quantum_ic_account_circle_vd_theme_24, ContactsView.ALL_CONTACTS)); 106 if (ObjectFactory.getAssistantFragment() != null) { 107 mPrimaryItems.add(new PrimaryItem(R.id.nav_assistant, R.string.menu_assistant, 108 R.drawable.quantum_ic_assistant_vd_theme_24, ContactsView.ASSISTANT)); 109 } 110 // Group Header 111 mGroupHeader = new HeaderItem(R.id.nav_groups, R.string.menu_title_groups); 112 // Account Header 113 mAccountHeader = new HeaderItem(R.id.nav_filters, R.string.menu_title_filters); 114 // Create Label Button 115 mCreateLabelButton = new BaseDrawerItem(VIEW_TYPE_CREATE_LABEL, R.id.nav_create_label, 116 R.string.menu_new_group_action_bar, R.drawable.quantum_ic_add_vd_theme_24); 117 // Misc Items 118 mMiscItems.add(new DividerItem()); 119 mMiscItems.add(new MiscItem(R.id.nav_settings, R.string.menu_settings, 120 R.drawable.quantum_ic_settings_vd_theme_24)); 121 mMiscItems.add(new MiscItem(R.id.nav_help, R.string.menu_help, 122 R.drawable.quantum_ic_help_vd_theme_24)); 123 rebuildItemsList(); 124 } 125 rebuildItemsList()126 private void rebuildItemsList() { 127 mItemsList.clear(); 128 mItemsList.add(mStatusBarSpacerItem); 129 mItemsList.add(mNavSpacerItem); 130 mItemsList.addAll(mPrimaryItems); 131 if (mAreGroupWritableAccountsAvailable || !mGroupEntries.isEmpty()) { 132 mItemsList.add(mGroupHeader); 133 } 134 mItemsList.addAll(mGroupEntries); 135 if (mAreGroupWritableAccountsAvailable) { 136 mItemsList.add(mCreateLabelButton); 137 } 138 if (mAccountEntries.size() > 0) { 139 mItemsList.add(mAccountHeader); 140 } 141 mItemsList.addAll(mAccountEntries); 142 mItemsList.addAll(mMiscItems); 143 mItemsList.add(mNavSpacerItem); 144 } 145 setGroups(List<GroupListItem> groupListItems, boolean areGroupWritable)146 public void setGroups(List<GroupListItem> groupListItems, boolean areGroupWritable) { 147 final ArrayList<GroupEntryItem> groupEntries = new ArrayList<GroupEntryItem>(); 148 for (GroupListItem group : groupListItems) { 149 groupEntries.add(new GroupEntryItem(R.id.nav_group, group)); 150 } 151 mGroupEntries.clear(); 152 mGroupEntries.addAll(groupEntries); 153 mAreGroupWritableAccountsAvailable = areGroupWritable; 154 notifyChangeAndRebuildList(); 155 } 156 setAccounts(List<ContactListFilter> accountFilterItems)157 public void setAccounts(List<ContactListFilter> accountFilterItems) { 158 ArrayList<AccountEntryItem> accountItems = new ArrayList<AccountEntryItem>(); 159 for (ContactListFilter filter : accountFilterItems) { 160 accountItems.add(new AccountEntryItem(R.id.nav_filter, filter)); 161 } 162 mAccountDisplayFactory = AccountDisplayInfoFactory.fromListFilters(mActivity, 163 accountFilterItems); 164 mAccountEntries.clear(); 165 mAccountEntries.addAll(accountItems); 166 // TODO investigate performance of calling notifyDataSetChanged 167 notifyChangeAndRebuildList(); 168 } 169 170 @Override getCount()171 public int getCount() { 172 return mItemsList.size(); 173 } 174 getItem(int position)175 public BaseDrawerItem getItem(int position) { 176 return mItemsList.get(position); 177 } 178 179 @Override getItemId(int position)180 public long getItemId(int position) { 181 return getItem(position).id; 182 } 183 184 @Override getViewTypeCount()185 public int getViewTypeCount() { 186 return VIEW_TYPE_COUNT; 187 } 188 189 @Override getView(int position, View view, ViewGroup viewGroup)190 public View getView(int position, View view, ViewGroup viewGroup) { 191 final BaseDrawerItem drawerItem = getItem(position); 192 switch (drawerItem.viewType) { 193 case VIEW_TYPE_STATUS_SPACER: 194 return getBaseItemView(R.layout.nav_header_main, view, viewGroup); 195 case VIEW_TYPE_PRIMARY_ITEM: 196 return getPrimaryItemView((PrimaryItem) drawerItem, view, viewGroup); 197 case VIEW_TYPE_HEADER_ITEM: 198 return getHeaderItemView((HeaderItem) drawerItem, view, viewGroup); 199 case VIEW_TYPE_CREATE_LABEL: 200 return getDrawerItemView(drawerItem, view, viewGroup); 201 case VIEW_TYPE_GROUP_ENTRY: 202 return getGroupEntryView((GroupEntryItem) drawerItem, view, viewGroup); 203 case VIEW_TYPE_ACCOUNT_ENTRY: 204 return getAccountItemView((AccountEntryItem) drawerItem, view, viewGroup); 205 case VIEW_TYPE_MISC_ITEM: 206 return getDrawerItemView(drawerItem, view, viewGroup); 207 case VIEW_TYPE_NAV_SPACER: 208 return getBaseItemView(R.layout.nav_drawer_spacer, view, viewGroup); 209 case VIEW_TYPE_NAV_DIVIDER: 210 return getBaseItemView(R.layout.drawer_horizontal_divider, view, viewGroup); 211 } 212 throw new IllegalStateException("Unknown drawer item " + drawerItem); 213 } 214 getBaseItemView(@ayoutRes int layoutResID, View result,ViewGroup parent)215 private View getBaseItemView(@LayoutRes int layoutResID, View result,ViewGroup parent) { 216 if (result == null) { 217 result = mInflater.inflate(layoutResID, parent, false); 218 } 219 return result; 220 } 221 getPrimaryItemView(PrimaryItem item, View result, ViewGroup parent)222 private View getPrimaryItemView(PrimaryItem item, View result, ViewGroup parent) { 223 if (result == null) { 224 result = mInflater.inflate(R.layout.drawer_primary_item, parent, false); 225 } 226 final TextView titleView = (TextView) result.findViewById(R.id.title); 227 titleView.setText(item.text); 228 final ImageView iconView = (ImageView) result.findViewById(R.id.icon); 229 iconView.setImageResource(item.icon); 230 final TextView newBadge = (TextView) result.findViewById(R.id.assistant_new_badge); 231 final boolean showWelcomeBadge = !SharedPreferenceUtil.isWelcomeCardDismissed(mActivity); 232 newBadge.setVisibility(item.contactsView == ContactsView.ASSISTANT && showWelcomeBadge 233 ? View.VISIBLE : View.GONE); 234 result.setActivated(item.contactsView == mSelectedView); 235 updateSelectedStatus(titleView, iconView, item.contactsView == mSelectedView); 236 result.setId(item.id); 237 return result; 238 } 239 getHeaderItemView(HeaderItem item, View result, ViewGroup parent)240 private View getHeaderItemView(HeaderItem item, View result, ViewGroup parent) { 241 if (result == null) { 242 result = mInflater.inflate(R.layout.drawer_header, parent, false); 243 } 244 final TextView textView = (TextView) result.findViewById(R.id.title); 245 textView.setText(item.text); 246 result.setId(item.id); 247 return result; 248 } 249 getGroupEntryView(GroupEntryItem item, View result, ViewGroup parent)250 private View getGroupEntryView(GroupEntryItem item, View result, ViewGroup parent) { 251 if (result == null || !(result.getTag() instanceof GroupEntryItem)) { 252 result = mInflater.inflate(R.layout.drawer_item, parent, false); 253 result.setId(item.id); 254 } 255 256 final GroupListItem groupListItem = item.group; 257 final TextView title = (TextView) result.findViewById(R.id.title); 258 title.setText(groupListItem.getTitle()); 259 final ImageView icon = (ImageView) result.findViewById(R.id.icon); 260 icon.setImageResource(R.drawable.quantum_ic_label_vd_theme_24); 261 final boolean activated = groupListItem.getGroupId() == mSelectedGroupId && 262 mSelectedView == ContactsView.GROUP_VIEW; 263 updateSelectedStatus(title, icon, activated); 264 result.setActivated(activated); 265 266 result.setTag(groupListItem); 267 result.setContentDescription( 268 mActivity.getString(R.string.navigation_drawer_label, groupListItem.getTitle())); 269 return result; 270 } 271 getAccountItemView(AccountEntryItem item, View result, ViewGroup parent)272 private View getAccountItemView(AccountEntryItem item, View result, ViewGroup parent) { 273 if (result == null || !(result.getTag() instanceof ContactListFilter)) { 274 result = mInflater.inflate(R.layout.drawer_item, parent, false); 275 result.setId(item.id); 276 } 277 final ContactListFilter account = item.account; 278 final TextView textView = ((TextView) result.findViewById(R.id.title)); 279 textView.setText(account.accountName); 280 final boolean activated = account.equals(mSelectedAccount) 281 && mSelectedView == ContactsView.ACCOUNT_VIEW; 282 textView.setTextAppearance(mActivity, activated 283 ? TYPEFACE_STYLE_ACTIVATE : TYPEFACE_STYLE_INACTIVE); 284 285 final ImageView icon = (ImageView) result.findViewById(R.id.icon); 286 final AccountDisplayInfo displayableAccount = 287 mAccountDisplayFactory.getAccountDisplayInfoFor(item.account); 288 icon.setScaleType(ImageView.ScaleType.FIT_CENTER); 289 icon.setImageDrawable(displayableAccount.getIcon()); 290 291 result.setTag(account); 292 result.setActivated(activated); 293 result.setContentDescription( 294 displayableAccount.getTypeLabel() + " " + item.account.accountName); 295 return result; 296 } 297 getDrawerItemView(BaseDrawerItem item, View result, ViewGroup parent)298 private View getDrawerItemView(BaseDrawerItem item, View result, ViewGroup parent) { 299 if (result == null) { 300 result = mInflater.inflate(R.layout.drawer_item, parent, false); 301 } 302 303 final TextView textView = (TextView) result.findViewById(R.id.title); 304 textView.setText(item.text); 305 final ImageView iconView = (ImageView) result.findViewById(R.id.icon); 306 iconView.setImageResource(item.icon); 307 result.setId(item.id); 308 updateSelectedStatus(textView, iconView, false); 309 return result; 310 } 311 312 @Override getItemViewType(int position)313 public int getItemViewType(int position) { 314 return getItem(position).viewType; 315 } 316 updateSelectedStatus(TextView textView, ImageView imageView, boolean activated)317 private void updateSelectedStatus(TextView textView, ImageView imageView, boolean activated) { 318 textView.setTextAppearance(mActivity, activated 319 ? TYPEFACE_STYLE_ACTIVATE : TYPEFACE_STYLE_INACTIVE); 320 if (activated) { 321 imageView.setColorFilter(mActivity.getResources().getColor(R.color.primary_color), 322 PorterDuff.Mode.SRC_ATOP); 323 } else { 324 imageView.clearColorFilter(); 325 } 326 } 327 notifyChangeAndRebuildList()328 private void notifyChangeAndRebuildList() { 329 rebuildItemsList(); 330 notifyDataSetChanged(); 331 } 332 setSelectedContactsView(ContactsView contactsView)333 public void setSelectedContactsView(ContactsView contactsView) { 334 if (mSelectedView == contactsView) { 335 return; 336 } 337 mSelectedView = contactsView; 338 notifyChangeAndRebuildList(); 339 } 340 341 setSelectedGroupId(long groupId)342 public void setSelectedGroupId(long groupId) { 343 if (mSelectedGroupId == groupId) { 344 return; 345 } 346 mSelectedGroupId = groupId; 347 notifyChangeAndRebuildList(); 348 } 349 getSelectedGroupId()350 public long getSelectedGroupId() { 351 return mSelectedGroupId; 352 } 353 setSelectedAccount(ContactListFilter filter)354 public void setSelectedAccount(ContactListFilter filter) { 355 if (mSelectedAccount == filter) { 356 return; 357 } 358 mSelectedAccount = filter; 359 notifyChangeAndRebuildList(); 360 } 361 getSelectedAccount()362 public ContactListFilter getSelectedAccount() { 363 return mSelectedAccount; 364 } 365 366 public static class BaseDrawerItem { 367 public final int viewType; 368 public final int id; 369 public final int text; 370 public final int icon; 371 BaseDrawerItem(int adapterViewType, int viewId, int textResId, int iconResId)372 public BaseDrawerItem(int adapterViewType, int viewId, int textResId, int iconResId) { 373 viewType = adapterViewType; 374 id = viewId; 375 text = textResId; 376 icon = iconResId; 377 } 378 } 379 380 // Navigation drawer item for Contacts or Suggestions view which contains a name, an icon and 381 // contacts view. 382 public static class PrimaryItem extends BaseDrawerItem { 383 public final ContactsView contactsView; 384 PrimaryItem(int id, int pageName, int iconId, ContactsView contactsView)385 public PrimaryItem(int id, int pageName, int iconId, ContactsView contactsView) { 386 super(VIEW_TYPE_PRIMARY_ITEM, id, pageName, iconId); 387 this.contactsView = contactsView; 388 } 389 } 390 391 // Navigation drawer item for Settings, help and feedback, etc. 392 public static class MiscItem extends BaseDrawerItem { MiscItem(int id, int textId, int iconId)393 public MiscItem(int id, int textId, int iconId) { 394 super(VIEW_TYPE_MISC_ITEM, id, textId, iconId); 395 } 396 } 397 398 // Header for a list of sub-items in the drawer. 399 public static class HeaderItem extends BaseDrawerItem { HeaderItem(int id, int textId)400 public HeaderItem(int id, int textId) { 401 super(VIEW_TYPE_HEADER_ITEM, id, textId, /* iconResId */ 0); 402 } 403 } 404 405 406 // Navigation drawer item for status bar spacer item to take up the height of status bar in the 407 // drawer. 408 public static class StatusBarSpacerItem extends BaseDrawerItem { StatusBarSpacerItem(int id)409 public StatusBarSpacerItem(int id) { 410 super(VIEW_TYPE_STATUS_SPACER, id, /* textResId */ 0, /* iconResId */ 0); 411 } 412 } 413 414 // Navigation drawer item for spacer item for dividing sections in the drawer. 415 public static class NavSpacerItem extends BaseDrawerItem { NavSpacerItem(int id)416 public NavSpacerItem(int id) { 417 super(VIEW_TYPE_NAV_SPACER, id, /* textResId */ 0, /* iconResId */ 0); 418 } 419 } 420 421 // Divider for drawing a line between sections in the drawer. 422 public static class DividerItem extends BaseDrawerItem { DividerItem()423 public DividerItem() { 424 super(VIEW_TYPE_NAV_DIVIDER, /* id */ 0, /* textResId */ 0, /* iconResId */ 0); 425 } 426 } 427 428 // Navigation drawer item for a group. 429 public static class GroupEntryItem extends BaseDrawerItem { 430 private final GroupListItem group; 431 GroupEntryItem(int id, GroupListItem group)432 public GroupEntryItem(int id, GroupListItem group) { 433 super(VIEW_TYPE_GROUP_ENTRY, id, /* textResId */ 0, /* iconResId */ 0); 434 this.group = group; 435 } 436 } 437 438 // Navigation drawer item for an account. 439 public static class AccountEntryItem extends BaseDrawerItem { 440 private final ContactListFilter account; 441 AccountEntryItem(int id, ContactListFilter account)442 public AccountEntryItem(int id, ContactListFilter account) { 443 super(VIEW_TYPE_ACCOUNT_ENTRY, id, /* textResId */ 0, /* iconResId */ 0); 444 this.account = account; 445 } 446 } 447 } 448