1 /* 2 * Copyright (C) 2019 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 package android.car.media; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.annotation.RequiresPermission; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.car.Car; 24 import android.car.CarManagerBase; 25 import android.content.ComponentName; 26 import android.os.IBinder; 27 import android.os.RemoteException; 28 29 import com.android.internal.annotations.GuardedBy; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.HashMap; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * API for updating and receiving updates to the primary media source in the car. 39 * @hide 40 */ 41 @SystemApi 42 public final class CarMediaManager extends CarManagerBase { 43 44 public static final int MEDIA_SOURCE_MODE_PLAYBACK = 0; 45 public static final int MEDIA_SOURCE_MODE_BROWSE = 1; 46 47 /** @hide */ 48 @IntDef(prefix = { "MEDIA_SOURCE_MODE_" }, value = { 49 MEDIA_SOURCE_MODE_PLAYBACK, 50 MEDIA_SOURCE_MODE_BROWSE 51 }) 52 @Retention(RetentionPolicy.SOURCE) 53 public @interface MediaSourceMode {} 54 55 private final Object mLock = new Object(); 56 57 private final ICarMedia mService; 58 @GuardedBy("mLock") 59 private Map<MediaSourceChangedListener, ICarMediaSourceListener> mCallbackMap = new HashMap(); 60 61 /** 62 * Get an instance of the CarMediaManager. 63 * 64 * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 65 * @hide 66 */ CarMediaManager(Car car, IBinder service)67 public CarMediaManager(Car car, IBinder service) { 68 super(car); 69 mService = ICarMedia.Stub.asInterface(service); 70 } 71 72 /** 73 * Listener for updates to the primary media source 74 */ 75 public interface MediaSourceChangedListener { 76 77 /** 78 * Called when the primary media source is changed 79 */ onMediaSourceChanged(@onNull ComponentName componentName)80 void onMediaSourceChanged(@NonNull ComponentName componentName); 81 } 82 83 /** 84 * Gets the currently active media source for the provided mode 85 * 86 * @param mode the mode (playback or browse) for which the media source is active in. 87 * @return the active media source in the provided mode, will be non-{@code null}. 88 */ 89 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) getMediaSource(@ediaSourceMode int mode)90 public @NonNull ComponentName getMediaSource(@MediaSourceMode int mode) { 91 try { 92 return mService.getMediaSource(mode); 93 } catch (RemoteException e) { 94 return handleRemoteExceptionFromCarService(e, null); 95 } 96 } 97 98 /** 99 * Sets the currently active media source for the provided mode 100 * 101 * @param mode the mode (playback or browse) for which the media source is active in. 102 */ 103 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) setMediaSource(@onNull ComponentName componentName, @MediaSourceMode int mode)104 public void setMediaSource(@NonNull ComponentName componentName, @MediaSourceMode int mode) { 105 try { 106 mService.setMediaSource(componentName, mode); 107 } catch (RemoteException e) { 108 handleRemoteExceptionFromCarService(e); 109 } 110 } 111 112 /** 113 * Register a callback that receives updates to the active media source. 114 * 115 * @param callback the callback to receive active media source updates. 116 * @param mode the mode to receive updates for. 117 */ 118 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) addMediaSourceListener(@onNull MediaSourceChangedListener callback, @MediaSourceMode int mode)119 public void addMediaSourceListener(@NonNull MediaSourceChangedListener callback, 120 @MediaSourceMode int mode) { 121 try { 122 ICarMediaSourceListener binderCallback = new ICarMediaSourceListener.Stub() { 123 @Override 124 public void onMediaSourceChanged(ComponentName componentName) { 125 callback.onMediaSourceChanged(componentName); 126 } 127 }; 128 synchronized (mLock) { 129 mCallbackMap.put(callback, binderCallback); 130 } 131 mService.registerMediaSourceListener(binderCallback, mode); 132 } catch (RemoteException e) { 133 handleRemoteExceptionFromCarService(e); 134 } 135 } 136 137 /** 138 * Unregister a callback that receives updates to the active media source. 139 * 140 * @param callback the callback to be unregistered. 141 * @param mode the mode that the callback was registered to receive updates for. 142 */ 143 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) removeMediaSourceListener(@onNull MediaSourceChangedListener callback, @MediaSourceMode int mode)144 public void removeMediaSourceListener(@NonNull MediaSourceChangedListener callback, 145 @MediaSourceMode int mode) { 146 try { 147 synchronized (mLock) { 148 ICarMediaSourceListener binderCallback = mCallbackMap.remove(callback); 149 mService.unregisterMediaSourceListener(binderCallback, mode); 150 } 151 } catch (RemoteException e) { 152 handleRemoteExceptionFromCarService(e); 153 } 154 } 155 156 /** 157 * Retrieve a list of media sources, ordered by most recently used. 158 * 159 * @param mode the mode (playback or browse) for which to retrieve media sources from. 160 * @return non-{@code null} list of media sources, ordered by most recently used 161 */ 162 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) getLastMediaSources(@ediaSourceMode int mode)163 public @NonNull List<ComponentName> getLastMediaSources(@MediaSourceMode int mode) { 164 try { 165 return mService.getLastMediaSources(mode); 166 } catch (RemoteException e) { 167 return handleRemoteExceptionFromCarService(e, null); 168 } 169 } 170 171 /** @hide */ 172 @Override onCarDisconnected()173 public void onCarDisconnected() { 174 synchronized (mLock) { 175 mCallbackMap.clear(); 176 } 177 } 178 179 /** 180 * Returns whether the browse and playback sources can be changed independently. 181 * @return true if the browse and playback sources can be changed independently, false if it 182 * isn't or if the value could not be determined. 183 * @hide 184 */ 185 @TestApi 186 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) isIndependentPlaybackConfig()187 public boolean isIndependentPlaybackConfig() { 188 try { 189 return mService.isIndependentPlaybackConfig(); 190 } catch (RemoteException e) { 191 return handleRemoteExceptionFromCarService(e, null); 192 } 193 } 194 195 /** 196 * Sets whether the browse and playback sources can be changed independently. 197 * @param independent whether the browse and playback sources can be changed independently. 198 * @hide 199 */ 200 @TestApi 201 @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL) setIndependentPlaybackConfig(boolean independent)202 public void setIndependentPlaybackConfig(boolean independent) { 203 try { 204 mService.setIndependentPlaybackConfig(independent); 205 } catch (RemoteException e) { 206 handleRemoteExceptionFromCarService(e); 207 } 208 } 209 } 210