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