DirectoryLoader.java revision 251097b3789632000ccdaf7fb7d66a82ff37d882
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            final Cursor withRoot = new RootCursorWrapper(mUri.getAuthority(), mRootId, cursor, -1);
81            final Cursor sorted = new SortingCursorWrapper(withRoot, mSortOrder);
82
83            result.cursor = sorted;
84            result.cursor.registerContentObserver(mObserver);
85        } catch (Exception e) {
86            result.exception = e;
87            ContentProviderClient.closeQuietly(result.client);
88        } finally {
89            synchronized (this) {
90                mSignal = null;
91            }
92        }
93        return result;
94    }
95
96    @Override
97    public void cancelLoadInBackground() {
98        super.cancelLoadInBackground();
99
100        synchronized (this) {
101            if (mSignal != null) {
102                mSignal.cancel();
103            }
104        }
105    }
106
107    @Override
108    public void deliverResult(DirectoryResult result) {
109        if (isReset()) {
110            IoUtils.closeQuietly(result);
111            return;
112        }
113        DirectoryResult oldResult = mResult;
114        mResult = result;
115
116        if (isStarted()) {
117            super.deliverResult(result);
118        }
119
120        if (oldResult != null && oldResult != result) {
121            IoUtils.closeQuietly(oldResult);
122        }
123    }
124
125    @Override
126    protected void onStartLoading() {
127        if (mResult != null) {
128            deliverResult(mResult);
129        }
130        if (takeContentChanged() || mResult == null) {
131            forceLoad();
132        }
133    }
134
135    @Override
136    protected void onStopLoading() {
137        cancelLoad();
138    }
139
140    @Override
141    public void onCanceled(DirectoryResult result) {
142        IoUtils.closeQuietly(result);
143    }
144
145    @Override
146    protected void onReset() {
147        super.onReset();
148
149        // Ensure the loader is stopped
150        onStopLoading();
151
152        IoUtils.closeQuietly(mResult);
153        mResult = null;
154
155        getContext().getContentResolver().unregisterContentObserver(mObserver);
156    }
157
158    public static String getQuerySortOrder(int sortOrder) {
159        switch (sortOrder) {
160            case SORT_ORDER_DISPLAY_NAME:
161                return Document.COLUMN_DISPLAY_NAME + " ASC";
162            case SORT_ORDER_LAST_MODIFIED:
163                return Document.COLUMN_LAST_MODIFIED + " DESC";
164            case SORT_ORDER_SIZE:
165                return Document.COLUMN_SIZE + " DESC";
166            default:
167                return null;
168        }
169    }
170}
171