FileDocCategorySizeDatePackage
RecentLoader.javaAPI DocAndroid 5.1 API10256Thu Mar 12 22:22:40 GMT 2015com.android.documentsui

RecentLoader

public class RecentLoader extends android.content.AsyncTaskLoader

Fields Summary
private static final boolean
LOGD
private static final int
MAX_OUTSTANDING_RECENTS
private static final int
MAX_OUTSTANDING_RECENTS_SVELTE
private static final int
MAX_FIRST_PASS_WAIT_MILLIS
Time to wait for first pass to complete before returning partial results.
private static final int
MAX_DOCS_FROM_ROOT
Maximum documents from a single root.
private static final long
REJECT_OLDER_THAN
Ignore documents older than this age.
private static final String[]
RECENT_REJECT_MIMES
MIME types that should always be excluded from recents.
private final Semaphore
mQueryPermits
private final RootsCache
mRoots
private final com.android.documentsui.DocumentsActivity.State
mState
private final HashMap
mTasks
private final int
mSortOrder
private CountDownLatch
mFirstPassLatch
private volatile boolean
mFirstPassDone
private DirectoryResult
mResult
Constructors Summary
public RecentLoader(android.content.Context context, RootsCache roots, com.android.documentsui.DocumentsActivity.State state)

        super(context);
        mRoots = roots;
        mState = state;

        // Keep clients around on high-RAM devices, since we'd be spinning them
        // up moments later to fetch thumbnails anyway.
        final ActivityManager am = (ActivityManager) getContext().getSystemService(
                Context.ACTIVITY_SERVICE);
        mQueryPermits = new Semaphore(
                am.isLowRamDevice() ? MAX_OUTSTANDING_RECENTS_SVELTE : MAX_OUTSTANDING_RECENTS);
    
Methods Summary
public voidcancelLoadInBackground()

        super.cancelLoadInBackground();
    
public voiddeliverResult(DirectoryResult result)

        if (isReset()) {
            IoUtils.closeQuietly(result);
            return;
        }
        DirectoryResult oldResult = mResult;
        mResult = result;

        if (isStarted()) {
            super.deliverResult(result);
        }

        if (oldResult != null && oldResult != result) {
            IoUtils.closeQuietly(oldResult);
        }
    
public DirectoryResultloadInBackground()

        if (mFirstPassLatch == null) {
            // First time through we kick off all the recent tasks, and wait
            // around to see if everyone finishes quickly.

            final Collection<RootInfo> roots = mRoots.getMatchingRootsBlocking(mState);
            for (RootInfo root : roots) {
                if ((root.flags & Root.FLAG_SUPPORTS_RECENTS) != 0) {
                    final RecentTask task = new RecentTask(root.authority, root.rootId);
                    mTasks.put(root, task);
                }
            }

            mFirstPassLatch = new CountDownLatch(mTasks.size());
            for (RecentTask task : mTasks.values()) {
                ProviderExecutor.forAuthority(task.authority).execute(task);
            }

            try {
                mFirstPassLatch.await(MAX_FIRST_PASS_WAIT_MILLIS, TimeUnit.MILLISECONDS);
                mFirstPassDone = true;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        final long rejectBefore = System.currentTimeMillis() - REJECT_OLDER_THAN;

        // Collect all finished tasks
        boolean allDone = true;
        List<Cursor> cursors = Lists.newArrayList();
        for (RecentTask task : mTasks.values()) {
            if (task.isDone()) {
                try {
                    final Cursor cursor = task.get();
                    if (cursor == null) continue;

                    final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
                            cursor, mState.acceptMimes, RECENT_REJECT_MIMES, rejectBefore) {
                        @Override
                        public void close() {
                            // Ignored, since we manage cursor lifecycle internally
                        }
                    };
                    cursors.add(filtered);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } catch (ExecutionException e) {
                    // We already logged on other side
                }
            } else {
                allDone = false;
            }
        }

        if (LOGD) {
            Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done");
        }

        final DirectoryResult result = new DirectoryResult();
        result.sortOrder = SORT_ORDER_LAST_MODIFIED;

        // Hint to UI if we're still loading
        final Bundle extras = new Bundle();
        if (!allDone) {
            extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
        }

        final Cursor merged;
        if (cursors.size() > 0) {
            merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
        } else {
            // Return something when nobody is ready
            merged = new MatrixCursor(new String[0]);
        }

        final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder) {
            @Override
            public Bundle getExtras() {
                return extras;
            }
        };

        result.cursor = sorted;

        return result;
    
public voidonCanceled(DirectoryResult result)

        IoUtils.closeQuietly(result);
    
protected voidonReset()

        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();

        for (RecentTask task : mTasks.values()) {
            IoUtils.closeQuietly(task);
        }

        IoUtils.closeQuietly(mResult);
        mResult = null;
    
protected voidonStartLoading()

        if (mResult != null) {
            deliverResult(mResult);
        }
        if (takeContentChanged() || mResult == null) {
            forceLoad();
        }
    
protected voidonStopLoading()

        cancelLoad();