1 /* 2 * Copyright (C) 2021 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 android.provider; 18 19 import static android.provider.CloudMediaProviderContract.EXTRA_ERROR_MESSAGE; 20 import static android.provider.CloudMediaProviderContract.EXTRA_FILE_DESCRIPTOR; 21 22 import android.annotation.NonNull; 23 import android.net.Uri; 24 import android.os.Bundle; 25 import android.os.ParcelFileDescriptor; 26 import android.os.RemoteCallback; 27 import android.os.RemoteException; 28 29 import java.io.FileNotFoundException; 30 import java.util.concurrent.CompletableFuture; 31 import java.util.concurrent.ExecutionException; 32 import java.util.concurrent.TimeUnit; 33 import java.util.concurrent.TimeoutException; 34 35 /** 36 * @hide 37 */ 38 public final class AsyncContentProvider { 39 40 private static final long TIMEOUT_IN_MINUTES = 3L; 41 42 private final IAsyncContentProvider mAsyncContentProvider; 43 AsyncContentProvider(@onNull IAsyncContentProvider asyncContentProvider)44 public AsyncContentProvider(@NonNull IAsyncContentProvider asyncContentProvider) { 45 this.mAsyncContentProvider = asyncContentProvider; 46 } 47 48 @NonNull openMedia(@onNull Uri uri, @NonNull String mode)49 public ParcelFileDescriptor openMedia(@NonNull Uri uri, @NonNull String mode) 50 throws FileNotFoundException, ExecutionException, InterruptedException, 51 TimeoutException, RemoteException { 52 String mediaId = uri.getLastPathSegment(); 53 CompletableFuture<ParcelFileDescriptor> future = new CompletableFuture<>(); 54 RemoteCallback callback = new RemoteCallback(result -> setResult(result, future)); 55 mAsyncContentProvider.openMedia(mediaId, callback); 56 return future.get(TIMEOUT_IN_MINUTES, TimeUnit.MINUTES); 57 } 58 setResult(Bundle result, CompletableFuture<ParcelFileDescriptor> future)59 private void setResult(Bundle result, CompletableFuture<ParcelFileDescriptor> future) { 60 if (result.containsKey(EXTRA_FILE_DESCRIPTOR)) { 61 ParcelFileDescriptor pfd = result.getParcelable(EXTRA_FILE_DESCRIPTOR); 62 future.complete(pfd); 63 } else if (result.containsKey(EXTRA_ERROR_MESSAGE)) { 64 future.completeExceptionally( 65 new RemoteException( 66 result.getString(EXTRA_ERROR_MESSAGE))); 67 } else { 68 future.completeExceptionally( 69 new RemoteException( 70 "File descriptor and error message missing in response from " 71 + "CloudMediaProvider")); 72 } 73 } 74 } 75