Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.documentsui.model; |
| 18 | |
Jeff Sharkey | ded7718 | 2013-09-03 14:17:06 -0700 | [diff] [blame] | 19 | import android.content.ContentProviderClient; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 20 | import android.content.ContentResolver; |
| 21 | import android.database.Cursor; |
| 22 | import android.net.Uri; |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 23 | import android.os.Parcel; |
| 24 | import android.os.Parcelable; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 25 | import android.provider.DocumentsContract; |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 26 | import android.provider.DocumentsContract.Document; |
Jeff Sharkey | 7aa7601 | 2013-09-30 14:26:27 -0700 | [diff] [blame] | 27 | import android.provider.DocumentsProvider; |
Steve McKay | d3afdee | 2015-11-19 17:27:12 -0800 | [diff] [blame] | 28 | import android.support.annotation.VisibleForTesting; |
Jeff Sharkey | fa5ec77 | 2014-08-05 17:55:16 -0700 | [diff] [blame] | 29 | import android.text.TextUtils; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 30 | |
Jeff Sharkey | 7aa7601 | 2013-09-30 14:26:27 -0700 | [diff] [blame] | 31 | import com.android.documentsui.DocumentsApplication; |
Jeff Sharkey | 251097b | 2013-09-02 15:07:28 -0700 | [diff] [blame] | 32 | import com.android.documentsui.RootCursorWrapper; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 33 | |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 34 | import libcore.io.IoUtils; |
| 35 | |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 36 | import java.io.DataInputStream; |
| 37 | import java.io.DataOutputStream; |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 38 | import java.io.FileNotFoundException; |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 39 | import java.io.IOException; |
| 40 | import java.net.ProtocolException; |
Jeff Sharkey | fa5ec77 | 2014-08-05 17:55:16 -0700 | [diff] [blame] | 41 | import java.text.Collator; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 42 | |
| 43 | /** |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 44 | * Representation of a {@link Document}. |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 45 | */ |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 46 | public class DocumentInfo implements Durable, Parcelable { |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 47 | private static final int VERSION_INIT = 1; |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 48 | private static final int VERSION_SPLIT_URI = 2; |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 49 | |
Jeff Sharkey | fa5ec77 | 2014-08-05 17:55:16 -0700 | [diff] [blame] | 50 | private static final Collator sCollator; |
| 51 | |
| 52 | static { |
| 53 | sCollator = Collator.getInstance(); |
| 54 | sCollator.setStrength(Collator.SECONDARY); |
| 55 | } |
| 56 | |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 57 | public String authority; |
| 58 | public String documentId; |
Jeff Sharkey | 5dfb345 | 2013-08-31 21:27:44 -0700 | [diff] [blame] | 59 | public String mimeType; |
| 60 | public String displayName; |
| 61 | public long lastModified; |
| 62 | public int flags; |
| 63 | public String summary; |
| 64 | public long size; |
| 65 | public int icon; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 66 | |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 67 | /** Derived fields that aren't persisted */ |
| 68 | public Uri derivedUri; |
| 69 | |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 70 | public DocumentInfo() { |
| 71 | reset(); |
| 72 | } |
| 73 | |
| 74 | @Override |
| 75 | public void reset() { |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 76 | authority = null; |
| 77 | documentId = null; |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 78 | mimeType = null; |
| 79 | displayName = null; |
| 80 | lastModified = -1; |
| 81 | flags = 0; |
| 82 | summary = null; |
| 83 | size = -1; |
| 84 | icon = 0; |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 85 | |
| 86 | derivedUri = null; |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | @Override |
| 90 | public void read(DataInputStream in) throws IOException { |
| 91 | final int version = in.readInt(); |
| 92 | switch (version) { |
| 93 | case VERSION_INIT: |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 94 | throw new ProtocolException("Ignored upgrade"); |
| 95 | case VERSION_SPLIT_URI: |
| 96 | authority = DurableUtils.readNullableString(in); |
| 97 | documentId = DurableUtils.readNullableString(in); |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 98 | mimeType = DurableUtils.readNullableString(in); |
| 99 | displayName = DurableUtils.readNullableString(in); |
| 100 | lastModified = in.readLong(); |
| 101 | flags = in.readInt(); |
| 102 | summary = DurableUtils.readNullableString(in); |
| 103 | size = in.readLong(); |
| 104 | icon = in.readInt(); |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 105 | deriveFields(); |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 106 | break; |
| 107 | default: |
| 108 | throw new ProtocolException("Unknown version " + version); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | @Override |
| 113 | public void write(DataOutputStream out) throws IOException { |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 114 | out.writeInt(VERSION_SPLIT_URI); |
| 115 | DurableUtils.writeNullableString(out, authority); |
| 116 | DurableUtils.writeNullableString(out, documentId); |
Jeff Sharkey | b513311 | 2013-09-01 18:41:04 -0700 | [diff] [blame] | 117 | DurableUtils.writeNullableString(out, mimeType); |
| 118 | DurableUtils.writeNullableString(out, displayName); |
| 119 | out.writeLong(lastModified); |
| 120 | out.writeInt(flags); |
| 121 | DurableUtils.writeNullableString(out, summary); |
| 122 | out.writeLong(size); |
| 123 | out.writeInt(icon); |
| 124 | } |
| 125 | |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 126 | @Override |
| 127 | public int describeContents() { |
| 128 | return 0; |
| 129 | } |
| 130 | |
| 131 | @Override |
| 132 | public void writeToParcel(Parcel dest, int flags) { |
| 133 | DurableUtils.writeToParcel(dest, this); |
| 134 | } |
| 135 | |
| 136 | public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() { |
| 137 | @Override |
| 138 | public DocumentInfo createFromParcel(Parcel in) { |
| 139 | final DocumentInfo doc = new DocumentInfo(); |
| 140 | DurableUtils.readFromParcel(in, doc); |
| 141 | return doc; |
| 142 | } |
| 143 | |
| 144 | @Override |
| 145 | public DocumentInfo[] newArray(int size) { |
| 146 | return new DocumentInfo[size]; |
| 147 | } |
| 148 | }; |
| 149 | |
Jeff Sharkey | 251097b | 2013-09-02 15:07:28 -0700 | [diff] [blame] | 150 | public static DocumentInfo fromDirectoryCursor(Cursor cursor) { |
Jeff Sharkey | 251097b | 2013-09-02 15:07:28 -0700 | [diff] [blame] | 151 | final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY); |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 152 | return fromCursor(cursor, authority); |
| 153 | } |
| 154 | |
| 155 | public static DocumentInfo fromCursor(Cursor cursor, String authority) { |
Jeff Sharkey | deffade | 2013-09-24 12:07:12 -0700 | [diff] [blame] | 156 | final DocumentInfo info = new DocumentInfo(); |
| 157 | info.updateFromCursor(cursor, authority); |
| 158 | return info; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 159 | } |
| 160 | |
Jeff Sharkey | deffade | 2013-09-24 12:07:12 -0700 | [diff] [blame] | 161 | public void updateFromCursor(Cursor cursor, String authority) { |
| 162 | this.authority = authority; |
| 163 | this.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); |
| 164 | this.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); |
Jeff Sharkey | deffade | 2013-09-24 12:07:12 -0700 | [diff] [blame] | 165 | this.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); |
| 166 | this.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED); |
| 167 | this.flags = getCursorInt(cursor, Document.COLUMN_FLAGS); |
| 168 | this.summary = getCursorString(cursor, Document.COLUMN_SUMMARY); |
| 169 | this.size = getCursorLong(cursor, Document.COLUMN_SIZE); |
| 170 | this.icon = getCursorInt(cursor, Document.COLUMN_ICON); |
| 171 | this.deriveFields(); |
| 172 | } |
| 173 | |
| 174 | public static DocumentInfo fromUri(ContentResolver resolver, Uri uri) |
| 175 | throws FileNotFoundException { |
| 176 | final DocumentInfo info = new DocumentInfo(); |
| 177 | info.updateFromUri(resolver, uri); |
| 178 | return info; |
| 179 | } |
| 180 | |
| 181 | /** |
| 182 | * Update a possibly stale restored document against a live |
| 183 | * {@link DocumentsProvider}. |
| 184 | */ |
| 185 | public void updateSelf(ContentResolver resolver) throws FileNotFoundException { |
| 186 | updateFromUri(resolver, derivedUri); |
| 187 | } |
| 188 | |
| 189 | public void updateFromUri(ContentResolver resolver, Uri uri) throws FileNotFoundException { |
Jeff Sharkey | 7aa7601 | 2013-09-30 14:26:27 -0700 | [diff] [blame] | 190 | ContentProviderClient client = null; |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 191 | Cursor cursor = null; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 192 | try { |
Jeff Sharkey | 7aa7601 | 2013-09-30 14:26:27 -0700 | [diff] [blame] | 193 | client = DocumentsApplication.acquireUnstableProviderOrThrow( |
| 194 | resolver, uri.getAuthority()); |
Jeff Sharkey | ded7718 | 2013-09-03 14:17:06 -0700 | [diff] [blame] | 195 | cursor = client.query(uri, null, null, null, null); |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 196 | if (!cursor.moveToFirst()) { |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 197 | throw new FileNotFoundException("Missing details for " + uri); |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 198 | } |
Jeff Sharkey | deffade | 2013-09-24 12:07:12 -0700 | [diff] [blame] | 199 | updateFromCursor(cursor, uri.getAuthority()); |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 200 | } catch (Throwable t) { |
| 201 | throw asFileNotFoundException(t); |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 202 | } finally { |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 203 | IoUtils.closeQuietly(cursor); |
Jeff Sharkey | 7aa7601 | 2013-09-30 14:26:27 -0700 | [diff] [blame] | 204 | ContentProviderClient.releaseQuietly(client); |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 205 | } |
| 206 | } |
| 207 | |
Steve McKay | d3afdee | 2015-11-19 17:27:12 -0800 | [diff] [blame] | 208 | @VisibleForTesting |
| 209 | void deriveFields() { |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 210 | derivedUri = DocumentsContract.buildDocumentUri(authority, documentId); |
| 211 | } |
| 212 | |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 213 | @Override |
| 214 | public String toString() { |
Steve McKay | d3afdee | 2015-11-19 17:27:12 -0800 | [diff] [blame] | 215 | return "Document{" |
| 216 | + "docId=" + documentId |
| 217 | + ", name=" + displayName |
| 218 | + ", isDirectory=" + isDirectory() |
| 219 | + "}"; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 220 | } |
| 221 | |
| 222 | public boolean isCreateSupported() { |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 223 | return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 224 | } |
| 225 | |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 226 | public boolean isThumbnailSupported() { |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 227 | return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 228 | } |
| 229 | |
Jeff Sharkey | b156f4b | 2013-08-06 16:26:14 -0700 | [diff] [blame] | 230 | public boolean isDirectory() { |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 231 | return Document.MIME_TYPE_DIR.equals(mimeType); |
Jeff Sharkey | b156f4b | 2013-08-06 16:26:14 -0700 | [diff] [blame] | 232 | } |
| 233 | |
Jeff Sharkey | 4eb407a | 2013-08-18 17:38:20 -0700 | [diff] [blame] | 234 | public boolean isGridPreferred() { |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 235 | return (flags & Document.FLAG_DIR_PREFERS_GRID) != 0; |
Jeff Sharkey | 4eb407a | 2013-08-18 17:38:20 -0700 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | public boolean isDeleteSupported() { |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 239 | return (flags & Document.FLAG_SUPPORTS_DELETE) != 0; |
Jeff Sharkey | 4eb407a | 2013-08-18 17:38:20 -0700 | [diff] [blame] | 240 | } |
| 241 | |
Jeff Sharkey | f6db154 | 2013-09-13 13:42:19 -0700 | [diff] [blame] | 242 | public boolean isGridTitlesHidden() { |
| 243 | return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0; |
| 244 | } |
| 245 | |
Tomasz Mikolajewski | 39acff5 | 2015-11-25 13:01:18 +0900 | [diff] [blame] | 246 | public boolean isArchive() { |
| 247 | return (flags & Document.FLAG_ARCHIVE) != 0; |
| 248 | } |
| 249 | |
| 250 | public boolean isContainer() { |
| 251 | return isDirectory() || isArchive(); |
| 252 | } |
| 253 | |
Steve McKay | d3afdee | 2015-11-19 17:27:12 -0800 | [diff] [blame] | 254 | public int hashCode() { |
| 255 | return derivedUri.hashCode() + mimeType.hashCode(); |
| 256 | } |
| 257 | |
| 258 | public boolean equals(Object other) { |
| 259 | if (this == other) { |
| 260 | return true; |
| 261 | } else if (!(other instanceof DocumentInfo)) { |
| 262 | return false; |
| 263 | } |
| 264 | |
| 265 | DocumentInfo that = (DocumentInfo) other; |
| 266 | // Uri + mime type should be totally unique. |
| 267 | return derivedUri.equals(that.derivedUri) && mimeType.equals(that.mimeType); |
| 268 | } |
| 269 | |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 270 | public static String getCursorString(Cursor cursor, String columnName) { |
Jeff Sharkey | b156f4b | 2013-08-06 16:26:14 -0700 | [diff] [blame] | 271 | final int index = cursor.getColumnIndex(columnName); |
| 272 | return (index != -1) ? cursor.getString(index) : null; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 273 | } |
| 274 | |
Jeff Sharkey | a5599ef | 2013-08-15 16:17:41 -0700 | [diff] [blame] | 275 | /** |
| 276 | * Missing or null values are returned as -1. |
| 277 | */ |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 278 | public static long getCursorLong(Cursor cursor, String columnName) { |
Jeff Sharkey | b156f4b | 2013-08-06 16:26:14 -0700 | [diff] [blame] | 279 | final int index = cursor.getColumnIndex(columnName); |
Jeff Sharkey | a5599ef | 2013-08-15 16:17:41 -0700 | [diff] [blame] | 280 | if (index == -1) return -1; |
| 281 | final String value = cursor.getString(index); |
| 282 | if (value == null) return -1; |
| 283 | try { |
| 284 | return Long.parseLong(value); |
| 285 | } catch (NumberFormatException e) { |
| 286 | return -1; |
| 287 | } |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 288 | } |
| 289 | |
Jeff Sharkey | d182bb6 | 2013-09-07 14:45:03 -0700 | [diff] [blame] | 290 | /** |
| 291 | * Missing or null values are returned as 0. |
| 292 | */ |
Jeff Sharkey | ae9b51b | 2013-08-31 15:02:20 -0700 | [diff] [blame] | 293 | public static int getCursorInt(Cursor cursor, String columnName) { |
Jeff Sharkey | b156f4b | 2013-08-06 16:26:14 -0700 | [diff] [blame] | 294 | final int index = cursor.getColumnIndex(columnName); |
| 295 | return (index != -1) ? cursor.getInt(index) : 0; |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 296 | } |
| 297 | |
Jeff Sharkey | 0c2d31b | 2013-08-07 18:33:33 -0700 | [diff] [blame] | 298 | public static FileNotFoundException asFileNotFoundException(Throwable t) |
| 299 | throws FileNotFoundException { |
| 300 | if (t instanceof FileNotFoundException) { |
| 301 | throw (FileNotFoundException) t; |
| 302 | } |
| 303 | final FileNotFoundException fnfe = new FileNotFoundException(t.getMessage()); |
| 304 | fnfe.initCause(t); |
| 305 | throw fnfe; |
| 306 | } |
Jeff Sharkey | aeb16e2 | 2013-08-27 18:26:48 -0700 | [diff] [blame] | 307 | |
Jeff Sharkey | fa5ec77 | 2014-08-05 17:55:16 -0700 | [diff] [blame] | 308 | /** |
| 309 | * String prefix used to indicate the document is a directory. |
| 310 | */ |
| 311 | public static final char DIR_PREFIX = '\001'; |
| 312 | |
| 313 | /** |
| 314 | * Compare two strings against each other using system default collator in a |
| 315 | * case-insensitive mode. Clusters strings prefixed with {@link #DIR_PREFIX} |
| 316 | * before other items. |
| 317 | */ |
Jeff Sharkey | aeb16e2 | 2013-08-27 18:26:48 -0700 | [diff] [blame] | 318 | public static int compareToIgnoreCaseNullable(String lhs, String rhs) { |
Jeff Sharkey | fa5ec77 | 2014-08-05 17:55:16 -0700 | [diff] [blame] | 319 | final boolean leftEmpty = TextUtils.isEmpty(lhs); |
| 320 | final boolean rightEmpty = TextUtils.isEmpty(rhs); |
| 321 | |
| 322 | if (leftEmpty && rightEmpty) return 0; |
| 323 | if (leftEmpty) return -1; |
| 324 | if (rightEmpty) return 1; |
| 325 | |
| 326 | final boolean leftDir = (lhs.charAt(0) == DIR_PREFIX); |
| 327 | final boolean rightDir = (rhs.charAt(0) == DIR_PREFIX); |
| 328 | |
| 329 | if (leftDir && !rightDir) return -1; |
| 330 | if (rightDir && !leftDir) return 1; |
| 331 | |
| 332 | return sCollator.compare(lhs, rhs); |
Jeff Sharkey | aeb16e2 | 2013-08-27 18:26:48 -0700 | [diff] [blame] | 333 | } |
Jeff Sharkey | ef7184a | 2013-08-05 17:56:48 -0700 | [diff] [blame] | 334 | } |