blob: 995c050290666a16432d4d164e0a73844fd61c8b [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 Sharkeyac9e6272013-08-31 21:27:44 -070019import android.content.AsyncTaskLoader;
20import android.content.ContentProviderClient;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070021import android.content.ContentResolver;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070022import android.content.Context;
23import android.database.Cursor;
24import android.net.Uri;
25import android.os.CancellationSignal;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070026import android.os.OperationCanceledException;
Makoto Onuki77778752015-07-01 14:55:14 -070027import android.os.RemoteException;
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070028import android.provider.DocumentsContract;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070029import android.provider.DocumentsContract.Document;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070030import android.util.Log;
31
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070032import com.android.documentsui.model.DocumentInfo;
33import com.android.documentsui.model.RootInfo;
Garfield, Tan11d23482016-08-05 09:33:29 -070034import com.android.documentsui.sorting.SortModel;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070035
Jeff Sharkeya5defe32013-08-05 17:56:48 -070036import libcore.io.IoUtils;
37
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070038import java.io.FileNotFoundException;
39
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070040public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
Jeff Sharkey9dd02622013-09-27 16:44:11 -070041
Garfield, Tan11d23482016-08-05 09:33:29 -070042 private static final String TAG = "DirectoryLoader";
43
Jeff Sharkey9dd02622013-09-27 16:44:11 -070044 private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR };
45
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070046 private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
Jeff Sharkeya5defe32013-08-05 17:56:48 -070047
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070048 private final int mType;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070049 private final RootInfo mRoot;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070050 private final Uri mUri;
Garfield, Tan11d23482016-08-05 09:33:29 -070051 private final SortModel mModel;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080052 private final boolean mSearchMode;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070053
Steve McKay7776aa52016-01-25 19:00:22 -080054 private DocumentInfo mDoc;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070055 private CancellationSignal mSignal;
56 private DirectoryResult mResult;
57
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070058 public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
Garfield, Tan11d23482016-08-05 09:33:29 -070059 SortModel model, boolean inSearchMode) {
Jeff Sharkeyf63b7772013-10-01 17:57:41 -070060 super(context, ProviderExecutor.forAuthority(root.authority));
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -070061 mType = type;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070062 mRoot = root;
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070063 mUri = uri;
Garfield, Tan11d23482016-08-05 09:33:29 -070064 mModel = model;
Steve McKay7776aa52016-01-25 19:00:22 -080065 mDoc = doc;
Aga Wronskaaf5ace52016-02-17 13:50:42 -080066 mSearchMode = inSearchMode;
Jeff Sharkeya5defe32013-08-05 17:56:48 -070067 }
68
69 @Override
Jeff Sharkeyac9e6272013-08-31 21:27:44 -070070 public final DirectoryResult loadInBackground() {
71 synchronized (this) {
72 if (isLoadInBackgroundCanceled()) {
73 throw new OperationCanceledException();
74 }
75 mSignal = new CancellationSignal();
76 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070077
78 final ContentResolver resolver = getContext().getContentResolver();
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -070079 final String authority = mUri.getAuthority();
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070080
81 final DirectoryResult result = new DirectoryResult();
Tomasz Mikolajewskie29e3412016-02-24 12:53:44 +090082 result.doc = mDoc;
Garfield, Tan11d23482016-08-05 09:33:29 -070083 result.sortModel = mModel;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070084
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070085 // Use default document when searching
Aga Wronskaaf5ace52016-02-17 13:50:42 -080086 if (mSearchMode) {
Jeff Sharkey0e8c8712013-09-12 21:59:06 -070087 final Uri docUri = DocumentsContract.buildDocumentUri(
88 mRoot.authority, mRoot.documentId);
89 try {
90 mDoc = DocumentInfo.fromUri(resolver, docUri);
91 } catch (FileNotFoundException e) {
92 Log.w(TAG, "Failed to query", e);
93 result.exception = e;
94 return result;
95 }
96 }
97
Jeff Sharkeyf63b7772013-10-01 17:57:41 -070098 ContentProviderClient client = null;
Garfield, Tan11d23482016-08-05 09:33:29 -070099 Cursor cursor;
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700100 try {
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700101 client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority);
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700102 cursor = client.query(
Garfield, Tan11d23482016-08-05 09:33:29 -0700103 mUri, null, null, null, mModel.getDocumentSortQuery(), mSignal);
Makoto Onuki77778752015-07-01 14:55:14 -0700104 if (cursor == null) {
105 throw new RemoteException("Provider returned null");
106 }
107
Jeff Sharkey20b32272013-09-03 15:25:52 -0700108 cursor.registerContentObserver(mObserver);
109
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700110 cursor = new RootCursorWrapper(mUri.getAuthority(), mRoot.rootId, cursor, -1);
Jeff Sharkeyd82b26b2013-09-02 15:07:28 -0700111
Aga Wronskaaf5ace52016-02-17 13:50:42 -0800112 if (mSearchMode) {
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700113 // Filter directories out of search results, for now
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700114 cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700115 }
116
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700117 result.client = client;
Jeff Sharkeya35ac2d2013-09-10 12:04:26 -0700118 result.cursor = cursor;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700119 } catch (Exception e) {
Jeff Sharkey0e8c8712013-09-12 21:59:06 -0700120 Log.w(TAG, "Failed to query", e);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700121 result.exception = e;
Jeff Sharkeyf63b7772013-10-01 17:57:41 -0700122 ContentProviderClient.releaseQuietly(client);
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700123 } finally {
124 synchronized (this) {
125 mSignal = null;
126 }
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700127 }
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700128
Jeff Sharkey46899c82013-08-18 22:26:48 -0700129 return result;
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700130 }
131
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700132 @Override
133 public void cancelLoadInBackground() {
134 super.cancelLoadInBackground();
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700135
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700136 synchronized (this) {
137 if (mSignal != null) {
138 mSignal.cancel();
Jeff Sharkey46899c82013-08-18 22:26:48 -0700139 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700140 }
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700141 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700142
Jeff Sharkeyac9e6272013-08-31 21:27:44 -0700143 @Override
144 public void deliverResult(DirectoryResult result) {
145 if (isReset()) {
146 IoUtils.closeQuietly(result);
147 return;
148 }
149 DirectoryResult oldResult = mResult;
150 mResult = result;
151
152 if (isStarted()) {
153 super.deliverResult(result);
154 }
155
156 if (oldResult != null && oldResult != result) {
157 IoUtils.closeQuietly(oldResult);
158 }
159 }
160
161 @Override
162 protected void onStartLoading() {
163 if (mResult != null) {
164 deliverResult(mResult);
165 }
166 if (takeContentChanged() || mResult == null) {
167 forceLoad();
168 }
169 }
170
171 @Override
172 protected void onStopLoading() {
173 cancelLoad();
174 }
175
176 @Override
177 public void onCanceled(DirectoryResult result) {
178 IoUtils.closeQuietly(result);
179 }
180
181 @Override
182 protected void onReset() {
183 super.onReset();
184
185 // Ensure the loader is stopped
186 onStopLoading();
187
188 IoUtils.closeQuietly(mResult);
189 mResult = null;
190
191 getContext().getContentResolver().unregisterContentObserver(mObserver);
192 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700193}