Loading packages/MediaComponents/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ LOCAL_SRC_FILES := \ LOCAL_PROGUARD_FLAG_FILES := proguard.cfg # TODO: Enable proguard (b/74090741) LOCAL_PROGUARD_ENABLED := disabled LOCAL_MULTILIB := first LOCAL_JAVA_LIBRARIES += android-support-annotations Loading packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java 0 → 100644 +433 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.DataSourceDesc; import android.media.MediaItem2; import android.media.MediaMetadata2; import android.media.MediaPlayerBase; import android.media.MediaPlaylistAgent; import android.media.MediaSession2; import android.media.MediaSession2.OnDataSourceMissingHelper; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; public class SessionPlaylistAgent extends MediaPlaylistAgent { private static final String TAG = "SessionPlaylistAgent"; @VisibleForTesting static final int END_OF_PLAYLIST = -1; @VisibleForTesting static final int NO_VALID_ITEMS = -2; private final PlayItem mEopPlayItem = new PlayItem(END_OF_PLAYLIST, null); private final Object mLock = new Object(); private final MediaSession2 mSession; // TODO: Set data sources properly into mPlayer (b/74090741) @GuardedBy("mLock") private MediaPlayerBase mPlayer; @GuardedBy("mLock") private OnDataSourceMissingHelper mDsdHelper; // TODO: Check if having the same item is okay (b/74090741) @GuardedBy("mLock") private ArrayList<MediaItem2> mPlaylist = new ArrayList<>(); @GuardedBy("mLock") private ArrayList<MediaItem2> mShuffledList = new ArrayList<>(); @GuardedBy("mLock") private Map<MediaItem2, DataSourceDesc> mItemDsdMap = new ArrayMap<>(); @GuardedBy("mLock") private MediaMetadata2 mMetadata; @GuardedBy("mLock") private int mRepeatMode; @GuardedBy("mLock") private int mShuffleMode; @GuardedBy("mLock") private PlayItem mCurrent; private class PlayItem { int shuffledIdx; DataSourceDesc dsd; MediaItem2 mediaItem; PlayItem(int shuffledIdx) { this(shuffledIdx, null); } PlayItem(int shuffledIdx, DataSourceDesc dsd) { this.shuffledIdx = shuffledIdx; if (shuffledIdx >= 0) { this.mediaItem = mShuffledList.get(shuffledIdx); if (dsd == null) { synchronized (mLock) { this.dsd = retrieveDataSourceDescLocked(this.mediaItem); } } else { this.dsd = dsd; } } } boolean isValid() { if (this == mEopPlayItem) { return true; } if (mediaItem == null) { return false; } if (dsd == null) { return false; } if (shuffledIdx >= mShuffledList.size()) { return false; } if (mediaItem != mShuffledList.get(shuffledIdx)) { return false; } if (mediaItem.getDataSourceDesc() != null && !mediaItem.getDataSourceDesc().equals(dsd)) { return false; } return true; } } public SessionPlaylistAgent(@NonNull Context context, @NonNull MediaSession2 session, @NonNull MediaPlayerBase player) { super(context); if (session == null) { throw new IllegalArgumentException("session shouldn't be null"); } if (player == null) { throw new IllegalArgumentException("player shouldn't be null"); } mSession = session; mPlayer = player; } public void setPlayer(MediaPlayerBase player) { if (player == null) { throw new IllegalArgumentException("player shouldn't be null"); } synchronized (mLock) { mPlayer = player; } } public void setOnDataSourceMissingHelper(OnDataSourceMissingHelper helper) { synchronized (mLock) { mDsdHelper = helper; } } @Override public @Nullable List<MediaItem2> getPlaylist() { synchronized (mLock) { return Collections.unmodifiableList(mPlaylist); } } @Override public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { if (list == null) { throw new IllegalArgumentException("list shouldn't be null"); } synchronized (mLock) { mItemDsdMap.clear(); mPlaylist.clear(); mPlaylist.addAll(list); applyShuffleModeLocked(); mMetadata = metadata; mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } notifyPlaylistChanged(); } @Override public @Nullable MediaMetadata2 getPlaylistMetadata() { return mMetadata; } @Override public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) { synchronized (mLock) { if (metadata == mMetadata) { return; } mMetadata = metadata; } notifyPlaylistMetadataChanged(); } @Override public void addPlaylistItem(int index, @NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { index = clamp(index, mPlaylist.size()); int shuffledIdx = index; mPlaylist.add(index, item); if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_NONE) { mShuffledList.add(index, item); } else { // Add the item in random position of mShuffledList. shuffledIdx = ThreadLocalRandom.current().nextInt(mShuffledList.size() + 1); mShuffledList.add(shuffledIdx, item); } if (!hasValidItem()) { mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } else { updateCurrentIfNeededLocked(); } } notifyPlaylistChanged(); } @Override public void removePlaylistItem(@NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (!mPlaylist.remove(item)) { return; } mShuffledList.remove(item); mItemDsdMap.remove(item); updateCurrentIfNeededLocked(); } notifyPlaylistChanged(); } @Override public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (mPlaylist.size() <= 0) { return; } index = clamp(index, mPlaylist.size() - 1); int shuffledIdx = mShuffledList.indexOf(mPlaylist.get(index)); mItemDsdMap.remove(mShuffledList.get(shuffledIdx)); mShuffledList.set(shuffledIdx, item); mPlaylist.set(index, item); if (!hasValidItem()) { mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } else { updateCurrentIfNeededLocked(); } } notifyPlaylistChanged(); } @Override public void skipToPlaylistItem(@NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (!hasValidItem() || item.equals(mCurrent.mediaItem)) { return; } int shuffledIdx = mShuffledList.indexOf(item); if (shuffledIdx < 0) { return; } mCurrent = new PlayItem(shuffledIdx); updateCurrentIfNeededLocked(); } } @Override public void skipToPreviousItem() { synchronized (mLock) { if (!hasValidItem()) { return; } PlayItem prev = getNextValidPlayItemLocked(mCurrent.shuffledIdx, -1); if (prev != mEopPlayItem) { mCurrent = prev; } updateCurrentIfNeededLocked(); } } @Override public void skipToNextItem() { synchronized (mLock) { if (!hasValidItem()) { return; } PlayItem next = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1); if (next != mEopPlayItem) { mCurrent = next; } updateCurrentIfNeededLocked(); } } @Override public int getRepeatMode() { return mRepeatMode; } @Override public void setRepeatMode(int repeatMode) { if (repeatMode < MediaPlaylistAgent.REPEAT_MODE_NONE || repeatMode > MediaPlaylistAgent.REPEAT_MODE_GROUP) { return; } synchronized (mLock) { if (mRepeatMode == repeatMode) { return; } mRepeatMode = repeatMode; } notifyRepeatModeChanged(); } @Override public int getShuffleMode() { return mShuffleMode; } @Override public void setShuffleMode(int shuffleMode) { if (shuffleMode < MediaPlaylistAgent.SHUFFLE_MODE_NONE || shuffleMode > MediaPlaylistAgent.SHUFFLE_MODE_GROUP) { return; } synchronized (mLock) { if (mShuffleMode == shuffleMode) { return; } mShuffleMode = shuffleMode; applyShuffleModeLocked(); } notifyShuffleModeChanged(); } @VisibleForTesting int getCurShuffledIndex() { return hasValidItem() ? mCurrent.shuffledIdx : NO_VALID_ITEMS; } private boolean hasValidItem() { return mCurrent != null; } private DataSourceDesc retrieveDataSourceDescLocked(MediaItem2 item) { DataSourceDesc dsd = item.getDataSourceDesc(); if (dsd != null) { mItemDsdMap.put(item, dsd); return dsd; } dsd = mItemDsdMap.get(item); if (dsd != null) { return dsd; } OnDataSourceMissingHelper helper = mDsdHelper; if (helper != null) { // TODO: Do not call onDataSourceMissing with the lock (b/74090741). dsd = helper.onDataSourceMissing(mSession, item); if (dsd != null) { mItemDsdMap.put(item, dsd); } } return dsd; } private PlayItem getNextValidPlayItemLocked(int curShuffledIdx, int direction) { int size = mPlaylist.size(); if (curShuffledIdx == END_OF_PLAYLIST) { curShuffledIdx = (direction > 0) ? -1 : size; } for (int i = 0; i < size; i++) { curShuffledIdx += direction; if (curShuffledIdx < 0 || curShuffledIdx >= mPlaylist.size()) { if (mRepeatMode == REPEAT_MODE_NONE) { return (i == size - 1) ? null : mEopPlayItem; } else { curShuffledIdx = curShuffledIdx < 0 ? mPlaylist.size() - 1 : 0; } } DataSourceDesc dsd = retrieveDataSourceDescLocked(mShuffledList.get(curShuffledIdx)); if (dsd != null) { return new PlayItem(curShuffledIdx, dsd); } } return null; } private void updateCurrentIfNeededLocked() { if (!hasValidItem() || mCurrent.isValid()) { return; } int shuffledIdx = mShuffledList.indexOf(mCurrent.mediaItem); if (shuffledIdx >= 0) { // Added an item. mCurrent.shuffledIdx = shuffledIdx; return; } if (mCurrent.shuffledIdx >= mShuffledList.size()) { mCurrent = getNextValidPlayItemLocked(mShuffledList.size() - 1, 1); } else { mCurrent.mediaItem = mShuffledList.get(mCurrent.shuffledIdx); if (retrieveDataSourceDescLocked(mCurrent.mediaItem) == null) { mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1); } } return; } private void applyShuffleModeLocked() { mShuffledList.clear(); mShuffledList.addAll(mPlaylist); if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_ALL || mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_GROUP) { Collections.shuffle(mShuffledList); } } // Clamps value to [0, size] private static int clamp(int value, int size) { if (value < 0) { return 0; } return (value > size) ? size : value; } } packages/MediaComponents/tests/Android.mk 0 → 100644 +35 −0 Original line number Diff line number Diff line # Copyright 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_STATIC_JAVA_LIBRARIES := \ android.test.runner.stubs \ android.test.base.stubs \ junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MediaComponentsTest LOCAL_INSTRUMENTATION_FOR := MediaComponents LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) packages/MediaComponents/tests/AndroidManifest.xml 0 → 100644 +33 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.media.tests"> <application android:label="Media API Test"> <uses-library android:name="android.test.runner" /> </application> <!-- To run the tests use the command: "adb shell am instrument -w com.android.media.tests/android.test.InstrumentationTestRunner" --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.android.media.update" android:label="Media API test" /> </manifest> Loading
packages/MediaComponents/Android.mk +3 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,9 @@ LOCAL_SRC_FILES := \ LOCAL_PROGUARD_FLAG_FILES := proguard.cfg # TODO: Enable proguard (b/74090741) LOCAL_PROGUARD_ENABLED := disabled LOCAL_MULTILIB := first LOCAL_JAVA_LIBRARIES += android-support-annotations Loading
packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java 0 → 100644 +433 −0 Original line number Diff line number Diff line /* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.DataSourceDesc; import android.media.MediaItem2; import android.media.MediaMetadata2; import android.media.MediaPlayerBase; import android.media.MediaPlaylistAgent; import android.media.MediaSession2; import android.media.MediaSession2.OnDataSourceMissingHelper; import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; public class SessionPlaylistAgent extends MediaPlaylistAgent { private static final String TAG = "SessionPlaylistAgent"; @VisibleForTesting static final int END_OF_PLAYLIST = -1; @VisibleForTesting static final int NO_VALID_ITEMS = -2; private final PlayItem mEopPlayItem = new PlayItem(END_OF_PLAYLIST, null); private final Object mLock = new Object(); private final MediaSession2 mSession; // TODO: Set data sources properly into mPlayer (b/74090741) @GuardedBy("mLock") private MediaPlayerBase mPlayer; @GuardedBy("mLock") private OnDataSourceMissingHelper mDsdHelper; // TODO: Check if having the same item is okay (b/74090741) @GuardedBy("mLock") private ArrayList<MediaItem2> mPlaylist = new ArrayList<>(); @GuardedBy("mLock") private ArrayList<MediaItem2> mShuffledList = new ArrayList<>(); @GuardedBy("mLock") private Map<MediaItem2, DataSourceDesc> mItemDsdMap = new ArrayMap<>(); @GuardedBy("mLock") private MediaMetadata2 mMetadata; @GuardedBy("mLock") private int mRepeatMode; @GuardedBy("mLock") private int mShuffleMode; @GuardedBy("mLock") private PlayItem mCurrent; private class PlayItem { int shuffledIdx; DataSourceDesc dsd; MediaItem2 mediaItem; PlayItem(int shuffledIdx) { this(shuffledIdx, null); } PlayItem(int shuffledIdx, DataSourceDesc dsd) { this.shuffledIdx = shuffledIdx; if (shuffledIdx >= 0) { this.mediaItem = mShuffledList.get(shuffledIdx); if (dsd == null) { synchronized (mLock) { this.dsd = retrieveDataSourceDescLocked(this.mediaItem); } } else { this.dsd = dsd; } } } boolean isValid() { if (this == mEopPlayItem) { return true; } if (mediaItem == null) { return false; } if (dsd == null) { return false; } if (shuffledIdx >= mShuffledList.size()) { return false; } if (mediaItem != mShuffledList.get(shuffledIdx)) { return false; } if (mediaItem.getDataSourceDesc() != null && !mediaItem.getDataSourceDesc().equals(dsd)) { return false; } return true; } } public SessionPlaylistAgent(@NonNull Context context, @NonNull MediaSession2 session, @NonNull MediaPlayerBase player) { super(context); if (session == null) { throw new IllegalArgumentException("session shouldn't be null"); } if (player == null) { throw new IllegalArgumentException("player shouldn't be null"); } mSession = session; mPlayer = player; } public void setPlayer(MediaPlayerBase player) { if (player == null) { throw new IllegalArgumentException("player shouldn't be null"); } synchronized (mLock) { mPlayer = player; } } public void setOnDataSourceMissingHelper(OnDataSourceMissingHelper helper) { synchronized (mLock) { mDsdHelper = helper; } } @Override public @Nullable List<MediaItem2> getPlaylist() { synchronized (mLock) { return Collections.unmodifiableList(mPlaylist); } } @Override public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { if (list == null) { throw new IllegalArgumentException("list shouldn't be null"); } synchronized (mLock) { mItemDsdMap.clear(); mPlaylist.clear(); mPlaylist.addAll(list); applyShuffleModeLocked(); mMetadata = metadata; mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } notifyPlaylistChanged(); } @Override public @Nullable MediaMetadata2 getPlaylistMetadata() { return mMetadata; } @Override public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) { synchronized (mLock) { if (metadata == mMetadata) { return; } mMetadata = metadata; } notifyPlaylistMetadataChanged(); } @Override public void addPlaylistItem(int index, @NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { index = clamp(index, mPlaylist.size()); int shuffledIdx = index; mPlaylist.add(index, item); if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_NONE) { mShuffledList.add(index, item); } else { // Add the item in random position of mShuffledList. shuffledIdx = ThreadLocalRandom.current().nextInt(mShuffledList.size() + 1); mShuffledList.add(shuffledIdx, item); } if (!hasValidItem()) { mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } else { updateCurrentIfNeededLocked(); } } notifyPlaylistChanged(); } @Override public void removePlaylistItem(@NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (!mPlaylist.remove(item)) { return; } mShuffledList.remove(item); mItemDsdMap.remove(item); updateCurrentIfNeededLocked(); } notifyPlaylistChanged(); } @Override public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (mPlaylist.size() <= 0) { return; } index = clamp(index, mPlaylist.size() - 1); int shuffledIdx = mShuffledList.indexOf(mPlaylist.get(index)); mItemDsdMap.remove(mShuffledList.get(shuffledIdx)); mShuffledList.set(shuffledIdx, item); mPlaylist.set(index, item); if (!hasValidItem()) { mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1); } else { updateCurrentIfNeededLocked(); } } notifyPlaylistChanged(); } @Override public void skipToPlaylistItem(@NonNull MediaItem2 item) { if (item == null) { throw new IllegalArgumentException("item shouldn't be null"); } synchronized (mLock) { if (!hasValidItem() || item.equals(mCurrent.mediaItem)) { return; } int shuffledIdx = mShuffledList.indexOf(item); if (shuffledIdx < 0) { return; } mCurrent = new PlayItem(shuffledIdx); updateCurrentIfNeededLocked(); } } @Override public void skipToPreviousItem() { synchronized (mLock) { if (!hasValidItem()) { return; } PlayItem prev = getNextValidPlayItemLocked(mCurrent.shuffledIdx, -1); if (prev != mEopPlayItem) { mCurrent = prev; } updateCurrentIfNeededLocked(); } } @Override public void skipToNextItem() { synchronized (mLock) { if (!hasValidItem()) { return; } PlayItem next = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1); if (next != mEopPlayItem) { mCurrent = next; } updateCurrentIfNeededLocked(); } } @Override public int getRepeatMode() { return mRepeatMode; } @Override public void setRepeatMode(int repeatMode) { if (repeatMode < MediaPlaylistAgent.REPEAT_MODE_NONE || repeatMode > MediaPlaylistAgent.REPEAT_MODE_GROUP) { return; } synchronized (mLock) { if (mRepeatMode == repeatMode) { return; } mRepeatMode = repeatMode; } notifyRepeatModeChanged(); } @Override public int getShuffleMode() { return mShuffleMode; } @Override public void setShuffleMode(int shuffleMode) { if (shuffleMode < MediaPlaylistAgent.SHUFFLE_MODE_NONE || shuffleMode > MediaPlaylistAgent.SHUFFLE_MODE_GROUP) { return; } synchronized (mLock) { if (mShuffleMode == shuffleMode) { return; } mShuffleMode = shuffleMode; applyShuffleModeLocked(); } notifyShuffleModeChanged(); } @VisibleForTesting int getCurShuffledIndex() { return hasValidItem() ? mCurrent.shuffledIdx : NO_VALID_ITEMS; } private boolean hasValidItem() { return mCurrent != null; } private DataSourceDesc retrieveDataSourceDescLocked(MediaItem2 item) { DataSourceDesc dsd = item.getDataSourceDesc(); if (dsd != null) { mItemDsdMap.put(item, dsd); return dsd; } dsd = mItemDsdMap.get(item); if (dsd != null) { return dsd; } OnDataSourceMissingHelper helper = mDsdHelper; if (helper != null) { // TODO: Do not call onDataSourceMissing with the lock (b/74090741). dsd = helper.onDataSourceMissing(mSession, item); if (dsd != null) { mItemDsdMap.put(item, dsd); } } return dsd; } private PlayItem getNextValidPlayItemLocked(int curShuffledIdx, int direction) { int size = mPlaylist.size(); if (curShuffledIdx == END_OF_PLAYLIST) { curShuffledIdx = (direction > 0) ? -1 : size; } for (int i = 0; i < size; i++) { curShuffledIdx += direction; if (curShuffledIdx < 0 || curShuffledIdx >= mPlaylist.size()) { if (mRepeatMode == REPEAT_MODE_NONE) { return (i == size - 1) ? null : mEopPlayItem; } else { curShuffledIdx = curShuffledIdx < 0 ? mPlaylist.size() - 1 : 0; } } DataSourceDesc dsd = retrieveDataSourceDescLocked(mShuffledList.get(curShuffledIdx)); if (dsd != null) { return new PlayItem(curShuffledIdx, dsd); } } return null; } private void updateCurrentIfNeededLocked() { if (!hasValidItem() || mCurrent.isValid()) { return; } int shuffledIdx = mShuffledList.indexOf(mCurrent.mediaItem); if (shuffledIdx >= 0) { // Added an item. mCurrent.shuffledIdx = shuffledIdx; return; } if (mCurrent.shuffledIdx >= mShuffledList.size()) { mCurrent = getNextValidPlayItemLocked(mShuffledList.size() - 1, 1); } else { mCurrent.mediaItem = mShuffledList.get(mCurrent.shuffledIdx); if (retrieveDataSourceDescLocked(mCurrent.mediaItem) == null) { mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1); } } return; } private void applyShuffleModeLocked() { mShuffledList.clear(); mShuffledList.addAll(mPlaylist); if (mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_ALL || mShuffleMode == MediaPlaylistAgent.SHUFFLE_MODE_GROUP) { Collections.shuffle(mShuffledList); } } // Clamps value to [0, size] private static int clamp(int value, int size) { if (value < 0) { return 0; } return (value > size) ? size : value; } }
packages/MediaComponents/tests/Android.mk 0 → 100644 +35 −0 Original line number Diff line number Diff line # Copyright 2018 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_STATIC_JAVA_LIBRARIES := \ android.test.runner.stubs \ android.test.base.stubs \ junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MediaComponentsTest LOCAL_INSTRUMENTATION_FOR := MediaComponents LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE)
packages/MediaComponents/tests/AndroidManifest.xml 0 → 100644 +33 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2018 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.media.tests"> <application android:label="Media API Test"> <uses-library android:name="android.test.runner" /> </application> <!-- To run the tests use the command: "adb shell am instrument -w com.android.media.tests/android.test.InstrumentationTestRunner" --> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.android.media.update" android:label="Media API test" /> </manifest>