blob: 13b7b14600eb842ca9e1b8910a141e98db024797 [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
Steve McKay7776aa52016-01-25 19:00:22 -080019import static com.android.documentsui.Shared.DEBUG;
Steve McKayfefcd702015-08-20 16:19:38 +000020import static com.android.documentsui.Shared.TAG;
Steve McKayf8a5e082015-09-23 17:21:40 -070021import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
22import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
23import static com.android.documentsui.State.SORT_ORDER_SIZE;
Jeff Sharkeyb3620442013-09-01 18:41:04 -070024
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070025import android.content.AsyncTaskLoader;
26import android.content.ContentProviderClient;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070027import android.content.ContentResolver;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070028import android.content.Context;
29import android.database.Cursor;
30import android.net.Uri;
31import android.os.CancellationSignal;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070032import android.os.OperationCanceledException;
Makoto Onuki77778752015-07-01 14:55:14 -070033import android.os.RemoteException;
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070034import android.provider.DocumentsContract;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070035import android.provider.DocumentsContract.Document;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070036import android.util.Log;
37
Steve McKayf68210e2015-11-03 15:23:16 -080038import com.android.documentsui.dirlist.DirectoryFragment;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070039import com.android.documentsui.model.DocumentInfo;
40import com.android.documentsui.model.RootInfo;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070041
Jeff Sharkeya5defe32013-08-05 17:56:48 -070042import libcore.io.IoUtils;
43
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070044import java.io.FileNotFoundException;
45
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070046public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
Jeff Sharkey9dd02622013-09-27 16:44:11 -070047
48 private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
49
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070050 private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
Jeff Sharkeya5defe32013-08-05 17:56:48 -070051
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070052 private final int mType;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070053 private final RootInfo mRoot;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070054 private final Uri mUri;
Jeff Sharkeyd10f0492013-09-09 17:35:46 -070055 private final int mUserSortOrder;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080056 private final boolean mSearchMode;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070057
Steve McKay7776aa52016-01-25 19:00:22 -080058 private DocumentInfo mDoc;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070059 private CancellationSignal mSignal;
60 private DirectoryResult mResult;
61
Aga Wronskaaf5ace52016-02-17 13:50:42 -080062
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070063 public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
Aga Wronskaaf5ace52016-02-17 13:50:42 -080064 int userSortOrder, boolean inSearchMode) {
Jeff Sharkeyf63b7772013-10-01 17:57:41 -070065 super(context, ProviderExecutor.forAuthority(root.authority));
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070066 mType = type;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070067 mRoot = root;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070068 mUri = uri;
Jeff Sharkeyd10f0492013-09-09 17:35:46 -070069 mUserSortOrder = userSortOrder;
Steve McKay7776aa52016-01-25 19:00:22 -080070 mDoc = doc;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080071 mSearchMode = inSearchMode;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070072 }
73
74 @Override
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070075 public final DirectoryResult loadInBackground() {
76 synchronized (this) {
77 if (isLoadInBackgroundCanceled()) {
78 throw new OperationCanceledException();
79 }
80 mSignal = new CancellationSignal();
81 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070082
83 final ContentResolver resolver = getContext().getContentResolver();
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -070084 final String authority = mUri.getAuthority();
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070085
86 final DirectoryResult result = new DirectoryResult();
87
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070088 // Use default document when searching
Aga Wronskaaf5ace52016-02-17 13:50:42 -080089 if (mSearchMode) {
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070090 final Uri docUri = DocumentsContract.buildDocumentUri(
91 mRoot.authority, mRoot.documentId);
92 try {
93 mDoc = DocumentInfo.fromUri(resolver, docUri);
94 } catch (FileNotFoundException e) {
95 Log.w(TAG, "Failed to query", e);
96 result.exception = e;
97 return result;
98 }
99 }
100
Jeff Sharkeyd10f0492013-09-09 17:35:46 -0700101 if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
102 result.sortOrder = mUserSortOrder;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700103 } else {
104 if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
105 result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
106 } else {
107 result.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
108 }
109 }
110
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700111 // Search always uses ranking from provider
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800112 if (mSearchMode) {
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700113 result.sortOrder = State.SORT_ORDER_UNKNOWN;
114 }
115
Steve McKay7776aa52016-01-25 19:00:22 -0800116 if (DEBUG)
117 Log.d(TAG, "userSortOrder=" + mUserSortOrder + ", sortOrder=" + result.sortOrder);
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700118
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700119 ContentProviderClient client = null;
Steve McKay7776aa52016-01-25 19:00:22 -0800120 Cursor cursor = null;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700121 try {
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700122 client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700123 cursor = client.query(
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700124 mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
Makoto Onuki77778752015-07-01 14:55:14 -0700125 if (cursor == null) {
126 throw new RemoteException("Provider returned null");
127 }
128
Jeff Sharkey20b32272013-09-03 15:25:52 -0700129 cursor.registerContentObserver(mObserver);
130
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700131 cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -0700132
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800133 if (mSearchMode) {
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700134 // Filter directories out of search results, for now
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700135 cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700136 }
137
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700138 result.client = client;
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700139 result.cursor = cursor;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700140 } catch (Exception e) {
Jeff Sharkey0e8c8712013-09-12 21:59:06 -0700141 Log.w(TAG, "Failed to query", e);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700142 result.exception = e;
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700143 ContentProviderClient.releaseQuietly(client);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700144 } finally {
145 synchronized (this) {
146 mSignal = null;
147 }
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700148 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700149
Jeff Sharkey46899c82013-08-18 22:26:48 -0700150 return result;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700151 }
152
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700153 @Override
154 public void cancelLoadInBackground() {
155 super.cancelLoadInBackground();
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700156
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700157 synchronized (this) {
158 if (mSignal != null) {
159 mSignal.cancel();
Jeff Sharkey46899c82013-08-18 22:26:48 -0700160 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700161 }
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700162 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700163
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700164 @Override
165 public void deliverResult(DirectoryResult result) {
166 if (isReset()) {
167 IoUtils.closeQuietly(result);
168 return;
169 }
170 DirectoryResult oldResult = mResult;
171 mResult = result;
172
173 if (isStarted()) {
174 super.deliverResult(result);
175 }
176
177 if (oldResult != null && oldResult != result) {
178 IoUtils.closeQuietly(oldResult);
179 }
180 }
181
182 @Override
183 protected void onStartLoading() {
184 if (mResult != null) {
185 deliverResult(mResult);
186 }
187 if (takeContentChanged() || mResult == null) {
188 forceLoad();
189 }
190 }
191
192 @Override
193 protected void onStopLoading() {
194 cancelLoad();
195 }
196
197 @Override
198 public void onCanceled(DirectoryResult result) {
199 IoUtils.closeQuietly(result);
200 }
201
202 @Override
203 protected void onReset() {
204 super.onReset();
205
206 // Ensure the loader is stopped
207 onStopLoading();
208
209 IoUtils.closeQuietly(mResult);
210 mResult = null;
211
212 getContext().getContentResolver().unregisterContentObserver(mObserver);
213 }
214
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -0700215 public static String getQuerySortOrder(int sortOrder) {
216 switch (sortOrder) {
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700217 case SORT_ORDER_DISPLAY_NAME:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700218 return Document.COLUMN_DISPLAY_NAME + " ASC";
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700219 case SORT_ORDER_LAST_MODIFIED:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700220 return Document.COLUMN_LAST_MODIFIED + " DESC";
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700221 case SORT_ORDER_SIZE:
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700222 return Document.COLUMN_SIZE + " DESC";
223 default:
224 return null;
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700225 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700226 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700227}