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