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