1 /* 2 * Copyright 2018 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 com.android.media; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.media.DataSourceDesc; 23 import android.media.MediaItem2; 24 import android.media.MediaMetadata2; 25 import android.media.MediaPlaylistAgent; 26 import android.media.MediaPlaylistAgent.PlaylistEventCallback; 27 import android.media.update.MediaPlaylistAgentProvider; 28 import android.util.ArrayMap; 29 import android.util.Log; 30 31 import com.android.internal.annotations.GuardedBy; 32 33 import java.util.List; 34 import java.util.concurrent.Executor; 35 36 public class MediaPlaylistAgentImpl implements MediaPlaylistAgentProvider { 37 private static final String TAG = "MediaPlaylistAgent"; 38 39 private final MediaPlaylistAgent mInstance; 40 41 private final Object mLock = new Object(); 42 @GuardedBy("mLock") 43 private final ArrayMap<PlaylistEventCallback, Executor> mCallbacks = new ArrayMap<>(); 44 45 public MediaPlaylistAgentImpl(MediaPlaylistAgent instance) { 46 mInstance = instance; 47 } 48 49 @Override 50 final public void registerPlaylistEventCallback_impl( 51 @NonNull @CallbackExecutor Executor executor, @NonNull PlaylistEventCallback callback) { 52 if (executor == null) { 53 throw new IllegalArgumentException("executor shouldn't be null"); 54 } 55 if (callback == null) { 56 throw new IllegalArgumentException("callback shouldn't be null"); 57 } 58 59 synchronized (mLock) { 60 if (mCallbacks.get(callback) != null) { 61 Log.w(TAG, "callback is already added. Ignoring."); 62 return; 63 } 64 mCallbacks.put(callback, executor); 65 } 66 } 67 68 @Override 69 final public void unregisterPlaylistEventCallback_impl( 70 @NonNull PlaylistEventCallback callback) { 71 if (callback == null) { 72 throw new IllegalArgumentException("callback shouldn't be null"); 73 } 74 synchronized (mLock) { 75 mCallbacks.remove(callback); 76 } 77 } 78 79 @Override 80 final public void notifyPlaylistChanged_impl() { 81 ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks(); 82 List<MediaItem2> playlist= mInstance.getPlaylist(); 83 MediaMetadata2 metadata = mInstance.getPlaylistMetadata(); 84 for (int i = 0; i < callbacks.size(); i++) { 85 final PlaylistEventCallback callback = callbacks.keyAt(i); 86 final Executor executor = callbacks.valueAt(i); 87 executor.execute(() -> callback.onPlaylistChanged( 88 mInstance, playlist, metadata)); 89 } 90 } 91 92 @Override 93 final public void notifyPlaylistMetadataChanged_impl() { 94 ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks(); 95 for (int i = 0; i < callbacks.size(); i++) { 96 final PlaylistEventCallback callback = callbacks.keyAt(i); 97 final Executor executor = callbacks.valueAt(i); 98 executor.execute(() -> callback.onPlaylistMetadataChanged( 99 mInstance, mInstance.getPlaylistMetadata())); 100 } 101 } 102 103 @Override 104 final public void notifyShuffleModeChanged_impl() { 105 ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks(); 106 for (int i = 0; i < callbacks.size(); i++) { 107 final PlaylistEventCallback callback = callbacks.keyAt(i); 108 final Executor executor = callbacks.valueAt(i); 109 executor.execute(() -> callback.onShuffleModeChanged( 110 mInstance, mInstance.getShuffleMode())); 111 } 112 } 113 114 @Override 115 final public void notifyRepeatModeChanged_impl() { 116 ArrayMap<PlaylistEventCallback, Executor> callbacks = getCallbacks(); 117 for (int i = 0; i < callbacks.size(); i++) { 118 final PlaylistEventCallback callback = callbacks.keyAt(i); 119 final Executor executor = callbacks.valueAt(i); 120 executor.execute(() -> callback.onRepeatModeChanged( 121 mInstance, mInstance.getRepeatMode())); 122 } 123 } 124 125 @Override 126 public @Nullable List<MediaItem2> getPlaylist_impl() { 127 // empty implementation 128 return null; 129 } 130 131 @Override 132 public void setPlaylist_impl(@NonNull List<MediaItem2> list, 133 @Nullable MediaMetadata2 metadata) { 134 // empty implementation 135 } 136 137 @Override 138 public @Nullable MediaMetadata2 getPlaylistMetadata_impl() { 139 // empty implementation 140 return null; 141 } 142 143 @Override 144 public void updatePlaylistMetadata_impl(@Nullable MediaMetadata2 metadata) { 145 // empty implementation 146 } 147 148 @Override 149 public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) { 150 // empty implementation 151 } 152 153 @Override 154 public void removePlaylistItem_impl(@NonNull MediaItem2 item) { 155 // empty implementation 156 } 157 158 @Override 159 public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) { 160 // empty implementation 161 } 162 163 @Override 164 public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) { 165 // empty implementation 166 } 167 168 @Override 169 public void skipToPreviousItem_impl() { 170 // empty implementation 171 } 172 173 @Override 174 public void skipToNextItem_impl() { 175 // empty implementation 176 } 177 178 @Override 179 public int getRepeatMode_impl() { 180 return MediaPlaylistAgent.REPEAT_MODE_NONE; 181 } 182 183 @Override 184 public void setRepeatMode_impl(int repeatMode) { 185 // empty implementation 186 } 187 188 @Override 189 public int getShuffleMode_impl() { 190 // empty implementation 191 return MediaPlaylistAgent.SHUFFLE_MODE_NONE; 192 } 193 194 @Override 195 public void setShuffleMode_impl(int shuffleMode) { 196 // empty implementation 197 } 198 199 @Override 200 public @Nullable MediaItem2 getMediaItem_impl(@NonNull DataSourceDesc dsd) { 201 if (dsd == null) { 202 throw new IllegalArgumentException("dsd shouldn't be null"); 203 } 204 List<MediaItem2> itemList = mInstance.getPlaylist(); 205 if (itemList == null) { 206 return null; 207 } 208 for (int i = 0; i < itemList.size(); i++) { 209 MediaItem2 item = itemList.get(i); 210 if (item != null && item.getDataSourceDesc() == dsd) { 211 return item; 212 } 213 } 214 return null; 215 } 216 217 private ArrayMap<PlaylistEventCallback, Executor> getCallbacks() { 218 ArrayMap<PlaylistEventCallback, Executor> callbacks = new ArrayMap<>(); 219 synchronized (mLock) { 220 callbacks.putAll(mCallbacks); 221 } 222 return callbacks; 223 } 224 } 225