1e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira/******************************************************************************* 2e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * Copyright (C) 2012 Google Inc. 3e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * Licensed to The Android Open Source Project. 4e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * 5e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 6e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * you may not use this file except in compliance with the License. 7e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * You may obtain a copy of the License at 8e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * 9e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 10e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * 11e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * Unless required by applicable law or agreed to in writing, software 12e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 13e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * See the License for the specific language governing permissions and 15e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira * limitations under the License. 16e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira *******************************************************************************/ 17e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 18e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereirapackage com.android.mail.ui; 19e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 20e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport com.android.mail.R; 21e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport com.android.mail.providers.Folder; 22a89424729fe63b635e64037a989958a49fb70cffPaul Westbrookimport com.android.mail.providers.UIProvider.FolderCapabilities; 239695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Caoimport com.android.mail.utils.Utils; 24a7e154530add87e05d1fcee980e1a1fc34a456e7mindypimport com.google.common.base.Objects; 25e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport com.google.common.collect.Lists; 26e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 27e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.content.Context; 28e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.database.Cursor; 2947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport android.net.Uri; 30a7e154530add87e05d1fcee980e1a1fc34a456e7mindypimport android.text.TextUtils; 31e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.view.LayoutInflater; 32e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.view.View; 33e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.view.ViewGroup; 34e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport android.widget.BaseAdapter; 35590c6146482fd90b56afc547605c2193706fbf99Rohan Shahimport android.widget.CheckedTextView; 3641b1c8d641caf29a0699a8080f469b3984fe319eMindy Pereiraimport android.widget.CompoundButton; 37a716ddb162e23aab7c202460e5a475db97a71a8dMindy Pereiraimport android.widget.ImageView; 385a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereiraimport android.widget.TextView; 39e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 4047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport java.util.ArrayDeque; 4133e84f666058dc902a89883f144be4d7baaf50f3Tony Mantlerimport java.util.ArrayList; 4247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport java.util.Deque; 4347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport java.util.HashMap; 44e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport java.util.List; 4547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport java.util.Map; 4647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantlerimport java.util.PriorityQueue; 47e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereiraimport java.util.Set; 48e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 49e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira/** 507a5d95a08464fb82b0310c82f3c39bfb8b63539fVikram Aggarwal * An adapter for translating a cursor of {@link Folder} to a set of selectable views to be used for 5130fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira * applying folders to one or more conversations. 52e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira */ 53e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereirapublic class FolderSelectorAdapter extends BaseAdapter { 54e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 55e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public static class FolderRow implements Comparable<FolderRow> { 56e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira private final Folder mFolder; 5774098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao private boolean mIsSelected; 5847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Filled in during folderSort 5947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler public String mPathName; 60e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 6174098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao public FolderRow(Folder folder, boolean isSelected) { 62e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira mFolder = folder; 6374098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao mIsSelected = isSelected; 64e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 65e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 66e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public Folder getFolder() { 67e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira return mFolder; 68e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 69e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 7074098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao public boolean isSelected() { 7174098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao return mIsSelected; 72e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 73e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 7474098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao public void setIsSelected(boolean isSelected) { 7574098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao mIsSelected = isSelected; 76e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 77e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 78e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira @Override 79e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public int compareTo(FolderRow another) { 80a89424729fe63b635e64037a989958a49fb70cffPaul Westbrook // TODO: this should sort the system folders in the appropriate order 81e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira if (equals(another)) { 82e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira return 0; 83e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } else { 84e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira return mFolder.name.compareToIgnoreCase(another.mFolder.name); 85e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 86e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 87e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 88e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 89e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 90eb86a56580c220e4442951e77e9e7c7658fbf09bVikram Aggarwal protected final List<FolderRow> mFolderRows = Lists.newArrayList(); 91eb86a56580c220e4442951e77e9e7c7658fbf09bVikram Aggarwal private final LayoutInflater mInflater; 92eb86a56580c220e4442951e77e9e7c7658fbf09bVikram Aggarwal private final int mLayout; 93a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp private Folder mExcludedFolder; 94e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 95e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public FolderSelectorAdapter(Context context, Cursor folders, 96106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein Set<String> selected, int layout) { 97e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira mInflater = LayoutInflater.from(context); 98a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp mLayout = layout; 9974098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao createFolderRows(folders, selected); 100e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 101e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 102106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein public FolderSelectorAdapter(Context context, Cursor folders, 103106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein int layout, Folder excludedFolder) { 104a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp mInflater = LayoutInflater.from(context); 105a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp mLayout = layout; 106a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp mExcludedFolder = excludedFolder; 107a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp createFolderRows(folders, null); 108a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp } 109a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp 11074098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao protected void createFolderRows(Cursor folders, Set<String> selected) { 11161cea951d1e813941b80bba7438745541e5133eaMindy Pereira if (folders == null) { 11261cea951d1e813941b80bba7438745541e5133eaMindy Pereira return; 11361cea951d1e813941b80bba7438745541e5133eaMindy Pereira } 11433e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler final List<FolderRow> allFolders = new ArrayList<FolderRow>(folders.getCount()); 11533e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler 116fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao // Rows corresponding to user created, unchecked folders. 11774098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao final List<FolderRow> userFolders = new ArrayList<FolderRow>(); 118fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao // Rows corresponding to system created, unchecked folders. 11974098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao final List<FolderRow> systemFolders = new ArrayList<FolderRow>(); 120fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao 121a6f1e1013f234123eb52bc3e36228a0cffb76092mindyp if (folders.moveToFirst()) { 122a6f1e1013f234123eb52bc3e36228a0cffb76092mindyp do { 123a6f1e1013f234123eb52bc3e36228a0cffb76092mindyp final Folder folder = new Folder(folders); 12474098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao final boolean isSelected = selected != null 12574098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao && selected.contains( 12633e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler folder.folderUri.getComparisonUri().toString()); 12733e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler final FolderRow row = new FolderRow(folder, isSelected); 12833e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler allFolders.add(row); 129fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao 130fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao // Add system folders here since we want the original unsorted order (for now..) 1318300fe7192c5511c2de7fca1e4abb198c06678b2Jin Cao if (meetsRequirements(folder) && !Objects.equal(folder, mExcludedFolder) && 1328300fe7192c5511c2de7fca1e4abb198c06678b2Jin Cao folder.isProviderFolder()) { 13374098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao systemFolders.add(row); 134fc57e7c8ad3fba409e2eab312fa7a1da3ccc690cJin Cao } 135a6f1e1013f234123eb52bc3e36228a0cffb76092mindyp } while (folders.moveToNext()); 136a6f1e1013f234123eb52bc3e36228a0cffb76092mindyp } 13733e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler // Need to do the foldersort first with all folders present to avoid dropping orphans 13833e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler folderSort(allFolders); 13933e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler 14033e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler // Divert the folders to the appropriate sections 14133e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler for (final FolderRow row : allFolders) { 14233e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler final Folder folder = row.getFolder(); 14374098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao if (meetsRequirements(folder) && !Objects.equal(folder, mExcludedFolder) && 14474098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao !folder.isProviderFolder()) { 14574098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao userFolders.add(row); 14633e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler } 14733e84f666058dc902a89883f144be4d7baaf50f3Tony Mantler } 14874098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao mFolderRows.addAll(systemFolders); 14974098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao mFolderRows.addAll(userFolders); 150e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 151e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 1525650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira /** 15347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Wrapper class to construct a hierarchy tree of FolderRow objects for sorting 15447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler */ 15547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler private static class TreeNode implements Comparable<TreeNode> { 15647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler public FolderRow mWrappedObject; 15747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final public PriorityQueue<TreeNode> mChildren = new PriorityQueue<TreeNode>(); 15847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler public boolean mAddedToList = false; 15947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 16047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TreeNode(FolderRow wrappedObject) { 16147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler mWrappedObject = wrappedObject; 16247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 16347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 16447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler void addChild(final TreeNode child) { 16547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler mChildren.add(child); 16647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 16747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 16847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TreeNode pollChild() { 16947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler return mChildren.poll(); 17047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 17147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 17247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler @Override 17347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler public int compareTo(TreeNode o) { 17447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // mWrappedObject is always non-null here because we set it before we add this object 17547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // to a sorted collection, otherwise we wouldn't have known what collection to add it to 17647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler return mWrappedObject.compareTo(o.mWrappedObject); 17747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 17847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 17947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 18047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler /** 18147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Sorts the folder list according to hierarchy. 18247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * If no parent information exists this basically just turns into a heap sort 18347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * 18447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * How this works: 18547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * When the first part of this algorithm completes, we want to have a tree of TreeNode objects 18647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * mirroring the hierarchy of mailboxes/folders in the user's account, but we don't have any 18747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * guarantee that we'll see the parents before their respective children. 18847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * First we check the nodeMap to see if we've already pre-created (see below) a TreeNode for 18947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * the current FolderRow, and if not then we create one now. 19047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Then for each folder, we check to see if the parent TreeNode has already been created. We 19147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * special case the root node. If we don't find the parent node, then we pre-create one to fill 19247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * in later (see above) when we eventually find the parent's entry. 19347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Whenever we create a new TreeNode we add it to the nodeMap keyed on the folder's provider 19447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Uri, so that we can find it later either to add children or to retrieve a half-created node. 19547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * It should be noted that it is only valid to add a child node after the mWrappedObject 19647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * member variable has been set. 19747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * Finally we do a depth-first traversal of the constructed tree to re-fill the folderList in 19847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * hierarchical order. 19947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * @param folderList List of {@link Folder} objects to sort 20047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler */ 20147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler private void folderSort(final List<FolderRow> folderList) { 20247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final TreeNode root = new TreeNode(null); 20347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Make double-sure we don't accidentally add the root node to the final list 20447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler root.mAddedToList = true; 20547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Map from folder Uri to TreeNode containing said folder 20647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final Map<Uri, TreeNode> nodeMap = new HashMap<Uri, TreeNode>(folderList.size()); 20747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler nodeMap.put(Uri.EMPTY, root); 20847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 20947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler for (final FolderRow folderRow : folderList) { 21047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final Folder folder = folderRow.mFolder; 21147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Find-and-complete or create the TreeNode wrapper 21247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TreeNode node = nodeMap.get(folder.folderUri.getComparisonUri()); 21347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (node == null) { 21447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler node = new TreeNode(folderRow); 21547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler nodeMap.put(folder.folderUri.getComparisonUri(), node); 21647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } else { 21747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler node.mWrappedObject = folderRow; 21847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 21947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Special case the top level folders 2209695e0046f79bd2d7166a411d6feff4cf0fb2539Jin Cao if (Utils.isEmpty(folderRow.mFolder.parent)) { 22147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler root.addChild(node); 22247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } else { 22347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Find or half-create the parent TreeNode wrapper 22447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TreeNode parentNode = nodeMap.get(folder.parent); 22547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (parentNode == null) { 22647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler parentNode = new TreeNode(null); 22747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler nodeMap.put(folder.parent, parentNode); 22847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 22947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler parentNode.addChild(node); 23047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 23147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 23247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 23347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler folderList.clear(); 23447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 23547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Depth-first traversal of the constructed tree. Flattens the tree back into the 23647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // folderList list and sets mPathName in the FolderRow objects 23747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final Deque<TreeNode> stack = new ArrayDeque<TreeNode>(10); 23847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler stack.push(root); 23947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TreeNode currentNode; 24047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler while ((currentNode = stack.poll()) != null) { 24147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final TreeNode parentNode = stack.peek(); 24247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // If parentNode is null then currentNode is the root node (not a real folder) 24347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // If mAddedToList is true it means we've seen this node before and just want to 24447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // iterate the children. 24547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (parentNode != null && !currentNode.mAddedToList) { 24647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final String pathName; 24747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // If the wrapped object is null then the parent is the root 24847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (parentNode.mWrappedObject == null || 24947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler TextUtils.isEmpty(parentNode.mWrappedObject.mPathName)) { 25047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler pathName = currentNode.mWrappedObject.mFolder.name; 25147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } else { 25247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler /** 25347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * This path name is re-split at / characters in 25447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler * {@link HierarchicalFolderSelectorAdapter#truncateHierarchy} 25547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler */ 25647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler pathName = parentNode.mWrappedObject.mPathName + "/" 25747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler + currentNode.mWrappedObject.mFolder.name; 25847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 25947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler currentNode.mWrappedObject.mPathName = pathName; 26047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler folderList.add(currentNode.mWrappedObject); 26147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // Mark this node as done so we don't re-add it 26247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler currentNode.mAddedToList = true; 26347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 26447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final TreeNode childNode = currentNode.pollChild(); 26547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (childNode != null) { 26647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // If we have children to deal with, re-push the current node as the parent... 26747ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler stack.push(currentNode); 26847ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // ... then add the child node and loop around to deal with it... 26947ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler stack.push(childNode); 27047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 27147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler // ... otherwise we're done with currentNode 27247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 27347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } 27447ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler 27547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler /** 2765650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira * Return whether the supplied folder meets the requirements to be displayed 2775650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira * in the folder list. 2785650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira */ 2795650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira protected boolean meetsRequirements(Folder folder) { 2805650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira // We only want to show the non-Trash folders that can accept moved messages 2815650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira return folder.supportsCapability(FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES) && 2828c1058ee75ec4a5824a68c3c5275bc48d56bbad8Scott Kennedy !folder.isTrash() && !Objects.equal(folder, mExcludedFolder); 2835650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira } 2845650bb59fd9bb351ee94e44a32256e717048ed63Mindy Pereira 285e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira @Override 286e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public int getCount() { 287106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein return mFolderRows.size(); 288e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 289e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 290e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira @Override 2915a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira public Object getItem(int position) { 292106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein return mFolderRows.get(position); 293e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 294e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 295e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira @Override 296e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public long getItemId(int position) { 297e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira return position; 298e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 299e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira 300e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira @Override 3015a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira public int getItemViewType(int position) { 302106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein return SeparatedFolderListAdapter.TYPE_ITEM; 3035a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira } 3045a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira 3055a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira @Override 3065a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira public int getViewTypeCount() { 307106a12a1b6642e8c2f716aefa846d9664fbec158Andrew Sapperstein return 1; 308723ca34b4f74191a014055194dceb1a12a8127c5Vikram Aggarwal } 309723ca34b4f74191a014055194dceb1a12a8127c5Vikram Aggarwal 3105a5859d34d44ed4cbe0a4658eec76ffe466f4bddMindy Pereira @Override 311e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 31247ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final View view; 31347ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler if (convertView == null) { 314a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp view = mInflater.inflate(mLayout, parent, false); 31547ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler } else { 31647ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler view = convertView; 317a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp } 3187ac3d4ea760a5b2eef1a1f5476f25747027c2883Paul Westbrook final FolderRow row = (FolderRow) getItem(position); 3197ac3d4ea760a5b2eef1a1f5476f25747027c2883Paul Westbrook final Folder folder = row.getFolder(); 32047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final String folderDisplay = !TextUtils.isEmpty(row.mPathName) ? 32147ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler row.mPathName : folder.name; 322590c6146482fd90b56afc547605c2193706fbf99Rohan Shah final CheckedTextView checkBox = (CheckedTextView) view.findViewById(R.id.checkbox); 323a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp if (checkBox != null) { 324a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp // Suppress the checkbox selection, and handle the toggling of the 325a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp // folder on the parent list item's click handler. 326a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp checkBox.setClickable(false); 327a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp checkBox.setText(folderDisplay); 32874098779f90c61487ff0b5bbb7a458f0a8818047Jin Cao checkBox.setChecked(row.isSelected()); 329a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp } 33047ce8047c208f3268f31bd7ef7eb5392b670ea8aTony Mantler final TextView display = (TextView) view.findViewById(R.id.folder_name); 331a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp if (display != null) { 332a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp display.setText(folderDisplay); 333a7e154530add87e05d1fcee980e1a1fc34a456e7mindyp } 334cc2e1ee5ea19d1b166a7542ea03f4fd4e5c807e3Rohan Shah 335cc2e1ee5ea19d1b166a7542ea03f4fd4e5c807e3Rohan Shah final ImageView folderIcon = (ImageView) view.findViewById(R.id.folder_icon); 336590c6146482fd90b56afc547605c2193706fbf99Rohan Shah Folder.setIcon(folder, folderIcon); 337e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira return view; 338e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira } 339e234cb1ef4285cb6061a18b95ec5dd49ed119f5cMindy Pereira} 340