1 /* 2 * Copyright (C) 2024 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.OemMetadataService.EXTRA_OEM_DATA_KEYS; 20 import static android.provider.OemMetadataService.EXTRA_OEM_DATA_VALUES; 21 import static android.provider.OemMetadataService.EXTRA_OEM_SUPPORTED_MIME_TYPES; 22 23 import android.annotation.FlaggedApi; 24 import android.annotation.NonNull; 25 import android.os.Bundle; 26 import android.os.ParcelFileDescriptor; 27 import android.os.RemoteCallback; 28 import android.util.Log; 29 30 import com.android.providers.media.flags.Flags; 31 32 import java.util.ArrayList; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.Set; 38 import java.util.concurrent.CompletableFuture; 39 import java.util.concurrent.ExecutionException; 40 import java.util.concurrent.ExecutorService; 41 import java.util.concurrent.Executors; 42 import java.util.concurrent.TimeUnit; 43 import java.util.concurrent.TimeoutException; 44 45 /** 46 * Wrapper defined to handle async calls to OemMetadataService. 47 * @hide 48 */ 49 public final class OemMetadataServiceWrapper { 50 51 private static final String TAG = "OemMetadataServiceWrapper"; 52 53 private static final long DEFAULT_TIMEOUT_IN_SECONDS = 1L; 54 55 private final IOemMetadataService mOemMetadataService; 56 57 private final ExecutorService mExecutorService; 58 59 private final long mServiceTimeoutInSeconds; 60 OemMetadataServiceWrapper(@onNull IOemMetadataService oemMetadataService)61 public OemMetadataServiceWrapper(@NonNull IOemMetadataService oemMetadataService) { 62 this(oemMetadataService, DEFAULT_TIMEOUT_IN_SECONDS); 63 } 64 OemMetadataServiceWrapper(@onNull IOemMetadataService oemMetadataService, long serviceTimeoutInSeconds)65 public OemMetadataServiceWrapper(@NonNull IOemMetadataService oemMetadataService, 66 long serviceTimeoutInSeconds) { 67 Objects.requireNonNull(oemMetadataService); 68 69 this.mOemMetadataService = oemMetadataService; 70 this.mServiceTimeoutInSeconds = serviceTimeoutInSeconds; 71 mExecutorService = Executors.newFixedThreadPool(3); 72 } 73 74 /** 75 * Gets supported mimetype from OemMetadataService within certain timeout. 76 */ getSupportedMimeTypes()77 public Set<String> getSupportedMimeTypes() 78 throws ExecutionException, InterruptedException, TimeoutException { 79 if (!Flags.enableOemMetadata()) { 80 return new HashSet<>(); 81 } 82 83 return mExecutorService.submit(() -> { 84 CompletableFuture<Set<String>> future = new CompletableFuture<>(); 85 RemoteCallback callback = new RemoteCallback( 86 result -> setResultForGetSupportedMimeTypes(result, future)); 87 mOemMetadataService.getSupportedMimeTypes(callback); 88 return future.get(); 89 }).get(mServiceTimeoutInSeconds, TimeUnit.SECONDS); 90 } 91 92 /** 93 * Gets OEM custom data from OemMetadataService within certain timeout. 94 */ getOemCustomData(ParcelFileDescriptor pfd)95 public Map<String, String> getOemCustomData(ParcelFileDescriptor pfd) 96 throws ExecutionException, InterruptedException, TimeoutException { 97 if (!Flags.enableOemMetadata()) { 98 return new HashMap<>(); 99 } 100 101 return mExecutorService.submit(() -> { 102 CompletableFuture<Map<String, String>> future = new CompletableFuture<>(); 103 RemoteCallback callback = new RemoteCallback( 104 result -> setResultForGetOemCustomData(result, future)); 105 mOemMetadataService.getOemCustomData(pfd, callback); 106 return future.get(); 107 }).get(mServiceTimeoutInSeconds, TimeUnit.SECONDS); 108 } 109 110 @FlaggedApi(Flags.FLAG_ENABLE_OEM_METADATA) 111 private void setResultForGetSupportedMimeTypes(Bundle result, 112 CompletableFuture<Set<String>> future) { 113 if (result.containsKey(EXTRA_OEM_SUPPORTED_MIME_TYPES)) { 114 ArrayList<String> supportedMimeTypes = result.getStringArrayList( 115 EXTRA_OEM_SUPPORTED_MIME_TYPES); 116 future.complete(Set.copyOf(supportedMimeTypes)); 117 } else { 118 Log.v(TAG, "No data received for getSupportedMimeTypes()"); 119 future.complete(new HashSet<>()); 120 } 121 } 122 123 @FlaggedApi(Flags.FLAG_ENABLE_OEM_METADATA) 124 private void setResultForGetOemCustomData(Bundle result, 125 CompletableFuture<Map<String, String>> future) { 126 if (result.containsKey(EXTRA_OEM_DATA_KEYS) && result.containsKey(EXTRA_OEM_DATA_VALUES)) { 127 Map<String, String> oemCustomDataMap = new HashMap<>(); 128 ArrayList<String> keys = result.getStringArrayList(EXTRA_OEM_DATA_KEYS); 129 ArrayList<String> values = result.getStringArrayList(EXTRA_OEM_DATA_VALUES); 130 for (int i = 0; i < keys.size(); i++) { 131 oemCustomDataMap.put(keys.get(i), values.get(i)); 132 } 133 future.complete(oemCustomDataMap); 134 } else { 135 Log.v(TAG, "No data received for getOemCustomData()"); 136 future.complete(new HashMap<>()); 137 } 138 } 139 } 140