1 /* 2 * Copyright (C) 2016 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 static com.android.documentsui.base.Shared.DEBUG; 20 21 import android.annotation.Nullable; 22 import android.content.ContentProviderClient; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.net.Uri; 26 import android.os.CancellationSignal; 27 import android.util.Log; 28 29 import com.android.documentsui.base.ApplicationScope; 30 import com.android.documentsui.base.BooleanConsumer; 31 import com.android.documentsui.base.CheckedTask; 32 import com.android.documentsui.base.DocumentInfo; 33 import com.android.documentsui.base.Features; 34 import com.android.documentsui.base.State; 35 36 /** 37 * A {@link CheckedTask} that calls 38 * {@link ContentResolver#refresh(Uri, android.os.Bundle, android.os.CancellationSignal)} on the 39 * current directory, and then calls the supplied callback with the refresh return value. 40 */ 41 public class RefreshTask extends TimeoutTask<Void, Boolean> { 42 43 private final static String TAG = "RefreshTask"; 44 45 private final @ApplicationScope Context mContext; 46 private final Features mFeatures; 47 private final State mState; 48 private final DocumentInfo mDoc; 49 private final BooleanConsumer mCallback; 50 private final CancellationSignal mSignal; 51 52 RefreshTask(Features features, State state, DocumentInfo doc, long timeout, @ApplicationScope Context context, Check check, BooleanConsumer callback)53 public RefreshTask(Features features, State state, DocumentInfo doc, long timeout, 54 @ApplicationScope Context context, Check check, BooleanConsumer callback) { 55 super(check, timeout); 56 mFeatures = features; 57 mState = state; 58 mDoc = doc; 59 mContext = context; 60 mCallback = callback; 61 mSignal = new CancellationSignal(); 62 } 63 64 @Override run(Void... params)65 public @Nullable Boolean run(Void... params) { 66 if (mDoc == null) { 67 Log.w(TAG, "Ignoring attempt to refresh due to null DocumentInfo."); 68 return false; 69 } 70 71 if (mState.stack.isEmpty()) { 72 Log.w(TAG, "Ignoring attempt to refresh due to empty stack."); 73 return false; 74 } 75 76 if (!mDoc.derivedUri.equals(mState.stack.peek().derivedUri)) { 77 Log.w(TAG, "Ignoring attempt to refresh on a non-top-level uri."); 78 return false; 79 } 80 81 // API O introduces ContentResolver#refresh, and if available and the ContentProvider 82 // supports it, the ContentProvider will automatically send a content updated notification 83 // and we will update accordingly. Else, we just tell the callback that Refresh is not 84 // supported. 85 if (!mFeatures.isContentRefreshEnabled()) { 86 Log.w(TAG, "Ignoring attempt to call Refresh on an older Android platform."); 87 return false; 88 } 89 90 final ContentResolver resolver = mContext.getContentResolver(); 91 final String authority = mDoc.authority; 92 boolean refreshSupported = false; 93 ContentProviderClient client = null; 94 try { 95 client = DocumentsApplication.acquireUnstableProviderOrThrow(resolver, authority); 96 refreshSupported = client.refresh(mDoc.derivedUri, null, mSignal); 97 } catch (Exception e) { 98 Log.w(TAG, "Failed to refresh", e); 99 } finally { 100 ContentProviderClient.releaseQuietly(client); 101 } 102 return refreshSupported; 103 } 104 105 @Override onTimeout()106 protected void onTimeout() { 107 mSignal.cancel(); 108 Log.w(TAG, "Provider taking too long to respond. Cancelling."); 109 } 110 111 @Override finish(Boolean refreshSupported)112 public void finish(Boolean refreshSupported) { 113 if (DEBUG) { 114 // In case of timeout, refreshSupported is null. 115 if (Boolean.TRUE.equals(refreshSupported)) { 116 Log.v(TAG, "Provider supports refresh and has refreshed"); 117 } else { 118 Log.v(TAG, "Provider does not support refresh and did not refresh"); 119 } 120 } 121 mCallback.accept(refreshSupported != null ? refreshSupported : Boolean.FALSE); 122 } 123 } 124