Home | History | Annotate | Download | only in documentsui
      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 
     17 package com.android.documentsui;
     18 
     19 import android.content.AsyncTaskLoader;
     20 import android.content.Context;
     21 import android.database.ContentObserver;
     22 import android.os.CancellationSignal;
     23 import android.os.OperationCanceledException;
     24 
     25 /**
     26  * Loader that derives its data from a Uri. Watches for {@link ContentObserver}
     27  * changes while started, manages {@link CancellationSignal}, and caches
     28  * returned results.
     29  */
     30 public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
     31     final ForceLoadContentObserver mObserver;
     32 
     33     private final P mParam;
     34 
     35     private R mResult;
     36     private CancellationSignal mCancellationSignal;
     37 
     38     @Override
     39     public final R loadInBackground() {
     40         synchronized (this) {
     41             if (isLoadInBackgroundCanceled()) {
     42                 throw new OperationCanceledException();
     43             }
     44             mCancellationSignal = new CancellationSignal();
     45         }
     46         try {
     47             return loadInBackground(mParam, mCancellationSignal);
     48         } finally {
     49             synchronized (this) {
     50                 mCancellationSignal = null;
     51             }
     52         }
     53     }
     54 
     55     public abstract R loadInBackground(P param, CancellationSignal signal);
     56 
     57     @Override
     58     public void cancelLoadInBackground() {
     59         super.cancelLoadInBackground();
     60 
     61         synchronized (this) {
     62             if (mCancellationSignal != null) {
     63                 mCancellationSignal.cancel();
     64             }
     65         }
     66     }
     67 
     68     @Override
     69     public void deliverResult(R result) {
     70         if (isReset()) {
     71             closeQuietly(result);
     72             return;
     73         }
     74         R oldResult = mResult;
     75         mResult = result;
     76 
     77         if (isStarted()) {
     78             super.deliverResult(result);
     79         }
     80 
     81         if (oldResult != null && oldResult != result) {
     82             closeQuietly(oldResult);
     83         }
     84     }
     85 
     86     public UriDerivativeLoader(Context context, P param) {
     87         super(context);
     88         mObserver = new ForceLoadContentObserver();
     89         mParam = param;
     90     }
     91 
     92     @Override
     93     protected void onStartLoading() {
     94         if (mResult != null) {
     95             deliverResult(mResult);
     96         }
     97         if (takeContentChanged() || mResult == null) {
     98             forceLoad();
     99         }
    100     }
    101 
    102     @Override
    103     protected void onStopLoading() {
    104         cancelLoad();
    105     }
    106 
    107     @Override
    108     public void onCanceled(R result) {
    109         closeQuietly(result);
    110     }
    111 
    112     @Override
    113     protected void onReset() {
    114         super.onReset();
    115 
    116         // Ensure the loader is stopped
    117         onStopLoading();
    118 
    119         closeQuietly(mResult);
    120         mResult = null;
    121 
    122         getContext().getContentResolver().unregisterContentObserver(mObserver);
    123     }
    124 
    125     private void closeQuietly(R result) {
    126         if (result instanceof AutoCloseable) {
    127             try {
    128                 ((AutoCloseable) result).close();
    129             } catch (RuntimeException rethrown) {
    130                 throw rethrown;
    131             } catch (Exception ignored) {
    132             }
    133         }
    134     }
    135 }
    136