| /* |
| * Copyright (C) 2013 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.mail.adapter; |
| |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.TextView; |
| |
| import com.android.bitmap.BitmapCache; |
| import com.android.mail.R; |
| import com.android.mail.bitmap.ContactResolver; |
| import com.android.mail.providers.Account; |
| import com.android.mail.providers.Folder; |
| import com.android.mail.ui.AccountItemView; |
| import com.android.mail.ui.ControllableActivity; |
| import com.android.mail.ui.FolderItemView; |
| import com.android.mail.utils.FolderUri; |
| import com.android.mail.utils.LogTag; |
| import com.android.mail.utils.LogUtils; |
| |
| |
| /** |
| * An element that is shown in the {@link com.android.mail.ui.FolderListFragment}. This class is |
| * only used for elements that are shown in the {@link com.android.mail.ui.DrawerFragment}. |
| * This class is an enumeration of a few element types: Account, a folder, a recent folder, |
| * or a header (a resource string). A {@link DrawerItem} can only be one type and can never |
| * switch types. Items are created using methods like |
| * {@link DrawerItem#ofAccount(com.android.mail.ui.ControllableActivity, |
| com.android.mail.providers.Account, int, boolean)}, |
| * {@link DrawerItem#ofWaitView(com.android.mail.ui.ControllableActivity)}, etc. |
| * |
| * Once created, the item can create a view using |
| * {@link #getView(android.view.View, android.view.ViewGroup)}. |
| */ |
| public class DrawerItem { |
| private static final String LOG_TAG = LogTag.getLogTag(); |
| public final Folder mFolder; |
| public final Account mAccount; |
| private final int mResource; |
| /** True if the drawer item represents the current account, false otherwise */ |
| private final boolean mIsSelected; |
| /** Either {@link #VIEW_ACCOUNT}, {@link #VIEW_FOLDER} or {@link #VIEW_HEADER} */ |
| public final int mType; |
| /** A normal folder, also a child, if a parent is specified. */ |
| public static final int VIEW_FOLDER = 0; |
| /** A text-label which serves as a header in sectioned lists. */ |
| public static final int VIEW_HEADER = 1; |
| /** An account object, which allows switching accounts rather than folders. */ |
| public static final int VIEW_ACCOUNT = 2; |
| /** An expandable object for expanding/collapsing more of the list */ |
| public static final int VIEW_WAITING_FOR_SYNC = 3; |
| /** The value (1-indexed) of the last View type. Useful when returning the number of types. */ |
| private static final int LAST_FIELD = VIEW_WAITING_FOR_SYNC + 1; |
| |
| /** TODO: On adding another type, be sure to change getViewTypes() */ |
| |
| /** The parent activity */ |
| private final ControllableActivity mActivity; |
| private final LayoutInflater mInflater; |
| |
| // TODO(viki): Put all these constants in an interface. |
| /** |
| * Either {@link #FOLDER_INBOX}, {@link #FOLDER_RECENT} or {@link #FOLDER_OTHER} when |
| * {@link #mType} is {@link #VIEW_FOLDER}, or an {@link #ACCOUNT} in the case of |
| * accounts, and {@link #INERT_HEADER} otherwise. |
| */ |
| public final int mFolderType; |
| /** Non existent item or folder type not yet set */ |
| public static final int UNSET = 0; |
| /** An unclickable text-header visually separating the different types. */ |
| public static final int INERT_HEADER = 0; |
| /** An inbox folder: Inbox, ...*/ |
| public static final int FOLDER_INBOX = 1; |
| /** A folder from whom a conversation was recently viewed */ |
| public static final int FOLDER_RECENT = 2; |
| /** A non-inbox folder that is shown in the "everything else" group. */ |
| public static final int FOLDER_OTHER = 3; |
| /** An entry for the accounts the user has on the device. */ |
| public static final int ACCOUNT = 4; |
| |
| /** True if this view is enabled, false otherwise. */ |
| private final boolean mIsEnabled; |
| |
| private BitmapCache mImagesCache; |
| private ContactResolver mContactResolver; |
| |
| @Override |
| public String toString() { |
| switch(mType) { |
| case VIEW_FOLDER: |
| return folderToString(); |
| case VIEW_HEADER: |
| return headerToString(); |
| case VIEW_ACCOUNT: |
| return accountToString(); |
| case VIEW_WAITING_FOR_SYNC: |
| return waitToString(); |
| } |
| // Should never come here. |
| return null; |
| } |
| |
| /** |
| * Creates a drawer item with every instance variable specified. |
| * |
| * @param type the type of the item. This must be a VIEW_* element |
| * @param activity the underlying activity |
| * @param folder a non-null folder, if this is a folder type |
| * @param folderType the type of the folder. For folders this is: |
| * {@link #FOLDER_INBOX}, {@link #FOLDER_RECENT}, |
| * {@link #FOLDER_OTHER}, or for non-folders this is |
| * {@link #ACCOUNT}, or {@link #INERT_HEADER} |
| * @param account the account object, for an account drawer element |
| * @param resource either the string resource for a header, or the unread |
| * count for an account. |
| * @param isCurrentAccount true if this item is the current account |
| */ |
| private DrawerItem(int type, ControllableActivity activity, Folder folder, int folderType, |
| Account account, int resource, boolean isCurrentAccount, BitmapCache cache, |
| ContactResolver contactResolver) { |
| mActivity = activity; |
| mFolder = folder; |
| mFolderType = folderType; |
| mAccount = account; |
| mResource = resource; |
| mIsSelected = isCurrentAccount; |
| mInflater = LayoutInflater.from(activity.getActivityContext()); |
| mType = type; |
| mIsEnabled = calculateEnabled(); |
| mImagesCache = cache; |
| mContactResolver = contactResolver; |
| } |
| |
| /** |
| * Create a folder item with the given type. |
| * |
| * @param activity the underlying activity |
| * @param folder a folder that this item represents |
| * @param folderType one of {@link #FOLDER_INBOX}, {@link #FOLDER_RECENT} or |
| * {@link #FOLDER_OTHER} |
| * @return a drawer item for the folder. |
| */ |
| public static DrawerItem ofFolder(ControllableActivity activity, Folder folder, |
| int folderType) { |
| return new DrawerItem(VIEW_FOLDER, activity, folder, folderType, null, -1, false, |
| null, null); |
| } |
| |
| private String folderToString() { |
| final StringBuilder sb = new StringBuilder("[DrawerItem "); |
| sb.append(" VIEW_FOLDER "); |
| sb.append(", mFolder="); |
| sb.append(mFolder); |
| sb.append(", mFolderType="); |
| sb.append(mFolderType); |
| sb.append("]"); |
| return sb.toString(); |
| } |
| |
| /** |
| * Creates an item from an account. |
| * @param activity the underlying activity |
| * @param account the account to create a drawer item for |
| * @param unreadCount the unread count of the account, pass zero if |
| * @param isCurrentAccount true if the account is the current account, false otherwise |
| * @return a drawer item for the account. |
| */ |
| public static DrawerItem ofAccount(ControllableActivity activity, Account account, |
| int unreadCount, boolean isCurrentAccount, BitmapCache cache, |
| ContactResolver contactResolver) { |
| return new DrawerItem(VIEW_ACCOUNT, activity, null, ACCOUNT, account, unreadCount, |
| isCurrentAccount, cache, contactResolver); |
| } |
| |
| private String accountToString() { |
| final StringBuilder sb = new StringBuilder("[DrawerItem "); |
| sb.append(" VIEW_ACCOUNT "); |
| sb.append(", mAccount="); |
| sb.append(mAccount); |
| sb.append("]"); |
| return sb.toString(); |
| } |
| |
| /** |
| * Create a header item with a string resource. |
| * |
| * @param activity the underlying activity |
| * @param resource the string resource: R.string.all_folders_heading |
| * @return a drawer item for the header. |
| */ |
| public static DrawerItem ofHeader(ControllableActivity activity, int resource) { |
| return new DrawerItem(VIEW_HEADER, activity, null, INERT_HEADER, null, resource, false, |
| null, null); |
| } |
| |
| private String headerToString() { |
| final StringBuilder sb = new StringBuilder("[DrawerItem "); |
| sb.append(" VIEW_HEADER "); |
| sb.append(", mResource="); |
| sb.append(mResource); |
| sb.append("]"); |
| return sb.toString(); |
| } |
| |
| /** |
| * Create a "waiting for initialization" item. |
| * |
| * @param activity the underlying activity |
| * @return a drawer item with an indeterminate progress indicator. |
| */ |
| public static DrawerItem ofWaitView(ControllableActivity activity) { |
| return new DrawerItem(VIEW_WAITING_FOR_SYNC, activity, null, INERT_HEADER, null, -1, false, |
| null, null); |
| } |
| |
| private static String waitToString() { |
| return "[DrawerItem VIEW_WAITING_FOR_SYNC ]"; |
| } |
| |
| /** |
| * Returns a view for the given item. The method signature is identical to that required by a |
| * {@link android.widget.ListAdapter#getView(int, android.view.View, android.view.ViewGroup)}. |
| */ |
| public View getView(View convertView, ViewGroup parent) { |
| final View result; |
| switch (mType) { |
| case VIEW_FOLDER: |
| result = getFolderView(convertView, parent); |
| break; |
| case VIEW_HEADER: |
| result = getHeaderView(convertView, parent); |
| break; |
| case VIEW_ACCOUNT: |
| result = getAccountView(convertView, parent); |
| break; |
| case VIEW_WAITING_FOR_SYNC: |
| result = getEmptyView(convertView, parent); |
| break; |
| default: |
| LogUtils.wtf(LOG_TAG, "DrawerItem.getView(%d) for an invalid type!", mType); |
| result = null; |
| } |
| return result; |
| } |
| |
| /** |
| * Book-keeping for how many different view types there are. Be sure to |
| * increment this appropriately once adding more types as drawer items |
| * @return number of different types of view items |
| */ |
| public static int getViewTypes() { |
| return LAST_FIELD; |
| } |
| |
| /** |
| * Returns whether this view is enabled or not. An enabled view is one that accepts user taps |
| * and acts upon them. |
| * @return true if this view is enabled, false otherwise. |
| */ |
| public boolean isItemEnabled() { |
| return mIsEnabled; |
| } |
| |
| /** Calculate whether the item is enabled */ |
| private boolean calculateEnabled() { |
| switch (mType) { |
| case VIEW_HEADER : |
| // Headers are never enabled. |
| return false; |
| case VIEW_FOLDER : |
| // Folders are always enabled. |
| return true; |
| case VIEW_ACCOUNT: |
| // Accounts are always enabled. |
| return true; |
| case VIEW_WAITING_FOR_SYNC: |
| // Waiting for sync cannot be tapped, so never enabled. |
| return false; |
| default: |
| LogUtils.wtf(LOG_TAG, "DrawerItem.isItemEnabled() for invalid type %d", mType); |
| return false; |
| } |
| } |
| |
| /** |
| * Returns whether this view is highlighted or not. |
| * |
| * |
| * @param currentFolder The current folder, according to the |
| * {@link com.android.mail.ui.FolderListFragment} |
| * @param currentType The type of the current folder. We want to only highlight a folder once. |
| * A folder might be in two places at once: in "All Folders", and in |
| * "Recent Folder". Valid types of selected folders are : |
| * {@link DrawerItem#FOLDER_INBOX}, {@link DrawerItem#FOLDER_RECENT} or |
| * {@link DrawerItem#FOLDER_OTHER}, or {@link DrawerItem#UNSET}. |
| |
| * @return true if this DrawerItem results in a view that is highlighted (this DrawerItem is |
| * the current folder. |
| */ |
| public boolean isHighlighted(FolderUri currentFolder, int currentType) { |
| switch (mType) { |
| case VIEW_HEADER : |
| // Headers are never highlighted |
| return false; |
| case VIEW_FOLDER: |
| // True if folder types and URIs are the same |
| if (currentFolder != null && mFolder != null && mFolder.folderUri != null) { |
| return (mFolderType == currentType) && mFolder.folderUri.equals(currentFolder); |
| } |
| return false; |
| case VIEW_ACCOUNT: |
| // Accounts are never highlighted |
| return false; |
| case VIEW_WAITING_FOR_SYNC: |
| // Waiting for sync cannot be tapped, so never highlighted. |
| return false; |
| default: |
| LogUtils.wtf(LOG_TAG, "DrawerItem.isHighlighted() for invalid type %d", mType); |
| return false; |
| } |
| } |
| |
| /** |
| * Return a view for an account object. |
| * |
| * @param convertView a view, possibly null, to be recycled. |
| * @param parent the parent viewgroup to attach to. |
| * @return a view to display at this position. |
| */ |
| private View getAccountView(View convertView, ViewGroup parent) { |
| final AccountItemView accountItemView; |
| if (convertView != null) { |
| accountItemView = (AccountItemView) convertView; |
| } else { |
| accountItemView = |
| (AccountItemView) mInflater.inflate(R.layout.account_item, parent, false); |
| } |
| accountItemView.bind(mActivity.getActivityContext(), mAccount, mIsSelected, mImagesCache, |
| mContactResolver); |
| return accountItemView; |
| } |
| |
| /** |
| * Returns a text divider between divisions. |
| * |
| * @param convertView a previous view, perhaps null |
| * @param parent the parent of this view |
| * @return a text header at the given position. |
| */ |
| private View getHeaderView(View convertView, ViewGroup parent) { |
| final TextView headerView; |
| if (convertView != null) { |
| headerView = (TextView) convertView; |
| } else { |
| headerView = (TextView) mInflater.inflate(R.layout.folder_list_header, parent, false); |
| } |
| headerView.setText(mResource); |
| return headerView; |
| } |
| |
| /** |
| * Return a folder: either a parent folder or a normal (child or flat) |
| * folder. |
| * |
| * @param convertView a view, possibly null, to be recycled. |
| * @return a view showing a folder at the given position. |
| */ |
| private View getFolderView(View convertView, ViewGroup parent) { |
| final FolderItemView folderItemView; |
| if (convertView != null) { |
| folderItemView = (FolderItemView) convertView; |
| } else { |
| folderItemView = |
| (FolderItemView) mInflater.inflate(R.layout.folder_item, parent, false); |
| } |
| folderItemView.bind(mFolder, mActivity); |
| Folder.setFolderBlockColor(mFolder, folderItemView.findViewById(R.id.color_block)); |
| folderItemView.setIcon(mFolder); |
| return folderItemView; |
| } |
| |
| /** |
| * Return a view for the 'Waiting for sync' item with the indeterminate progress indicator. |
| * |
| * @param convertView a view, possibly null, to be recycled. |
| * @param parent the parent hosting this view. |
| * @return a view for "Waiting for sync..." at given position. |
| */ |
| private View getEmptyView(View convertView, ViewGroup parent) { |
| final ViewGroup emptyView; |
| if (convertView != null) { |
| emptyView = (ViewGroup) convertView; |
| } else { |
| emptyView = (ViewGroup) mInflater.inflate(R.layout.drawer_empty_view, parent, false); |
| } |
| return emptyView; |
| } |
| |
| } |
| |