Folder.java revision 518ee42d4f5cfbcac07dc61fdcac4de8c32c0e26
1/******************************************************************************* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 *******************************************************************************/ 17 18package com.android.mail.providers; 19 20import android.database.Cursor; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.text.TextUtils; 24 25import com.android.mail.utils.LogUtils; 26import com.google.common.collect.Maps; 27 28import java.util.Collection; 29import java.util.Map; 30import java.util.regex.Pattern; 31 32/** 33 * A folder is a collection of conversations, and perhaps other folders. 34 */ 35public class Folder implements Parcelable { 36 /** 37 * 38 */ 39 private static final String FOLDER_UNINITIALIZED = "Uninitialized!"; 40 41 // Try to match the order of members with the order of constants in UIProvider. 42 43 /** 44 * Unique id of this folder. 45 */ 46 public String id; 47 48 /** 49 * The content provider URI that returns this folder for this account. 50 */ 51 public String uri; 52 53 /** 54 * The human visible name for this folder. 55 */ 56 public String name; 57 58 /** 59 * The possible capabilities that this folder supports. 60 */ 61 public int capabilities; 62 63 /** 64 * Whether or not this folder has children folders. 65 */ 66 public boolean hasChildren; 67 68 /** 69 * How large the synchronization window is: how many days worth of data is retained on the 70 * device. 71 */ 72 public int syncWindow; 73 74 /** 75 * The content provider URI to return the list of conversations in this 76 * folder. 77 */ 78 public String conversationListUri; 79 80 /** 81 * The content provider URI to return the list of child folders of this folder. 82 */ 83 public String childFoldersListUri; 84 85 /** 86 * The number of messages that are unread in this folder. 87 */ 88 public int unreadCount; 89 90 /** 91 * The total number of messages in this folder. 92 */ 93 public int totalCount; 94 95 /** 96 * The content provider URI to force a refresh of this folder. 97 */ 98 public String refreshUri; 99 100 /** 101 * The current sync status of the folder 102 */ 103 public int syncStatus; 104 105 /** 106 * The result of the last sync for this folder 107 */ 108 public int lastSyncResult; 109 110 /** 111 * Total number of members that comprise an instance of a folder. This is 112 * the number of members that need to be serialized or parceled. 113 */ 114 private static final int NUMBER_MEMBERS = UIProvider.FOLDERS_PROJECTION.length; 115 116 /** 117 * Used only for debugging. 118 */ 119 private static final String LOG_TAG = new LogUtils().getLogTag(); 120 121 /** 122 * Examples of expected format for the joined folder strings 123 * 124 * Example of a joined folder string: 125 * 630107622^*^^i^*^^i^*^0 126 * <id>^*^<canonical name>^*^<name>^*^<color index> 127 * 128 * The sqlite queries will return a list of folder strings separated with "^**^" 129 * Example of a query result: 130 * 630107622^*^^i^*^^i^*^0^**^630107626^*^^u^*^^u^*^0^**^630107627^*^^f^*^^f^*^0 131 */ 132 private static final String FOLDER_COMPONENT_SEPARATOR = "^*^"; 133 private static final Pattern FOLDER_COMPONENT_SEPARATOR_PATTERN = 134 Pattern.compile("\\^\\*\\^"); 135 136 private static final String FOLDER_SEPARATOR = "^**^"; 137 138 public Folder(Parcel in) { 139 id = in.readString(); 140 uri = in.readString(); 141 name = in.readString(); 142 capabilities = in.readInt(); 143 // 1 for true, 0 for false. 144 hasChildren = in.readInt() == 1; 145 syncWindow = in.readInt(); 146 conversationListUri = in.readString(); 147 childFoldersListUri = in.readString(); 148 unreadCount = in.readInt(); 149 totalCount = in.readInt(); 150 refreshUri = in.readString(); 151 syncStatus = in.readInt(); 152 lastSyncResult = in.readInt(); 153 } 154 155 public Folder(Cursor cursor) { 156 id = cursor.getString(UIProvider.FOLDER_ID_COLUMN); 157 uri = cursor.getString(UIProvider.FOLDER_URI_COLUMN); 158 name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN); 159 capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN); 160 // 1 for true, 0 for false. 161 hasChildren = cursor.getInt(UIProvider.FOLDER_HAS_CHILDREN_COLUMN) == 1; 162 syncWindow = cursor.getInt(UIProvider.FOLDER_SYNC_WINDOW_COLUMN); 163 conversationListUri = cursor.getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN); 164 childFoldersListUri = cursor.getString(UIProvider.FOLDER_CHILD_FOLDERS_LIST_COLUMN); 165 unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN); 166 totalCount = cursor.getInt(UIProvider.FOLDER_TOTAL_COUNT_COLUMN); 167 refreshUri = cursor.getString(UIProvider.FOLDER_REFRESH_URI_COLUMN); 168 syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN); 169 lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN); 170 } 171 172 @Override 173 public void writeToParcel(Parcel dest, int flags) { 174 dest.writeString(id); 175 dest.writeString(uri); 176 dest.writeString(name); 177 dest.writeInt(capabilities); 178 // 1 for true, 0 for false. 179 dest.writeInt(hasChildren ? 1 : 0); 180 dest.writeInt(syncWindow); 181 dest.writeString(conversationListUri); 182 dest.writeString(childFoldersListUri); 183 dest.writeInt(unreadCount); 184 dest.writeInt(totalCount); 185 dest.writeString(refreshUri); 186 dest.writeInt(syncStatus); 187 dest.writeInt(lastSyncResult); 188 } 189 190 /** 191 * Return a serialized String for this folder. 192 */ 193 public synchronized String serialize(){ 194 StringBuilder out = new StringBuilder(); 195 out.append(id).append(FOLDER_COMPONENT_SEPARATOR); 196 out.append(uri).append(FOLDER_COMPONENT_SEPARATOR); 197 out.append(name).append(FOLDER_COMPONENT_SEPARATOR); 198 out.append(capabilities).append(FOLDER_COMPONENT_SEPARATOR); 199 out.append(hasChildren ? "1": "0").append(FOLDER_COMPONENT_SEPARATOR); 200 out.append(syncWindow).append(FOLDER_COMPONENT_SEPARATOR); 201 out.append(conversationListUri).append(FOLDER_COMPONENT_SEPARATOR); 202 out.append(childFoldersListUri).append(FOLDER_COMPONENT_SEPARATOR); 203 out.append(unreadCount).append(FOLDER_COMPONENT_SEPARATOR); 204 out.append(totalCount).append(FOLDER_COMPONENT_SEPARATOR); 205 out.append(refreshUri).append(FOLDER_COMPONENT_SEPARATOR); 206 out.append(syncStatus).append(FOLDER_COMPONENT_SEPARATOR); 207 out.append(lastSyncResult); 208 return out.toString(); 209 } 210 211 /** 212 * Construct a new Folder instance from a previously serialized string. 213 * @param serializedFolder string obtained from {@link #serialize()} on a valid folder. 214 */ 215 public Folder(String serializedFolder){ 216 String[] folderMembers = TextUtils.split(serializedFolder, 217 FOLDER_COMPONENT_SEPARATOR_PATTERN); 218 if (folderMembers.length != NUMBER_MEMBERS) { 219 throw new IllegalArgumentException( 220 "Folder de-serializing failed. Wrong number of members detected."); 221 } 222 id = folderMembers[0]; 223 uri = folderMembers[1]; 224 name = folderMembers[2]; 225 capabilities = Integer.valueOf(folderMembers[3]); 226 // 1 for true, 0 for false 227 hasChildren = folderMembers[4] == "1"; 228 syncWindow = Integer.valueOf(folderMembers[5]); 229 conversationListUri = folderMembers[6]; 230 childFoldersListUri = folderMembers[7]; 231 unreadCount = Integer.valueOf(folderMembers[8]); 232 totalCount = Integer.valueOf(folderMembers[9]); 233 refreshUri = folderMembers[10]; 234 syncStatus = Integer.valueOf(folderMembers[11]); 235 lastSyncResult = Integer.valueOf(folderMembers[12]); 236 } 237 238 /** 239 * Constructor that leaves everything uninitialized. For use only by {@link #serialize()} 240 * which is responsible for filling in all the fields 241 */ 242 public Folder() { 243 name = FOLDER_UNINITIALIZED; 244 } 245 246 @SuppressWarnings("hiding") 247 public static final Creator<Folder> CREATOR = new Creator<Folder>() { 248 @Override 249 public Folder createFromParcel(Parcel source) { 250 return new Folder(source); 251 } 252 253 @Override 254 public Folder[] newArray(int size) { 255 return new Folder[size]; 256 } 257 }; 258 259 @Override 260 public int describeContents() { 261 // Return a sort of version number for this parcelable folder. Starting with zero. 262 return 0; 263 } 264 265 /** 266 * Create a Folder map from a string of serialized folders. This can only be done on the output 267 * of {@link #serialize(Map)}. 268 * @param serializedFolder A string obtained from {@link #serialize(Map)} 269 * @return a Map of folder name to folder. 270 */ 271 public static Map<String, Folder> parseFoldersFromString(String serializedFolder) { 272 LogUtils.d(LOG_TAG, "folder query result: %s", serializedFolder); 273 274 Map<String, Folder> folderMap = Maps.newHashMap(); 275 if (serializedFolder == null || serializedFolder == "") { 276 return folderMap; 277 } 278 String[] folderPieces = TextUtils.split( 279 serializedFolder, FOLDER_COMPONENT_SEPARATOR_PATTERN); 280 for (int i = 0, n = folderPieces.length; i < n; i++) { 281 Folder folder = new Folder(folderPieces[i]); 282 if (folder.name != FOLDER_UNINITIALIZED) { 283 folderMap.put(folder.name, folder); 284 } 285 } 286 return folderMap; 287 } 288 289 /** 290 * Returns a boolean indicating whether network activity (sync) is occuring for this folder. 291 */ 292 public boolean isSyncInProgress() { 293 return 0 != (syncStatus & (UIProvider.SyncStatus.BACKGROUND_SYNC | 294 UIProvider.SyncStatus.USER_REFRESH | 295 UIProvider.SyncStatus.USER_QUERY | 296 UIProvider.SyncStatus.USER_MORE_RESULTS)); 297 } 298 299 /** 300 * Serialize the given list of folders 301 * @param folderMap A valid map of folder names to Folders 302 * @return a string containing a serialized output of folder maps. 303 */ 304 public static String serialize(Map<String, Folder> folderMap) { 305 Collection<Folder> folderCollection = folderMap.values(); 306 Folder[] folderList = folderCollection.toArray(new Folder[]{} ); 307 int numFolders = folderList.length; 308 StringBuilder result = new StringBuilder(); 309 for (int i = 0; i < numFolders; i++) { 310 if (i > 0) { 311 result.append(FOLDER_SEPARATOR); 312 } 313 Folder folder = folderList[i]; 314 result.append(folder.serialize()); 315 } 316 return result.toString(); 317 } 318 319 public boolean supportsCapability(int capability) { 320 return (capabilities & capability) != 0; 321 } 322} 323