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