blob: 334e26285f6aef87f65251474f8c6ea76259f90e [file] [log] [blame]
Jeff Sharkeya5defe32013-08-05 17:56:48 -07001/*
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
17package com.android.documentsui;
18
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070019import static com.android.documentsui.DocumentsActivity.TAG;
20import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
Jeff Sharkeyb3620442013-09-01 18:41:04 -070021import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
22import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
23import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070024import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
25import static com.android.documentsui.model.DocumentInfo.getCursorInt;
Jeff Sharkeyb3620442013-09-01 18:41:04 -070026
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070027import android.content.AsyncTaskLoader;
28import android.content.ContentProviderClient;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070029import android.content.ContentResolver;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070030import android.content.Context;
31import android.database.Cursor;
32import android.net.Uri;
33import android.os.CancellationSignal;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070034import android.os.OperationCanceledException;
35import android.provider.DocumentsContract.Document;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070036import android.util.Log;
37
38import com.android.documentsui.DocumentsActivity.State;
39import com.android.documentsui.RecentsProvider.StateColumns;
40import com.android.documentsui.model.DocumentInfo;
41import com.android.documentsui.model.RootInfo;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070042
Jeff Sharkeya5defe32013-08-05 17:56:48 -070043import libcore.io.IoUtils;
44
Jeff Sharkey46899c82013-08-18 22:26:48 -070045class DirectoryResult implements AutoCloseable {
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070046 ContentProviderClient client;
Jeff Sharkey46899c82013-08-18 22:26:48 -070047 Cursor cursor;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070048 Exception exception;
Jeff Sharkey46899c82013-08-18 22:26:48 -070049
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070050 int mode = MODE_UNKNOWN;
51 int sortOrder = SORT_ORDER_UNKNOWN;
52
Jeff Sharkey46899c82013-08-18 22:26:48 -070053 @Override
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070054 public void close() {
Jeff Sharkey46899c82013-08-18 22:26:48 -070055 IoUtils.closeQuietly(cursor);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070056 ContentProviderClient.closeQuietly(client);
57 cursor = null;
58 client = null;
Jeff Sharkey46899c82013-08-18 22:26:48 -070059 }
60}
61
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070062public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
63 private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
Jeff Sharkeya5defe32013-08-05 17:56:48 -070064
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070065 private final int mType;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070066 private final RootInfo mRoot;
67 private final DocumentInfo mDoc;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070068 private final Uri mUri;
Jeff Sharkeyd10f0492013-09-09 17:35:46 -070069 private final int mUserSortOrder;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070070
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070071 private CancellationSignal mSignal;
72 private DirectoryResult mResult;
73
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070074 public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
75 int userSortOrder) {
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070076 super(context);
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070077 mType = type;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070078 mRoot = root;
79 mDoc = doc;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070080 mUri = uri;
Jeff Sharkeyd10f0492013-09-09 17:35:46 -070081 mUserSortOrder = userSortOrder;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070082 }
83
84 @Override
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070085 public final DirectoryResult loadInBackground() {
86 synchronized (this) {
87 if (isLoadInBackgroundCanceled()) {
88 throw new OperationCanceledException();
89 }
90 mSignal = new CancellationSignal();
91 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070092
93 final ContentResolver resolver = getContext().getContentResolver();
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -070094 final String authority = mUri.getAuthority();
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070095
96 final DirectoryResult result = new DirectoryResult();
97
98 int userMode = State.MODE_UNKNOWN;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070099
100 // Pick up any custom modes requested by user
101 Cursor cursor = null;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700102 try {
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700103 final Uri stateUri = RecentsProvider.buildState(
104 mRoot.authority, mRoot.rootId, mDoc.documentId);
105 cursor = resolver.query(stateUri, null, null, null, null);
106 if (cursor.moveToFirst()) {
107 userMode = getCursorInt(cursor, StateColumns.MODE);
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700108 }
109 } finally {
110 IoUtils.closeQuietly(cursor);
111 }
112
113 if (userMode != State.MODE_UNKNOWN) {
114 result.mode = userMode;
115 } else {
116 if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
117 result.mode = State.MODE_GRID;
118 } else {
119 result.mode = State.MODE_LIST;
120 }
121 }
122
Jeff Sharkeyd10f0492013-09-09 17:35:46 -0700123 if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
124 result.sortOrder = mUserSortOrder;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700125 } else {
126 if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
127 result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
128 } else {
129 result.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
130 }
131 }
132
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700133 // Search always uses ranking from provider
134 if (mType == DirectoryFragment.TYPE_SEARCH) {
135 result.sortOrder = State.SORT_ORDER_UNKNOWN;
136 }
137
Jeff Sharkeyd10f0492013-09-09 17:35:46 -0700138 Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + mUserSortOrder + " --> mode="
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700139 + result.mode + ", sortOrder=" + result.sortOrder);
140
141 try {
142 result.client = resolver.acquireUnstableContentProviderClient(authority);
143 cursor = result.client.query(
144 mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
Jeff Sharkey20b32272013-09-03 15:25:52 -0700145 cursor.registerContentObserver(mObserver);
146
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700147 cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -0700148
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700149 if (mType == DirectoryFragment.TYPE_SEARCH) {
150 // Filter directories out of search results, for now
151 cursor = new FilteringCursorWrapper(cursor, null, new String[] {
152 Document.MIME_TYPE_DIR });
153 } else {
154 // Normal directories should have sorting applied
155 cursor = new SortingCursorWrapper(cursor, result.sortOrder);
156 }
157
158 result.cursor = cursor;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700159 } catch (Exception e) {
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700160 Log.d(TAG, "Failed to query", e);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700161 result.exception = e;
162 ContentProviderClient.closeQuietly(result.client);
163 } finally {
164 synchronized (this) {
165 mSignal = null;
166 }
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700167 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700168
Jeff Sharkey46899c82013-08-18 22:26:48 -0700169 return result;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700170 }
171
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700172 @Override
173 public void cancelLoadInBackground() {
174 super.cancelLoadInBackground();
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700175
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700176 synchronized (this) {
177 if (mSignal != null) {
178 mSignal.cancel();
Jeff Sharkey46899c82013-08-18 22:26:48 -0700179 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700180 }
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700181 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700182
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700183 @Override
184 public void deliverResult(DirectoryResult result) {
185 if (isReset()) {
186 IoUtils.closeQuietly(result);
187 return;
188 }
189 DirectoryResult oldResult = mResult;
190 mResult = result;
191
192 if (isStarted()) {
193 super.deliverResult(result);
194 }
195
196 if (oldResult != null && oldResult != result) {
197 IoUtils.closeQuietly(oldResult);
198 }
199 }
200
201 @Override
202 protected void onStartLoading() {
203 if (mResult != null) {
204 deliverResult(mResult);
205 }
206 if (takeContentChanged() || mResult == null) {
207 forceLoad();
208 }
209 }
210
211 @Override
212 protected void onStopLoading() {
213 cancelLoad();
214 }
215
216 @Override
217 public void onCanceled(DirectoryResult result) {
218 IoUtils.closeQuietly(result);
219 }
220
221 @Override
222 protected void onReset() {
223 super.onReset();
224
225 // Ensure the loader is stopped
226 onStopLoading();
227
228 IoUtils.closeQuietly(mResult);
229 mResult = null;
230
231 getContext().getContentResolver().unregisterContentObserver(mObserver);
232 }
233
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -0700234 public static String getQuerySortOrder(int sortOrder) {
235 switch (sortOrder) {
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700236 case SORT_ORDER_DISPLAY_NAME:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700237 return Document.COLUMN_DISPLAY_NAME + " ASC";
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700238 case SORT_ORDER_LAST_MODIFIED:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700239 return Document.COLUMN_LAST_MODIFIED + " DESC";
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700240 case SORT_ORDER_SIZE:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700241 return Document.COLUMN_SIZE + " DESC";
242 default:
243 return null;
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700244 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700245 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700246}