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