DirectoryLoader.java revision 954be0232655d316bc5decbbd35579af902c75c2
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
17package com.android.documentsui;
18
19import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
20import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
21import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
22
23import android.content.AsyncTaskLoader;
24import android.content.ContentProviderClient;
25import android.content.Context;
26import android.database.Cursor;
27import android.net.Uri;
28import android.os.CancellationSignal;
29import android.os.OperationCanceledException;
30import android.provider.DocumentsContract.Document;
31
32import libcore.io.IoUtils;
33
34class DirectoryResult implements AutoCloseable {
35    ContentProviderClient client;
36    Cursor cursor;
37    Exception exception;
38
39    @Override
40    public void close() {
41        IoUtils.closeQuietly(cursor);
42        ContentProviderClient.closeQuietly(client);
43        cursor = null;
44        client = null;
45    }
46}
47
48public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
49    private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
50
51    private final String mRootId;
52    private final Uri mUri;
53    private final int mSortOrder;
54
55    private CancellationSignal mSignal;
56    private DirectoryResult mResult;
57
58    public DirectoryLoader(Context context, String rootId, Uri uri, int sortOrder) {
59        super(context);
60        mRootId = rootId;
61        mUri = uri;
62        mSortOrder = sortOrder;
63    }
64
65    @Override
66    public final DirectoryResult loadInBackground() {
67        synchronized (this) {
68            if (isLoadInBackgroundCanceled()) {
69                throw new OperationCanceledException();
70            }
71            mSignal = new CancellationSignal();
72        }
73        final DirectoryResult result = new DirectoryResult();
74        final String authority = mUri.getAuthority();
75        try {
76            result.client = getContext()
77                    .getContentResolver().acquireUnstableContentProviderClient(authority);
78            final Cursor cursor = result.client.query(
79                    mUri, null, null, null, getQuerySortOrder(mSortOrder), mSignal);
80            cursor.registerContentObserver(mObserver);
81
82            final Cursor withRoot = new RootCursorWrapper(mUri.getAuthority(), mRootId, cursor, -1);
83            final Cursor sorted = new SortingCursorWrapper(withRoot, mSortOrder);
84
85            result.cursor = sorted;
86        } catch (Exception e) {
87            result.exception = e;
88            ContentProviderClient.closeQuietly(result.client);
89        } finally {
90            synchronized (this) {
91                mSignal = null;
92            }
93        }
94        return result;
95    }
96
97    @Override
98    public void cancelLoadInBackground() {
99        super.cancelLoadInBackground();
100
101        synchronized (this) {
102            if (mSignal != null) {
103                mSignal.cancel();
104            }
105        }
106    }
107
108    @Override
109    public void deliverResult(DirectoryResult result) {
110        if (isReset()) {
111            IoUtils.closeQuietly(result);
112            return;
113        }
114        DirectoryResult oldResult = mResult;
115        mResult = result;
116
117        if (isStarted()) {
118            super.deliverResult(result);
119        }
120
121        if (oldResult != null && oldResult != result) {
122            IoUtils.closeQuietly(oldResult);
123        }
124    }
125
126    @Override
127    protected void onStartLoading() {
128        if (mResult != null) {
129            deliverResult(mResult);
130        }
131        if (takeContentChanged() || mResult == null) {
132            forceLoad();
133        }
134    }
135
136    @Override
137    protected void onStopLoading() {
138        cancelLoad();
139    }
140
141    @Override
142    public void onCanceled(DirectoryResult result) {
143        IoUtils.closeQuietly(result);
144    }
145
146    @Override
147    protected void onReset() {
148        super.onReset();
149
150        // Ensure the loader is stopped
151        onStopLoading();
152
153        IoUtils.closeQuietly(mResult);
154        mResult = null;
155
156        getContext().getContentResolver().unregisterContentObserver(mObserver);
157    }
158
159    public static String getQuerySortOrder(int sortOrder) {
160        switch (sortOrder) {
161            case SORT_ORDER_DISPLAY_NAME:
162                return Document.COLUMN_DISPLAY_NAME + " ASC";
163            case SORT_ORDER_LAST_MODIFIED:
164                return Document.COLUMN_LAST_MODIFIED + " DESC";
165            case SORT_ORDER_SIZE:
166                return Document.COLUMN_SIZE + " DESC";
167            default:
168                return null;
169        }
170    }
171}
172