DirectoryLoader.java revision 954be0232655d316bc5decbbd35579af902c75c2
1ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey/*
2ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
4ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * you may not use this file except in compliance with the License.
6ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * You may obtain a copy of the License at
7ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
8ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey *
10ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
11ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * See the License for the specific language governing permissions and
14ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey * limitations under the License.
15ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey */
16ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
17ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeypackage com.android.documentsui;
18ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
19b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
20b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
21b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkeyimport static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
22b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey
235dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkeyimport android.content.AsyncTaskLoader;
245dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkeyimport android.content.ContentProviderClient;
25ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.content.Context;
26ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.database.Cursor;
27ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.net.Uri;
28ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.os.CancellationSignal;
295dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkeyimport android.os.OperationCanceledException;
305dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkeyimport android.provider.DocumentsContract.Document;
31ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
32ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport libcore.io.IoUtils;
33ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
34b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkeyclass DirectoryResult implements AutoCloseable {
355dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    ContentProviderClient client;
36b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey    Cursor cursor;
375dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    Exception exception;
38b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey
39b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey    @Override
405dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public void close() {
41b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey        IoUtils.closeQuietly(cursor);
425dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        ContentProviderClient.closeQuietly(client);
435dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        cursor = null;
445dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        client = null;
45b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey    }
46b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey}
47b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey
485dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkeypublic class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
495dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
505dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
51251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey    private final String mRootId;
525dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    private final Uri mUri;
535dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    private final int mSortOrder;
54ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
555dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    private CancellationSignal mSignal;
565dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    private DirectoryResult mResult;
57ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
58251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey    public DirectoryLoader(Context context, String rootId, Uri uri, int sortOrder) {
595dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        super(context);
60251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey        mRootId = rootId;
615dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        mUri = uri;
62ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        mSortOrder = sortOrder;
63ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
64ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
65ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    @Override
665dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public final DirectoryResult loadInBackground() {
675dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        synchronized (this) {
685dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            if (isLoadInBackgroundCanceled()) {
695dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                throw new OperationCanceledException();
705dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            }
715dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            mSignal = new CancellationSignal();
725dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
73b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey        final DirectoryResult result = new DirectoryResult();
74251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey        final String authority = mUri.getAuthority();
7554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        try {
765dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            result.client = getContext()
77251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey                    .getContentResolver().acquireUnstableContentProviderClient(authority);
785dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            final Cursor cursor = result.client.query(
79251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey                    mUri, null, null, null, getQuerySortOrder(mSortOrder), mSignal);
80954be0232655d316bc5decbbd35579af902c75c2Jeff Sharkey            cursor.registerContentObserver(mObserver);
81954be0232655d316bc5decbbd35579af902c75c2Jeff Sharkey
82251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey            final Cursor withRoot = new RootCursorWrapper(mUri.getAuthority(), mRootId, cursor, -1);
83251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey            final Cursor sorted = new SortingCursorWrapper(withRoot, mSortOrder);
84251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey
85251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey            result.cursor = sorted;
8654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        } catch (Exception e) {
875dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            result.exception = e;
885dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            ContentProviderClient.closeQuietly(result.client);
895dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        } finally {
905dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            synchronized (this) {
915dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                mSignal = null;
925dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            }
9354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        }
94b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey        return result;
9554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey    }
9654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
975dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
985dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public void cancelLoadInBackground() {
995dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        super.cancelLoadInBackground();
100b448660a227f93d7bd5c5d019a21745e67c2f54dJeff Sharkey
1015dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        synchronized (this) {
1025dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            if (mSignal != null) {
1035dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                mSignal.cancel();
104ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            }
105ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
1065dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
1075dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1085dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
1095dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public void deliverResult(DirectoryResult result) {
1105dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        if (isReset()) {
1115dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            IoUtils.closeQuietly(result);
1125dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            return;
1135dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
1145dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        DirectoryResult oldResult = mResult;
1155dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        mResult = result;
1165dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1175dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        if (isStarted()) {
1185dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            super.deliverResult(result);
1195dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
1205dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1215dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        if (oldResult != null && oldResult != result) {
1225dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            IoUtils.closeQuietly(oldResult);
1235dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
1245dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
1255dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1265dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
1275dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    protected void onStartLoading() {
1285dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        if (mResult != null) {
1295dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            deliverResult(mResult);
1305dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
1315dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        if (takeContentChanged() || mResult == null) {
1325dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            forceLoad();
1335dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        }
1345dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
1355dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1365dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
1375dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    protected void onStopLoading() {
1385dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        cancelLoad();
1395dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
1405dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1415dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
1425dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    public void onCanceled(DirectoryResult result) {
1435dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        IoUtils.closeQuietly(result);
1445dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
1455dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1465dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    @Override
1475dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    protected void onReset() {
1485dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        super.onReset();
1495dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1505dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        // Ensure the loader is stopped
1515dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        onStopLoading();
1525dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1535dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        IoUtils.closeQuietly(mResult);
1545dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        mResult = null;
1555dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey
1565dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey        getContext().getContentResolver().unregisterContentObserver(mObserver);
1575dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey    }
158ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
159251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey    public static String getQuerySortOrder(int sortOrder) {
160251097b3789632000ccdaf7fb7d66a82ff37d882Jeff Sharkey        switch (sortOrder) {
161b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case SORT_ORDER_DISPLAY_NAME:
1625dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                return Document.COLUMN_DISPLAY_NAME + " ASC";
163b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case SORT_ORDER_LAST_MODIFIED:
1645dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                return Document.COLUMN_LAST_MODIFIED + " DESC";
165b51331116eb2ebbc41aaf69142916f9af6dffdd5Jeff Sharkey            case SORT_ORDER_SIZE:
1665dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                return Document.COLUMN_SIZE + " DESC";
1675dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey            default:
1685dfb345df7cb17b3a7e534a80a270b4afe7934daJeff Sharkey                return null;
169ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
170ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
171ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey}
172