diff options
author | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-20 14:15:46 -0400 |
---|---|---|
committer | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-20 14:15:46 -0400 |
commit | a89edfcad4f69a7f8ddbce62ca33d4ba80d4a9ad (patch) | |
tree | 9c9e094567c5845cf6217c7fcb84ef9174011bb1 | |
parent | 7a69147a9ef21cea6aad096f628cc4a84f054ef4 (diff) | |
parent | ff9cc13b6a92ac1855ad1e9c36a71d195f4ec3e2 (diff) | |
download | AntennaPod-a89edfcad4f69a7f8ddbce62ca33d4ba80d4a9ad.zip |
Merge pull request #1212 from mfietz/ext_audioplayers_lib
Alternative to Prestissimo [4.1+] and other annoyances
38 files changed, 923 insertions, 3758 deletions
diff --git a/app/build.gradle b/app/build.gradle index e18708878..3415189aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,6 +4,7 @@ apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' repositories { + maven { url "https://jitpack.io" } mavenCentral() } @@ -28,6 +29,7 @@ dependencies { compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.0.3' compile 'com.afollestad:material-dialogs:0.7.8.0' + compile 'com.github.AntennaPod:AntennaPod-AudioPlayer:v1.0' compile project(':core') compile project(':library:drag-sort-listview') diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java new file mode 100644 index 000000000..17ec87aa3 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java @@ -0,0 +1,363 @@ +package de.test.antennapod.ui; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Build; +import android.preference.PreferenceManager; +import android.test.ActivityInstrumentationTestCase2; +import android.test.FlakyTest; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ListView; + +import com.robotium.solo.Solo; +import com.robotium.solo.Timeout; + +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.playback.PlaybackService; +import de.danoeh.antennapod.core.service.playback.PlayerStatus; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.PodDBAdapter; +import de.danoeh.antennapod.core.util.playback.Playable; +import de.danoeh.antennapod.core.util.playback.PlaybackController; + +/** + * test cases for starting and ending playback from the MainActivity and AudioPlayerActivity + */ +@TargetApi(Build.VERSION_CODES.JELLY_BEAN) +public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActivity> { + + private static final String TAG = PlaybackTest.class.getSimpleName(); + public static final int EPISODES_DRAWER_LIST_INDEX = 1; + public static final int QUEUE_DRAWER_LIST_INDEX = 0; + + private Solo solo; + private UITestUtils uiTestUtils; + + private Context context; + + private PlaybackController controller; + protected FeedMedia currentMedia; + + private PlaybackController createController(Activity activity) { + return new PlaybackController(activity, false) { + + @Override + public void setupGUI() { + } + + @Override + public void onPositionObserverUpdate() { + } + + @Override + public void onBufferStart() { + } + + @Override + public void onBufferEnd() { + } + + @Override + public void onBufferUpdate(float progress) { + } + + @Override + public void handleError(int code) { + } + + @Override + public void onReloadNotification(int code) { + } + + @Override + public void onSleepTimerUpdate() { + } + + @Override + public ImageButton getPlayButton() { + return null; + } + + @Override + public void postStatusMsg(int msg) { + } + + @Override + public void clearStatusMsg() { + } + + @Override + public boolean loadMediaInfo() { + Playable playable = controller.getMedia(); + if(playable == null) { + currentMedia = null; + return true; + } else if(playable instanceof FeedMedia) { + currentMedia = (FeedMedia) playable; + return true; + } else { + return false; + } + } + + @Override + public void onAwaitingVideoSurface() { + } + + @Override + public void onServiceQueried() { + } + + @Override + public void onShutdownNotification() { + } + + @Override + public void onPlaybackEnd() { + currentMedia = null; + } + + @Override + public void onPlaybackSpeedChange() { + } + + @Override + protected void setScreenOn(boolean enable) { + } + }; + } + + public PlaybackSonicTest() { + super(MainActivity.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + + PodDBAdapter.deleteDatabase(); + + context = getInstrumentation().getTargetContext(); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.edit() + .clear() + .putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false) + .putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false) + .putBoolean(UserPreferences.PREF_SONIC, true) + .commit(); + + controller = createController(getActivity()); + controller.init(); + + solo = new Solo(getInstrumentation(), getActivity()); + + uiTestUtils = new UITestUtils(context); + uiTestUtils.setup(); + + // create database + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.close(); + } + + @Override + public void tearDown() throws Exception { + controller.release(); + solo.finishOpenedActivities(); + uiTestUtils.tearDown(); + + // shut down playback service + skipEpisode(); + context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + + super.tearDown(); + } + + private void openNavDrawer() { + solo.clickOnScreen(50, 50); + } + + private void setContinuousPlaybackPreference(boolean value) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit(); + } + + private void skipEpisode() { + Intent skipIntent = new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE); + context.sendBroadcast(skipIntent); + } + + private void startLocalPlayback() { + openNavDrawer(); + // if we try to just click on plain old text then + // we might wind up clicking on the fragment title and not + // the drawer element like we want. + ListView drawerView = (ListView)solo.getView(R.id.nav_list); + // this should be 'Episodes' + View targetView = drawerView.getChildAt(EPISODES_DRAWER_LIST_INDEX); + solo.waitForView(targetView); + solo.clickOnView(targetView); + solo.waitForText(solo.getString(R.string.all_episodes_short_label)); + solo.clickOnText(solo.getString(R.string.all_episodes_short_label)); + + final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(10); + assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction))); + + solo.clickOnView(solo.getView(R.id.butSecondaryAction)); + long mediaId = episodes.get(0).getMedia().getId(); + boolean playing = solo.waitForCondition(() -> { + if (currentMedia != null) { + return currentMedia.getId() == mediaId; + } else { + return false; + } + }, Timeout.getSmallTimeout()); + assertTrue(playing); + } + + private void startLocalPlaybackFromQueue() { + openNavDrawer(); + + // if we try to just click on plain old text then + // we might wind up clicking on the fragment title and not + // the drawer element like we want. + ListView drawerView = (ListView)solo.getView(R.id.nav_list); + // this should be 'Queue' + View targetView = drawerView.getChildAt(QUEUE_DRAWER_LIST_INDEX); + solo.waitForView(targetView); + solo.clickOnView(targetView); + + assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction))); + final List<FeedItem> queue = DBReader.getQueue(); + solo.clickOnImageButton(1); + assertTrue(solo.waitForView(solo.getView(R.id.butPlay))); + long mediaId = queue.get(0).getMedia().getId(); + boolean playing = solo.waitForCondition(() -> { + if(currentMedia != null) { + return currentMedia.getId() == mediaId; + } else { + return false; + } + }, Timeout.getSmallTimeout()); + assertTrue(playing); + } + + public void testStartLocal() throws Exception { + uiTestUtils.addLocalFeedData(true); + DBWriter.clearQueue().get(); + startLocalPlayback(); + } + + public void testContinousPlaybackOffSingleEpisode() throws Exception { + setContinuousPlaybackPreference(false); + uiTestUtils.addLocalFeedData(true); + DBWriter.clearQueue().get(); + startLocalPlayback(); + } + + @FlakyTest(tolerance = 3) + public void testContinousPlaybackOffMultipleEpisodes() throws Exception { + setContinuousPlaybackPreference(false); + uiTestUtils.addLocalFeedData(true); + List<FeedItem> queue = DBReader.getQueue(); + final FeedItem first = queue.get(0); + + startLocalPlaybackFromQueue(); + boolean stopped = solo.waitForCondition(() -> { + if (currentMedia != null) { + return currentMedia.getId() != first.getMedia().getId(); + } else { + return false; + } + }, Timeout.getSmallTimeout()); + assertTrue(stopped); + Thread.sleep(1000); + PlayerStatus status = controller.getStatus(); + assertFalse(status.equals(PlayerStatus.PLAYING)); + } + + @FlakyTest(tolerance = 3) + public void testContinuousPlaybackOnMultipleEpisodes() throws Exception { + setContinuousPlaybackPreference(true); + uiTestUtils.addLocalFeedData(true); + List<FeedItem> queue = DBReader.getQueue(); + final FeedItem first = queue.get(0); + final FeedItem second = queue.get(1); + + startLocalPlaybackFromQueue(); + boolean firstPlaying = solo.waitForCondition(() -> { + if (currentMedia != null) { + return currentMedia.getId() == first.getMedia().getId(); + } else { + return false; + } + }, Timeout.getSmallTimeout()); + assertTrue(firstPlaying); + boolean secondPlaying = solo.waitForCondition(() -> { + if (currentMedia != null) { + return currentMedia.getId() == second.getMedia().getId(); + } else { + return false; + } + }, Timeout.getLargeTimeout()); + assertTrue(secondPlaying); + } + + /** + * Check if an episode can be played twice without problems. + */ + private void replayEpisodeCheck(boolean followQueue) throws Exception { + setContinuousPlaybackPreference(followQueue); + uiTestUtils.addLocalFeedData(true); + DBWriter.clearQueue().get(); + final List<FeedItem> episodes = DBReader.getRecentlyPublishedEpisodes(10); + + startLocalPlayback(); + long mediaId = episodes.get(0).getMedia().getId(); + boolean startedPlaying = solo.waitForCondition(() -> { + if (currentMedia != null) { + return currentMedia.getId() == mediaId; + } else { + return false; + } + }, Timeout.getSmallTimeout()); + assertTrue(startedPlaying); + + boolean stoppedPlaying = solo.waitForCondition(() -> { + return currentMedia == null || currentMedia.getId() != mediaId; + }, Timeout.getLargeTimeout()); + assertTrue(stoppedPlaying); + + startLocalPlayback(); + boolean startedReplay = solo.waitForCondition(() -> { + if(currentMedia != null) { + return currentMedia.getId() == mediaId; + } else { + return false; + } + }, Timeout.getLargeTimeout()); + assertTrue(startedReplay); + } + + public void testReplayEpisodeContinuousPlaybackOn() throws Exception { + replayEpisodeCheck(true); + } + + public void testReplayEpisodeContinuousPlaybackOff() throws Exception { + replayEpisodeCheck(false); + } + + +} diff --git a/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt b/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/app/src/main/assets/LICENSE_ANTENNAPOD_AUDIOPLAYER.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java index df764e829..fe31ccda8 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java @@ -57,9 +57,13 @@ public class AboutActivity extends ActionBarActivity { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - url = url.replace("file:///android_asset/", ""); - loadAsset(url); - return true; + if(url.startsWith("http")) { + return false; + } else { + url = url.replace("file:///android_asset/", ""); + loadAsset(url); + return true; + } } }); @@ -126,8 +130,10 @@ public class AboutActivity extends ActionBarActivity { @Override public void onBackPressed() { - if(showingLicense) { + if(showingLicense || webview.canGoBack()) { loadAsset("about.html"); + } else if(webview.canGoBack()) { + webview.goBack(); } else { super.onBackPressed(); } diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index 8eba51540..b01b13492 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -6,18 +6,19 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.preferences.UserPreferences; import java.util.Arrays; import java.util.List; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.preferences.UserPreferences; + public class VariableSpeedDialog { private VariableSpeedDialog() { } public static void showDialog(final Context context) { - if (com.aocate.media.MediaPlayer.isPrestoLibraryInstalled(context)) { + if (org.antennapod.audio.MediaPlayer.isPrestoLibraryInstalled(context)) { showSpeedSelectorDialog(context); } else { showGetPluginDialog(context); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 5d0edb638..5aed66013 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -4,10 +4,10 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; +import android.support.v4.util.Pair; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.SearchView; import android.util.Log; @@ -38,7 +38,6 @@ import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBReader; @@ -49,6 +48,10 @@ import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Shows unread or recently published episodes @@ -90,6 +93,8 @@ public class AllEpisodesFragment extends Fragment { private boolean isUpdatingFeeds; + protected Subscription subscription; + public AllEpisodesFragment() { // by default we show all the episodes this(false, DEFAULT_PREF_NAME); @@ -113,7 +118,7 @@ public class AllEpisodesFragment extends Fragment { @Override public void onResume() { super.onResume(); - startItemLoader(); + loadItems(); } @Override @@ -140,7 +145,9 @@ public class AllEpisodesFragment extends Fragment { public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -436,7 +443,7 @@ public class AllEpisodesFragment extends Fragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EVENTS) != 0) { - startItemLoader(); + loadItems(); if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) { getActivity().supportInvalidateOptionsMenu(); } @@ -453,69 +460,43 @@ public class AllEpisodesFragment extends Fragment { } } - private ItemLoader itemLoader; - - protected void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + protected void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } - itemLoader = new ItemLoader(); - itemLoader.execute(); - } - - protected void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + if (viewsCreated && !itemsLoaded) { + listView.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progLoading.setVisibility(View.VISIBLE); } + subscription = Observable.defer(() -> Observable.just(loadData())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(data -> { + listView.setVisibility(View.VISIBLE); + progLoading.setVisibility(View.GONE); + if (data != null) { + episodes = data.first; + queuedItemsIds = data.second; + itemsLoaded = true; + if (viewsCreated && activity.get() != null) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private class ItemLoader extends AsyncTask<Void, Void, Object[]> { - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (viewsCreated && !itemsLoaded) { - listView.setVisibility(View.GONE); - txtvEmpty.setVisibility(View.GONE); - progLoading.setVisibility(View.VISIBLE); - } - } - - @Override - protected Object[] doInBackground(Void... params) { - Context context = activity.get(); - if (context != null) { - if(showOnlyNewEpisodes) { - return new Object[] { - DBReader.getNewItemsList(), - DBReader.getQueueIDList(), - null // see ItemAccess.isNew - }; - } else { - return new Object[]{ - DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT), - DBReader.getQueueIDList() - }; - } - } else { - return null; - } - } - - @Override - protected void onPostExecute(Object[] lists) { - super.onPostExecute(lists); - listView.setVisibility(View.VISIBLE); - progLoading.setVisibility(View.GONE); - - if (lists != null) { - episodes = (List<FeedItem>) lists[0]; - queuedItemsIds = (LongList) lists[1]; - itemsLoaded = true; - if (viewsCreated && activity.get() != null) { - onFragmentLoaded(); - } - } + private Pair<List<FeedItem>,LongList> loadData() { + List<FeedItem> items; + if(showOnlyNewEpisodes) { + items = DBReader.getNewItemsList(); + } else { + items = DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT); } + LongList queuedIds = DBReader.getQueueIDList(); + return Pair.create(items, queuedIds); } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java index 278928f3d..c5b582d3a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -1,14 +1,12 @@ package de.danoeh.antennapod.fragment; import android.app.Activity; -import android.content.Context; -import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; +import android.util.Log; import android.view.View; import android.widget.ListView; -import java.util.Collections; import java.util.List; import de.danoeh.antennapod.R; @@ -18,11 +16,18 @@ import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Displays all running downloads and provides a button to delete them */ public class CompletedDownloadsFragment extends ListFragment { + + private static final String TAG = CompletedDownloadsFragment.class.getSimpleName(); + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOADLOG_UPDATE | @@ -34,11 +39,12 @@ public class CompletedDownloadsFragment extends ListFragment { private boolean viewCreated = false; private boolean itemsLoaded = false; + private Subscription subscription; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - startItemLoader(); + loadItems(); } @Override @@ -51,13 +57,17 @@ public class CompletedDownloadsFragment extends ListFragment { public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override public void onDetach() { super.onDetach(); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -65,7 +75,9 @@ public class CompletedDownloadsFragment extends ListFragment { super.onDestroyView(); listAdapter = null; viewCreated = false; - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -132,56 +144,32 @@ public class CompletedDownloadsFragment extends ListFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EVENTS) != 0) { - startItemLoader(); + loadItems(); } } }; - private ItemLoader itemLoader; - - private void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + private void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } - itemLoader = new ItemLoader(); - itemLoader.execute(); - } - - private void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + if (!itemsLoaded && viewCreated) { + setListShown(false); } + subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadedItems())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result != null) { + items = result; + itemsLoaded = true; + if (viewCreated && getActivity() != null) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> { - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (!itemsLoaded && viewCreated) { - setListShown(false); - } - } - - @Override - protected void onPostExecute(List<FeedItem> results) { - super.onPostExecute(results); - if (results != null) { - items = results; - itemsLoaded = true; - if (viewCreated && getActivity() != null) { - onFragmentLoaded(); - } - } - } - - @Override - protected List<FeedItem> doInBackground(Void... params) { - Context context = getActivity(); - if (context != null) { - return DBReader.getDownloadedItems(); - } - return Collections.emptyList(); - } - } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java index da2c05a69..669c6ac49 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java @@ -1,11 +1,10 @@ package de.danoeh.antennapod.fragment; -import android.content.Context; import android.content.res.TypedArray; -import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.view.MenuItemCompat; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -20,6 +19,10 @@ import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Shows the download log @@ -34,19 +37,23 @@ public class DownloadLogFragment extends ListFragment { private boolean viewsCreated = false; private boolean itemsLoaded = false; + private Subscription subscription; + @Override public void onStart() { super.onStart(); setHasOptionsMenu(true); EventDistributor.getInstance().register(contentUpdate); - startItemLoader(); + loadItems(); } @Override public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -93,27 +100,11 @@ public class DownloadLogFragment extends ListFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) { - startItemLoader(); + loadItems(); } } }; - private ItemLoader itemLoader; - - private void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); - } - itemLoader = new ItemLoader(); - itemLoader.execute(); - } - - private void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); - } - } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); @@ -152,27 +143,24 @@ public class DownloadLogFragment extends ListFragment { } } - private class ItemLoader extends AsyncTask<Void, Void, List<DownloadStatus>> { - - @Override - protected void onPostExecute(List<DownloadStatus> downloadStatuses) { - super.onPostExecute(downloadStatuses); - if (downloadStatuses != null) { - downloadLog = downloadStatuses; - itemsLoaded = true; - if (viewsCreated) { - onFragmentLoaded(); - } - } - } - - @Override - protected List<DownloadStatus> doInBackground(Void... params) { - Context context = getActivity(); - if (context != null) { - return DBReader.getDownloadLog(); - } - return null; + private void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } + subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadLog())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result != null) { + downloadLog = result; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java index 38c9b645a..3d0ff66f7 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -7,12 +7,12 @@ import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.LightingColorFilter; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; import android.support.v4.app.ListFragment; +import android.support.v4.util.Pair; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; @@ -73,6 +73,10 @@ import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.FeedMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; import de.greenrobot.event.EventBus; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Displays a list of FeedItems. @@ -111,6 +115,8 @@ public class ItemlistFragment extends ListFragment { private TextView txtvInformation; + private Subscription subscription; + /** * Creates new ItemlistFragment which shows the Feeditems of a specific * feed. Sets 'showFeedtitle' to false @@ -156,7 +162,9 @@ public class ItemlistFragment extends ListFragment { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); EventBus.getDefault().unregister(this); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -164,13 +172,15 @@ public class ItemlistFragment extends ListFragment { super.onResume(); Log.d(TAG, "onResume()"); updateProgressBarVisibility(); - startItemLoader(); + loadItems(); } @Override public void onDetach() { super.onDetach(); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -385,13 +395,13 @@ public class ItemlistFragment extends ListFragment { public void onEvent(QueueEvent event) { Log.d(TAG, "onEvent(" + event + ")"); - startItemLoader(); + loadItems(); } public void onEvent(FeedEvent event) { Log.d(TAG, "onEvent(" + event + ")"); if(event.feedId == feedID) { - startItemLoader(); + loadItems(); } } @@ -404,7 +414,7 @@ public class ItemlistFragment extends ListFragment { if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { updateProgressBarVisibility(); } else { - startItemLoader(); + loadItems(); updateProgressBarVisibility(); } } @@ -608,51 +618,37 @@ public class ItemlistFragment extends ListFragment { } }; - private ItemLoader itemLoader; - private void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + private void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } - itemLoader = new ItemLoader(); - itemLoader.execute(feedID); - } - private void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); - } + subscription = Observable.defer(() -> Observable.just(loadData())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result != null) { + feed = result.first; + queuedItemsIds = result.second; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private class ItemLoader extends AsyncTask<Long, Void, Object[]> { - @Override - protected Object[] doInBackground(Long... params) { - long feedID = params[0]; - Context context = getActivity(); - if (context != null) { - Feed feed = DBReader.getFeed(feedID); - if(feed != null && feed.getItemFilter() != null) { - FeedItemFilter filter = feed.getItemFilter(); - feed.setItems(filter.filter(context, feed.getItems())); - } - LongList queuedItemsIds = DBReader.getQueueIDList(); - return new Object[] { feed, queuedItemsIds }; - } else { - return null; - } - } - - @Override - protected void onPostExecute(Object[] res) { - super.onPostExecute(res); - if (res != null) { - feed = (Feed) res[0]; - queuedItemsIds = (LongList) res[1]; - itemsLoaded = true; - if (viewsCreated) { - onFragmentLoaded(); - } - } + private Pair<Feed, LongList> loadData() { + Feed feed = DBReader.getFeed(feedID); + if(feed != null && feed.getItemFilter() != null) { + FeedItemFilter filter = feed.getItemFilter(); + feed.setItems(filter.filter(feed.getItems())); } + LongList queuedItemsIds = DBReader.getQueueIDList(); + return Pair.create(feed, queuedItemsIds); } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index 6177f2a50..d454208c1 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -39,7 +39,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment { public void onEvent(QueueEvent event) { Log.d(TAG, "onEvent(" + event + ")"); - startItemLoader(); + loadItems(); } @Override @@ -69,7 +69,9 @@ public class NewEpisodesFragment extends AllEpisodesFragment { @Override public void remove(int which) { Log.d(TAG, "remove(" + which + ")"); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } FeedItem item = (FeedItem) listView.getAdapter().getItem(which); // we're marking it as unplayed since the user didn't actually play it // but they don't want it considered 'NEW' anymore diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index 530883667..e6460309b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -1,9 +1,7 @@ package de.danoeh.antennapod.fragment; import android.app.Activity; -import android.content.Context; import android.content.res.TypedArray; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.ListFragment; @@ -33,6 +31,10 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.util.LongList; import de.greenrobot.event.EventBus; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; public class PlaybackHistoryFragment extends ListFragment { @@ -53,6 +55,8 @@ public class PlaybackHistoryFragment extends ListFragment { private DownloadObserver downloadObserver; private List<Downloader> downloaderList; + private Subscription subscription; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -63,7 +67,7 @@ public class PlaybackHistoryFragment extends ListFragment { @Override public void onResume() { super.onResume(); - startItemLoader(); + loadItems(); } @Override @@ -78,13 +82,17 @@ public class PlaybackHistoryFragment extends ListFragment { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); EventBus.getDefault().unregister(this); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override public void onDetach() { super.onDetach(); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } activity.set(null); } @@ -176,7 +184,7 @@ public class PlaybackHistoryFragment extends ListFragment { public void onEvent(QueueEvent event) { Log.d(TAG, "onEvent(" + event + ")"); - startItemLoader(); + loadItems(); } private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { @@ -184,7 +192,7 @@ public class PlaybackHistoryFragment extends ListFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EVENTS) != 0) { - startItemLoader(); + loadItems(); getActivity().supportInvalidateOptionsMenu(); } } @@ -245,48 +253,32 @@ public class PlaybackHistoryFragment extends ListFragment { } }; - private ItemLoader itemLoader; - - private void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + private void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } - itemLoader = new ItemLoader(); - itemLoader.execute(); + subscription = Observable.defer(() -> Observable.just(loadData())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result != null) { + playbackHistory = result.first; + queue = result.second; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); - } + private Pair<List<FeedItem>, LongList> loadData() { + List<FeedItem> history = DBReader.getPlaybackHistory(); + LongList queue = DBReader.getQueueIDList(); + DBReader.loadFeedDataOfFeedItemlist(history); + return Pair.create(history, queue); } - private class ItemLoader extends AsyncTask<Void, Void, Pair<List<FeedItem>,LongList>> { - - @Override - protected Pair<List<FeedItem>,LongList> doInBackground(Void... params) { - Context context = activity.get(); - if (context != null) { - List<FeedItem> history = DBReader.getPlaybackHistory(); - LongList queue = DBReader.getQueueIDList(); - DBReader.loadFeedDataOfFeedItemlist(history); - return Pair.create(history, queue); - } else { - return null; - } - } - - @Override - protected void onPostExecute(Pair<List<FeedItem>,LongList> res) { - super.onPostExecute(res); - if (res != null) { - playbackHistory = res.first; - queue = res.second; - itemsLoaded = true; - if (viewsCreated) { - onFragmentLoaded(); - } - } - } - } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 63c319e03..7bcd98dc8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.Fragment; @@ -55,6 +54,10 @@ import de.danoeh.antennapod.core.util.gui.UndoBarController; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; import de.greenrobot.event.EventBus; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Shows all items in the queue @@ -98,6 +101,8 @@ public class QueueFragment extends Fragment { */ private boolean blockDownloadObserverUpdate = false; + private Subscription subscription; + @Override public void onCreate(Bundle savedInstanceState) { @@ -109,7 +114,7 @@ public class QueueFragment extends Fragment { @Override public void onResume() { super.onResume(); - startItemLoader(); + loadItems(); } @Override @@ -138,7 +143,9 @@ public class QueueFragment extends Fragment { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); EventBus.getDefault().unregister(this); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } if(undoBarController.isShowing()) { undoBarController.close(); } @@ -156,7 +163,7 @@ public class QueueFragment extends Fragment { undoBarController.showUndoBar(false, getString(R.string.removed_from_queue), new FeedItemUndoToken(event.item, event.position)); } - startItemLoader(); + loadItems(); } private void saveScrollPosition() { @@ -398,7 +405,9 @@ public class QueueFragment extends Fragment { public void drop(int from, int to) { Log.d(TAG, "drop"); blockDownloadObserverUpdate = false; - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } final FeedItem item = queue.remove(from); queue.add(to, item); listAdapter.notifyDataSetChanged(); @@ -408,7 +417,9 @@ public class QueueFragment extends Fragment { @Override public void remove(int which) { Log.d(TAG, "remove(" + which + ")"); - stopItemLoader(); + if(subscription != null) { + subscription.unsubscribe(); + } FeedItem item = (FeedItem) listView.getAdapter().getItem(which); DBWriter.removeQueueItem(getActivity(), item, true); } @@ -556,7 +567,7 @@ public class QueueFragment extends Fragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & EVENTS) != 0) { - startItemLoader(); + loadItems(); if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) { getActivity().supportInvalidateOptionsMenu(); } @@ -564,55 +575,31 @@ public class QueueFragment extends Fragment { } }; - private ItemLoader itemLoader; - - private void startItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + private void loadItems() { + if(subscription != null) { + subscription.unsubscribe(); } - itemLoader = new ItemLoader(); - itemLoader.execute(); - } - - private void stopItemLoader() { - if (itemLoader != null) { - itemLoader.cancel(true); + if (viewsCreated && !itemsLoaded) { + listView.setVisibility(View.GONE); + txtvEmpty.setVisibility(View.GONE); + progLoading.setVisibility(View.VISIBLE); } + subscription = Observable.defer(() -> Observable.just(DBReader.getQueue())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + listView.setVisibility(View.VISIBLE); + progLoading.setVisibility(View.GONE); + if(result != null) { + queue = result; + itemsLoaded = true; + if (viewsCreated && activity.get() != null) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> { - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (viewsCreated && !itemsLoaded) { - listView.setVisibility(View.GONE); - txtvEmpty.setVisibility(View.GONE); - progLoading.setVisibility(View.VISIBLE); - } - } - - @Override - protected void onPostExecute(List<FeedItem> feedItems) { - super.onPostExecute(feedItems); - listView.setVisibility(View.VISIBLE); - progLoading.setVisibility(View.GONE); - - if (feedItems != null) { - queue = feedItems; - itemsLoaded = true; - if (viewsCreated && activity.get() != null) { - onFragmentLoaded(); - } - } - } - - @Override - protected List<FeedItem> doInBackground(Void... params) { - Context context = activity.get(); - if (context != null) { - return DBReader.getQueue(); - } - return null; - } - } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index 975493ce9..edd8cdd1a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -1,19 +1,18 @@ package de.danoeh.antennapod.fragment; import android.content.Context; -import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.ListView; -import java.util.Collections; import java.util.List; import de.danoeh.antennapod.R; @@ -25,6 +24,10 @@ import de.danoeh.antennapod.core.feed.FeedComponent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.SearchResult; import de.danoeh.antennapod.core.storage.FeedSearcher; +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; /** * Performs a search operation on all feeds or one specific feed and displays the search result. @@ -41,6 +44,8 @@ public class SearchFragment extends ListFragment { private boolean viewCreated = false; private boolean itemsLoaded = false; + private Subscription subscription; + /** * Create a new SearchFragment that searches all feeds. */ @@ -68,7 +73,7 @@ public class SearchFragment extends ListFragment { super.onCreate(savedInstanceState); setRetainInstance(true); setHasOptionsMenu(true); - startSearchTask(); + search(); } @Override @@ -80,14 +85,18 @@ public class SearchFragment extends ListFragment { @Override public void onStop() { super.onStop(); - stopSearchTask(); + if(subscription != null) { + subscription.unsubscribe(); + } EventDistributor.getInstance().unregister(contentUpdate); } @Override public void onDetach() { super.onDetach(); - stopSearchTask(); + if(subscription != null) { + subscription.unsubscribe(); + } } @Override @@ -143,7 +152,7 @@ public class SearchFragment extends ListFragment { public boolean onQueryTextSubmit(String s) { getArguments().putString(ARG_QUERY, s); itemsLoaded = false; - startSearchTask(); + search(); return true; } @@ -161,7 +170,7 @@ public class SearchFragment extends ListFragment { public void update(EventDistributor eventDistributor, Integer arg) { if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE | EventDistributor.DOWNLOAD_HANDLED)) != 0) { - startSearchTask(); + search(); } } }; @@ -187,53 +196,36 @@ public class SearchFragment extends ListFragment { } }; - private SearchTask searchTask; - private void startSearchTask() { - if (searchTask != null) { - searchTask.cancel(true); + private void search() { + if(subscription != null) { + subscription.unsubscribe(); } - searchTask = new SearchTask(); - searchTask.execute(getArguments()); - } - - private void stopSearchTask() { - if (searchTask != null) { - searchTask.cancel(true); + if (viewCreated && !itemsLoaded) { + setListShown(false); } + subscription = Observable.defer(() -> Observable.just(performSearch())) + .subscribeOn(Schedulers.newThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + if (result != null) { + itemsLoaded = true; + searchResults = result; + if (viewCreated) { + onFragmentLoaded(); + } + } + }, error -> { + Log.e(TAG, Log.getStackTraceString(error)); + }); } - private class SearchTask extends AsyncTask<Bundle, Void, List<SearchResult>> { - @Override - protected List<SearchResult> doInBackground(Bundle... params) { - String query = params[0].getString(ARG_QUERY); - long feed = params[0].getLong(ARG_FEED); - Context context = getActivity(); - if (context != null) { - return FeedSearcher.performSearch(context, query, feed); - } else { - return Collections.emptyList(); - } - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (viewCreated && !itemsLoaded) { - setListShown(false); - } - } - - @Override - protected void onPostExecute(List<SearchResult> results) { - super.onPostExecute(results); - if (results != null) { - itemsLoaded = true; - searchResults = results; - if (viewCreated) { - onFragmentLoaded(); - } - } - } + private List<SearchResult> performSearch() { + Bundle args = getArguments(); + String query = args.getString(ARG_QUERY); + long feed = args.getLong(ARG_FEED); + Context context = getActivity(); + return FeedSearcher.performSearch(context, query, feed); } + } diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java index 3c9bf464c..1630898ec 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -460,6 +460,13 @@ public class PreferenceController { ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY) .setEnabled(UserPreferences.isEnableAutodownload()); + + if (Build.VERSION.SDK_INT >= 16) { + ui.findPreference(UserPreferences.PREF_SONIC).setEnabled(true); + } else { + Preference prefSonic = ui.findPreference(UserPreferences.PREF_SONIC); + prefSonic.setSummary("[Android 4.1+]\n" + prefSonic.getSummary()); + } } private void setParallelDownloadsText(int downloads) { diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index c9be65f2b..af20eddfd 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -223,7 +223,15 @@ <Preference android:key="prefAbout" android:title="@string/about_pref"/> + </PreferenceCategory> + <PreferenceCategory android:title="@string/experimental_pref"> + <CheckBoxPreference + android:defaultValue="false" + android:enabled="false" + android:key="prefSonic" + android:summary="@string/pref_sonic_message" + android:title="@string/pref_sonic_title"/> </PreferenceCategory> </PreferenceScreen> diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html index 3f26c2366..6ed5fc41d 100644 --- a/app/src/main/templates/about.html +++ b/app/src/main/templates/about.html @@ -59,8 +59,7 @@ <h1>Used libraries</h1> <h2>Apache Commons <a href="http://commons.apache.org/">(Link)</a></h2> -by The Apache Software Foundation, licensed under the Apache 2.0 license <a - href="LICENSE_APACHE_COMMONS.txt">(View)</a> +by The Apache Software Foundation, licensed under the Apache 2.0 license <a href="LICENSE_APACHE_COMMONS.txt">(View)</a> <h2>DragSortListView <a href="https://github.com/bauerca/drag-sort-listview">(Link)</a></h2> by Carl Bauer, licensed under the Apache 2.0 license <a href="LICENSE_DSLV.txt">(View)</a> @@ -101,5 +100,8 @@ licensed under the Apache 2.0 license <a href="LICENSE_RX_ANDROID.txt">(View)</a <h2>StackBlur <a href="https://github.com/kikoso/android-stackblur">(Link)</a></h2> by Enrique López Mañas, licensed under the Apache 2.0 license <a href="LICENSE_STACKBLUR.txt">(View)</a> +<h2>AntennaPod-AudioPlayer <a href="https://github.com/AntennaPod/AntennaPod-AudioPlayer/">(Link)</a></h2> +by the AntennaPod team, licensed under the Apache 2.0 license <a href="LICENSE_ANTENNAPOD_AUDIOPLAYER.txt">(View)</a> + </body> </html> diff --git a/core/build.gradle b/core/build.gradle index 4b1ab98a6..85891b999 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -32,8 +32,12 @@ android { } +repositories { + maven { url "https://jitpack.io" } + mavenCentral() +} + dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:support-v4:22.2.1' compile 'com.android.support:appcompat-v7:22.2.1' compile 'com.android.support:design:22.2.1' @@ -52,4 +56,6 @@ dependencies { compile 'com.nineoldandroids:library:2.4.0' compile 'de.greenrobot:eventbus:2.4.0' compile 'io.reactivex:rxandroid:1.0.1' + + compile 'com.github.AntennaPod:AntennaPod-AudioPlayer:v1.0' } diff --git a/core/src/main/aidl/com/aocate/presto/service/IDeathCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IDeathCallback_0_8.aidl deleted file mode 100644 index 6bdc76801..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IDeathCallback_0_8.aidl +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -oneway interface IDeathCallback_0_8 { -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl deleted file mode 100644 index 7357e402e..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnBufferingUpdateListenerCallback_0_8 { - void onBufferingUpdate(int percent); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl deleted file mode 100644 index d5edea729..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnCompletionListenerCallback_0_8 { - void onCompletion(); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl deleted file mode 100644 index 2c4f2df3e..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnErrorListenerCallback_0_8 { - boolean onError(int what, int extra); -} diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl deleted file mode 100644 index 9dbd1d260..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnInfoListenerCallback_0_8 { - boolean onInfo(int what, int extra); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl deleted file mode 100644 index 41223a97b..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 { - void onPitchAdjustmentAvailableChanged(boolean pitchAdjustmentAvailable); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl deleted file mode 100644 index 7be8f1237..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnPreparedListenerCallback_0_8 { - void onPrepared(); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl deleted file mode 100644 index 5bdda98b6..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnSeekCompleteListenerCallback_0_8 { - void onSeekComplete(); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl deleted file mode 100644 index a69c1cf34..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -interface IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 { - void onSpeedAdjustmentAvailableChanged(boolean speedAdjustmentAvailable); -}
\ No newline at end of file diff --git a/core/src/main/aidl/com/aocate/presto/service/IPlayMedia_0_8.aidl b/core/src/main/aidl/com/aocate/presto/service/IPlayMedia_0_8.aidl deleted file mode 100644 index 12a6047de..000000000 --- a/core/src/main/aidl/com/aocate/presto/service/IPlayMedia_0_8.aidl +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.presto.service; - -import com.aocate.presto.service.IDeathCallback_0_8; -import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8; -import com.aocate.presto.service.IOnCompletionListenerCallback_0_8; -import com.aocate.presto.service.IOnErrorListenerCallback_0_8; -import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8; -import com.aocate.presto.service.IOnPreparedListenerCallback_0_8; -import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8; -import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8; -import com.aocate.presto.service.IOnInfoListenerCallback_0_8; - -interface IPlayMedia_0_8 { - boolean canSetPitch(long sessionId); - boolean canSetSpeed(long sessionId); - float getCurrentPitchStepsAdjustment(long sessionId); - int getCurrentPosition(long sessionId); - float getCurrentSpeedMultiplier(long sessionId); - int getDuration(long sessionId); - float getMaxSpeedMultiplier(long sessionId); - float getMinSpeedMultiplier(long sessionId); - int getVersionCode(); - String getVersionName(); - boolean isLooping(long sessionId); - boolean isPlaying(long sessionId); - void pause(long sessionId); - void prepare(long sessionId); - void prepareAsync(long sessionId); - void registerOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb); - void registerOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb); - void registerOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb); - void registerOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb); - void registerOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb); - void registerOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb); - void registerOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb); - void registerOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb); - void release(long sessionId); - void reset(long sessionId); - void seekTo(long sessionId, int msec); - void setAudioStreamType(long sessionId, int streamtype); - void setDataSourceString(long sessionId, String path); - void setDataSourceUri(long sessionId, in Uri uri); - void setEnableSpeedAdjustment(long sessionId, boolean enableSpeedAdjustment); - void setLooping(long sessionId, boolean looping); - void setPitchStepsAdjustment(long sessionId, float pitchSteps); - void setPlaybackPitch(long sessionId, float f); - void setPlaybackSpeed(long sessionId, float f); - void setSpeedAdjustmentAlgorithm(long sessionId, int algorithm); - void setVolume(long sessionId, float left, float right); - void start(long sessionId); - long startSession(IDeathCallback_0_8 cb); - void stop(long sessionId); - void unregisterOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb); - void unregisterOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb); - void unregisterOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb); - void unregisterOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb); - void unregisterOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb); - void unregisterOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb); - void unregisterOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb); - void unregisterOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb); -}
\ No newline at end of file diff --git a/core/src/main/java/com/aocate/media/AndroidMediaPlayer.java b/core/src/main/java/com/aocate/media/AndroidMediaPlayer.java deleted file mode 100644 index 7c2ea3d61..000000000 --- a/core/src/main/java/com/aocate/media/AndroidMediaPlayer.java +++ /dev/null @@ -1,470 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.media; - -import android.content.Context; -import android.media.MediaPlayer; -import android.net.Uri; -import android.util.Log; - -import java.io.IOException; - -public class AndroidMediaPlayer extends MediaPlayerImpl { - private final static String AMP_TAG = "AocateAndroidMediaPlayer"; - - // private static final long TIMEOUT_DURATION_MS = 500; - - android.media.MediaPlayer mp = null; - - private android.media.MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() { - public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) { - if (owningMediaPlayer != null) { - owningMediaPlayer.lock.lock(); - try { - if ((owningMediaPlayer.onBufferingUpdateListener != null) - && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) { - owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - } - }; - - private android.media.MediaPlayer.OnCompletionListener onCompletionListener = new android.media.MediaPlayer.OnCompletionListener() { - public void onCompletion(android.media.MediaPlayer mp) { - Log.d(AMP_TAG, "onCompletionListener being called"); - if (owningMediaPlayer != null) { - owningMediaPlayer.lock.lock(); - try { - if (owningMediaPlayer.onCompletionListener != null) { - owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - } - }; - - private android.media.MediaPlayer.OnErrorListener onErrorListener = new android.media.MediaPlayer.OnErrorListener() { - public boolean onError(android.media.MediaPlayer mp, int what, int extra) { - // Once we're in errored state, any received messages are going to be junked - if (owningMediaPlayer != null) { - owningMediaPlayer.lock.lock(); - try { - if (owningMediaPlayer.onErrorListener != null) { - return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - return false; - } - }; - - private android.media.MediaPlayer.OnInfoListener onInfoListener = new android.media.MediaPlayer.OnInfoListener() { - public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) { - if (owningMediaPlayer != null) { - owningMediaPlayer.lock.lock(); - try { - if ((owningMediaPlayer.onInfoListener != null) - && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) { - return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - return false; - } - }; - - // We have to assign this.onPreparedListener because the - // onPreparedListener in owningMediaPlayer sets the state - // to PREPARED. Due to prepareAsync, that's the only - // reasonable place to do it - // The others it just didn't make sense to have a setOnXListener that didn't use the parameter - private android.media.MediaPlayer.OnPreparedListener onPreparedListener = new android.media.MediaPlayer.OnPreparedListener() { - public void onPrepared(android.media.MediaPlayer mp) { - Log.d(AMP_TAG, "Calling onPreparedListener.onPrepared()"); - if (AndroidMediaPlayer.this.owningMediaPlayer != null) { - AndroidMediaPlayer.this.lockMuteOnPreparedCount.lock(); - try { - if (AndroidMediaPlayer.this.muteOnPreparedCount > 0) { - AndroidMediaPlayer.this.muteOnPreparedCount--; - } - else { - AndroidMediaPlayer.this.muteOnPreparedCount = 0; - if (AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) { - Log.d(AMP_TAG, "Invoking AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared"); - AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared(AndroidMediaPlayer.this.owningMediaPlayer); - } - } - } - finally { - AndroidMediaPlayer.this.lockMuteOnPreparedCount.unlock(); - } - if (owningMediaPlayer.mpi != AndroidMediaPlayer.this) { - Log.d(AMP_TAG, "owningMediaPlayer has changed implementation"); - } - } - } - }; - - private android.media.MediaPlayer.OnSeekCompleteListener onSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() { - public void onSeekComplete(android.media.MediaPlayer mp) { - if (owningMediaPlayer != null) { - owningMediaPlayer.lock.lock(); - try { - lockMuteOnSeekCount.lock(); - try { - if (AndroidMediaPlayer.this.muteOnSeekCount > 0) { - AndroidMediaPlayer.this.muteOnSeekCount--; - } - else { - AndroidMediaPlayer.this.muteOnSeekCount = 0; - if (AndroidMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) { - owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer); - } - } - } - finally { - lockMuteOnSeekCount.unlock(); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - } - }; - - public AndroidMediaPlayer(com.aocate.media.MediaPlayer owningMediaPlayer, Context context) { - super(owningMediaPlayer, context); - - mp = new MediaPlayer(); - -// final ReentrantLock lock = new ReentrantLock(); -// Handler handler = new Handler(Looper.getMainLooper()) { -// @Override -// public void handleMessage(Message msg) { -// Log.d(AMP_TAG, "Instantiating new AndroidMediaPlayer from Handler"); -// lock.lock(); -// if (mp == null) { -// mp = new MediaPlayer(); -// } -// lock.unlock(); -// } -// }; -// -// long endTime = System.currentTimeMillis() + TIMEOUT_DURATION_MS; -// -// while (true) { -// // Retry messages until mp isn't null or it's time to give up -// handler.sendMessage(handler.obtainMessage()); -// if ((mp != null) -// || (endTime < System.currentTimeMillis())) { -// break; -// } -// try { -// Thread.sleep(50); -// } catch (InterruptedException e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } -// } - - if (mp == null) { - throw new IllegalStateException("Did not instantiate android.media.MediaPlayer successfully"); - } - - mp.setOnBufferingUpdateListener(this.onBufferingUpdateListener); - mp.setOnCompletionListener(this.onCompletionListener); - mp.setOnErrorListener(this.onErrorListener); - mp.setOnInfoListener(this.onInfoListener); - Log.d(AMP_TAG, " ++++++++++++++++++++++++++++++++ Setting prepared listener to this.onPreparedListener"); - mp.setOnPreparedListener(this.onPreparedListener); - mp.setOnSeekCompleteListener(this.onSeekCompleteListener); - } - - @Override - public boolean canSetPitch() { - return false; - } - - @Override - public boolean canSetSpeed() { - return false; - } - - @Override - public float getCurrentPitchStepsAdjustment() { - return 0; - } - - @Override - public int getCurrentPosition() { - owningMediaPlayer.lock.lock(); - try { - return mp.getCurrentPosition(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public float getCurrentSpeedMultiplier() { - return 1f; - } - - @Override - public int getDuration() { - owningMediaPlayer.lock.lock(); - try { - return mp.getDuration(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public float getMaxSpeedMultiplier() { - return 1f; - } - - @Override - public float getMinSpeedMultiplier() { - return 1f; - } - - @Override - public boolean isLooping() { - owningMediaPlayer.lock.lock(); - try { - return mp.isLooping(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public boolean isPlaying() { - owningMediaPlayer.lock.lock(); - try { - return mp.isPlaying(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void pause() { - owningMediaPlayer.lock.lock(); - try { - mp.pause(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void prepare() throws IllegalStateException, IOException { - owningMediaPlayer.lock.lock(); - Log.d(AMP_TAG, "prepare()"); - try { - mp.prepare(); - Log.d(AMP_TAG, "Finish prepare()"); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void prepareAsync() { - mp.prepareAsync(); - } - - @Override - public void release() { - owningMediaPlayer.lock.lock(); - try { - if (mp != null) { - Log.d(AMP_TAG, "mp.release()"); - mp.release(); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void reset() { - owningMediaPlayer.lock.lock(); - try { - mp.reset(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void seekTo(int msec) throws IllegalStateException { - owningMediaPlayer.lock.lock(); - try { - mp.setOnSeekCompleteListener(this.onSeekCompleteListener); - mp.seekTo(msec); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setAudioStreamType(int streamtype) { - owningMediaPlayer.lock.lock(); - try { - mp.setAudioStreamType(streamtype); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setDataSource(Context context, Uri uri) - throws IllegalArgumentException, IllegalStateException, IOException { - owningMediaPlayer.lock.lock(); - try { - Log.d(AMP_TAG, "setDataSource(context, " + uri.toString() + ")"); - mp.setDataSource(context, uri); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setDataSource(String path) throws IllegalArgumentException, - IllegalStateException, IOException { - owningMediaPlayer.lock.lock(); - try { - Log.d(AMP_TAG, "setDataSource(" + path + ")"); - mp.setDataSource(path); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { - // Can't! - } - - @Override - public void setLooping(boolean loop) { - owningMediaPlayer.lock.lock(); - try { - mp.setLooping(loop); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setPitchStepsAdjustment(float pitchSteps) { - // Can't! - } - - @Override - public void setPlaybackPitch(float f) { - // Can't! - } - - @Override - public void setPlaybackSpeed(float f) { - // Can't! - Log.d(AMP_TAG, "setPlaybackSpeed(" + f + ")"); - } - - @Override - public void setSpeedAdjustmentAlgorithm(int algorithm) { - // Can't! - Log.d(AMP_TAG, "setSpeedAdjustmentAlgorithm(" + algorithm + ")"); - } - - @Override - public void setVolume(float leftVolume, float rightVolume) { - owningMediaPlayer.lock.lock(); - try { - mp.setVolume(leftVolume, rightVolume); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void setWakeMode(Context context, int mode) { - owningMediaPlayer.lock.lock(); - try { - if (mode != 0) { - mp.setWakeMode(context, mode); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void start() { - owningMediaPlayer.lock.lock(); - try { - mp.start(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - @Override - public void stop() { - owningMediaPlayer.lock.lock(); - try { - mp.stop(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } -} diff --git a/core/src/main/java/com/aocate/media/MediaPlayer.java b/core/src/main/java/com/aocate/media/MediaPlayer.java deleted file mode 100644 index 79e63d03d..000000000 --- a/core/src/main/java/com/aocate/media/MediaPlayer.java +++ /dev/null @@ -1,1310 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.media; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.IBinder; -import android.os.Message; -import android.util.Log; - -import java.io.IOException; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -import de.danoeh.antennapod.core.BuildConfig; - -public class MediaPlayer { - public static final String TAG = "com.aocate.media.MediaPlayer"; - - public interface OnBufferingUpdateListener { - public abstract void onBufferingUpdate(MediaPlayer arg0, int percent); - } - - public interface OnCompletionListener { - public abstract void onCompletion(MediaPlayer arg0); - } - - public interface OnErrorListener { - public abstract boolean onError(MediaPlayer arg0, int what, int extra); - } - - public interface OnInfoListener { - public abstract boolean onInfo(MediaPlayer arg0, int what, int extra); - } - - public interface OnPitchAdjustmentAvailableChangedListener { - /** - * @param arg0 The owning media player - * @param pitchAdjustmentAvailable True if pitch adjustment is available, false if not - */ - public abstract void onPitchAdjustmentAvailableChanged( - MediaPlayer arg0, boolean pitchAdjustmentAvailable); - } - - public interface OnPreparedListener { - public abstract void onPrepared(MediaPlayer arg0); - } - - public interface OnSeekCompleteListener { - public abstract void onSeekComplete(MediaPlayer arg0); - } - - public interface OnSpeedAdjustmentAvailableChangedListener { - /** - * @param arg0 The owning media player - * @param speedAdjustmentAvailable True if speed adjustment is available, false if not - */ - public abstract void onSpeedAdjustmentAvailableChanged( - MediaPlayer arg0, boolean speedAdjustmentAvailable); - } - - public enum State { - IDLE, INITIALIZED, PREPARED, STARTED, PAUSED, STOPPED, PREPARING, PLAYBACK_COMPLETED, END, ERROR - } - - private static Uri SPEED_ADJUSTMENT_MARKET_URI = Uri - .parse("market://details?id=com.aocate.presto"); - - private static Intent prestoMarketIntent = null; - - public static final int MEDIA_ERROR_SERVER_DIED = android.media.MediaPlayer.MEDIA_ERROR_SERVER_DIED; - public static final int MEDIA_ERROR_UNKNOWN = android.media.MediaPlayer.MEDIA_ERROR_UNKNOWN; - public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = android.media.MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK; - - /** - * Indicates whether the specified action can be used as an intent. This - * method queries the package manager for installed packages that can - * respond to an intent with the specified action. If no suitable package is - * found, this method returns false. - * - * @param context The application's environment. - * @param action The Intent action to check for availability. - * @return True if an Intent with the specified action can be sent and - * responded to, false otherwise. - */ - public static boolean isIntentAvailable(Context context, String action) { - final PackageManager packageManager = context.getPackageManager(); - final Intent intent = new Intent(action); - List<ResolveInfo> list = packageManager.queryIntentServices(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return list.size() > 0; - } - - /** - * Returns an explicit Intent for a service that accepts the given Intent - * or null if no such service was found. - * - * @param context The application's environment. - * @param action The Intent action to check for availability. - * @return The explicit service Intent or null if no service was found. - */ - public static Intent getPrestoServiceIntent(Context context, String action) { - final PackageManager packageManager = context.getPackageManager(); - final Intent actionIntent = new Intent(action); - List<ResolveInfo> list = packageManager.queryIntentServices(actionIntent, - PackageManager.MATCH_DEFAULT_ONLY); - if (list.size() > 0) { - ResolveInfo first = list.get(0); - if (first.serviceInfo != null) { - Intent intent = new Intent(); - intent.setComponent(new ComponentName(first.serviceInfo.packageName, - first.serviceInfo.name)); - Log.i(TAG, "Returning intent:" + intent.toString()); - return intent; - } else { - Log.e(TAG, "Found service that accepts " + action + ", but serviceInfo was null"); - return null; - } - } else { - return null; - } - } - - /** - * Indicates whether the Presto library is installed - * - * @param context The context to use to query the package manager. - * @return True if the Presto library is installed, false if not. - */ - public static boolean isPrestoLibraryInstalled(Context context) { - return isIntentAvailable(context, ServiceBackedMediaPlayer.INTENT_NAME); - } - - /** - * Return an Intent that opens the Android Market page for the speed - * alteration library - * - * @return The Intent for the Presto library on the Android Market - */ - public static Intent getPrestoMarketIntent() { - if (prestoMarketIntent == null) { - prestoMarketIntent = new Intent(Intent.ACTION_VIEW, - SPEED_ADJUSTMENT_MARKET_URI); - } - return prestoMarketIntent; - } - - /** - * Open the Android Market page for the Presto library - * - * @param context The context from which to open the Android Market page - */ - public static void openPrestoMarketIntent(Context context) { - context.startActivity(getPrestoMarketIntent()); - } - - private static final String MP_TAG = "AocateReplacementMediaPlayer"; - - private static final double PITCH_STEP_CONSTANT = 1.0594630943593; - - private AndroidMediaPlayer amp = null; - // This is whether speed adjustment should be enabled (by the Service) - // To avoid the Service entirely, set useService to false - protected boolean enableSpeedAdjustment = true; - private int lastKnownPosition = 0; - // In some cases, we're going to have to replace the - // android.media.MediaPlayer on the fly, and we don't want to touch the - // wrong media player, so lock it way too much. - ReentrantLock lock = new ReentrantLock(); - private int mAudioStreamType = AudioManager.STREAM_MUSIC; - private Context mContext; - private boolean mIsLooping = false; - private float mLeftVolume = 1f; - private float mPitchStepsAdjustment = 0f; - private float mRightVolume = 1f; - private float mSpeedMultiplier = 1f; - private int mWakeMode = 0; - MediaPlayerImpl mpi = null; - protected boolean pitchAdjustmentAvailable = false; - private ServiceBackedMediaPlayer sbmp = null; - protected boolean speedAdjustmentAvailable = false; - - private Handler mServiceDisconnectedHandler = null; - - // Some parts of state cannot be found by calling MediaPlayerImpl functions, - // so store our own state. This also helps copy state when changing - // implementations - State state = State.INITIALIZED; - String stringDataSource = null; - Uri uriDataSource = null; - private boolean useService = false; - - // Naming Convention for Listeners - // Most listeners can both be set by clients and called by MediaPlayImpls - // There are a few that have to do things in this class as well as calling - // the function. In all cases, onX is what is called by MediaPlayerImpl - // If there is work to be done in this class, then the listener that is - // set by setX is X (with the first letter lowercase). - OnBufferingUpdateListener onBufferingUpdateListener = null; - OnCompletionListener onCompletionListener = null; - OnErrorListener onErrorListener = null; - OnInfoListener onInfoListener = null; - - // Special case. Pitch adjustment ceases to be available when we switch - // to the android.media.MediaPlayer (though it is not guaranteed to be - // available when using the ServiceBackedMediaPlayer) - OnPitchAdjustmentAvailableChangedListener onPitchAdjustmentAvailableChangedListener = new OnPitchAdjustmentAvailableChangedListener() { - public void onPitchAdjustmentAvailableChanged(MediaPlayer arg0, - boolean pitchAdjustmentAvailable) { - lock.lock(); - try { - Log - .d( - MP_TAG, - "onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged being called"); - if (MediaPlayer.this.pitchAdjustmentAvailable != pitchAdjustmentAvailable) { - Log.d(MP_TAG, "Pitch adjustment state has changed from " - + MediaPlayer.this.pitchAdjustmentAvailable - + " to " + pitchAdjustmentAvailable); - MediaPlayer.this.pitchAdjustmentAvailable = pitchAdjustmentAvailable; - if (MediaPlayer.this.pitchAdjustmentAvailableChangedListener != null) { - MediaPlayer.this.pitchAdjustmentAvailableChangedListener - .onPitchAdjustmentAvailableChanged(arg0, - pitchAdjustmentAvailable); - } - } - } finally { - lock.unlock(); - } - } - }; - OnPitchAdjustmentAvailableChangedListener pitchAdjustmentAvailableChangedListener = null; - - MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener() { - public void onPrepared(MediaPlayer arg0) { - Log.d(MP_TAG, "onPreparedListener 242 setting state to PREPARED"); - MediaPlayer.this.state = State.PREPARED; - if (MediaPlayer.this.preparedListener != null) { - Log.d(MP_TAG, "Calling preparedListener"); - MediaPlayer.this.preparedListener.onPrepared(arg0); - } - Log.d(MP_TAG, "Wrap up onPreparedListener"); - } - }; - - OnPreparedListener preparedListener = null; - OnSeekCompleteListener onSeekCompleteListener = null; - - // Special case. Speed adjustment ceases to be available when we switch - // to the android.media.MediaPlayer (though it is not guaranteed to be - // available when using the ServiceBackedMediaPlayer) - OnSpeedAdjustmentAvailableChangedListener onSpeedAdjustmentAvailableChangedListener = new OnSpeedAdjustmentAvailableChangedListener() { - public void onSpeedAdjustmentAvailableChanged(MediaPlayer arg0, - boolean speedAdjustmentAvailable) { - lock.lock(); - try { - Log - .d( - MP_TAG, - "onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged being called"); - if (MediaPlayer.this.speedAdjustmentAvailable != speedAdjustmentAvailable) { - Log.d(MP_TAG, "Speed adjustment state has changed from " - + MediaPlayer.this.speedAdjustmentAvailable - + " to " + speedAdjustmentAvailable); - MediaPlayer.this.speedAdjustmentAvailable = speedAdjustmentAvailable; - if (MediaPlayer.this.speedAdjustmentAvailableChangedListener != null) { - MediaPlayer.this.speedAdjustmentAvailableChangedListener - .onSpeedAdjustmentAvailableChanged(arg0, - speedAdjustmentAvailable); - } - } - } finally { - lock.unlock(); - } - } - }; - OnSpeedAdjustmentAvailableChangedListener speedAdjustmentAvailableChangedListener = null; - - private int speedAdjustmentAlgorithm = SpeedAdjustmentAlgorithm.SONIC; - - public MediaPlayer(final Context context) { - this(context, true); - } - - public MediaPlayer(final Context context, boolean useService) { - this.mContext = context; - this.useService = useService; - - // So here's the major problem - // Sometimes the service won't exist or won't be connected, - // so start with an android.media.MediaPlayer, and when - // the service is connected, use that from then on - this.mpi = this.amp = new AndroidMediaPlayer(this, context); - - // setupMpi will go get the Service, if it can, then bring that - // implementation into sync - Log.d(MP_TAG, "setupMpi"); - setupMpi(context); - } - - private boolean invalidServiceConnectionConfiguration() { - if (!(this.mpi instanceof ServiceBackedMediaPlayer)) { - if (this.useService && isPrestoLibraryInstalled()) { - // In this case, the Presto library has been installed - // or something while playing sound - // We could be using the service, but we're not - Log.d(MP_TAG, "We could be using the service, but we're not 316"); - return true; - } - // If useService is false, then we shouldn't be using the SBMP - // If the Presto library isn't installed, ditto - Log.d(MP_TAG, "this.mpi is not a ServiceBackedMediaPlayer, but we couldn't use it anyway 321"); - return false; - } else { - if (BuildConfig.DEBUG && !(this.mpi instanceof ServiceBackedMediaPlayer)) - throw new AssertionError(); - if (this.useService && isPrestoLibraryInstalled()) { - // We should be using the service, and we are. Great! - Log.d(MP_TAG, "We could be using a ServiceBackedMediaPlayer and we are 327"); - return false; - } - // We're trying to use the service when we shouldn't, - // that's an invalid configuration - Log.d(MP_TAG, "We're trying to use a ServiceBackedMediaPlayer but we shouldn't be 332"); - return true; - } - } - - private void setupMpi(final Context context) { - lock.lock(); - try { - Log.d(MP_TAG, "setupMpi 336"); - // Check if the client wants to use the service at all, - // then if we're already using the right kind of media player - if (this.useService && isPrestoLibraryInstalled()) { - if ((this.mpi != null) - && (this.mpi instanceof ServiceBackedMediaPlayer)) { - Log.d(MP_TAG, "Already using ServiceBackedMediaPlayer"); - return; - } - if (this.sbmp == null) { - Log.d(MP_TAG, "Instantiating new ServiceBackedMediaPlayer 346"); - this.sbmp = new ServiceBackedMediaPlayer(this, context, - new ServiceConnection() { - public void onServiceConnected( - ComponentName className, - final IBinder service) { - Thread t = new Thread(new Runnable() { - public void run() { - // This lock probably isn't granular - // enough - MediaPlayer.this.lock.lock(); - Log.d(MP_TAG, - "onServiceConnected 257"); - try { - MediaPlayer.this - .switchMediaPlayerImpl( - MediaPlayer.this.amp, - MediaPlayer.this.sbmp); - Log.d(MP_TAG, "End onServiceConnected 362"); - } finally { - MediaPlayer.this.lock.unlock(); - } - } - }); - t.start(); - } - - public void onServiceDisconnected( - ComponentName className) { - MediaPlayer.this.lock.lock(); - try { - // Can't get any more useful information - // out of sbmp - if (MediaPlayer.this.sbmp != null) { - MediaPlayer.this.sbmp.release(); - } - // Unlike most other cases, sbmp gets set - // to null since there's nothing useful - // backing it now - MediaPlayer.this.sbmp = null; - - if (mServiceDisconnectedHandler == null) { - mServiceDisconnectedHandler = new Handler(new Callback() { - public boolean handleMessage(Message msg) { - // switchMediaPlayerImpl won't try to - // clone anything from null - lock.lock(); - try { - if (MediaPlayer.this.amp == null) { - // This should never be in this state - MediaPlayer.this.amp = new AndroidMediaPlayer( - MediaPlayer.this, - MediaPlayer.this.mContext); - } - // Use sbmp instead of null in case by some miracle it's - // been restored in the meantime - MediaPlayer.this.switchMediaPlayerImpl( - MediaPlayer.this.sbmp, - MediaPlayer.this.amp); - return true; - } finally { - lock.unlock(); - } - } - }); - } - - // This code needs to execute on the - // original thread to instantiate - // the new object in the right place - mServiceDisconnectedHandler - .sendMessage( - mServiceDisconnectedHandler - .obtainMessage()); - // Note that we do NOT want to set - // useService. useService is about - // what the user wants, not what they - // get - } finally { - MediaPlayer.this.lock.unlock(); - } - } - } - ); - } - switchMediaPlayerImpl(this.amp, this.sbmp); - } else { - if ((this.mpi != null) - && (this.mpi instanceof AndroidMediaPlayer)) { - Log.d(MP_TAG, "Already using AndroidMediaPlayer"); - return; - } - if (this.amp == null) { - Log.d(MP_TAG, "Instantiating new AndroidMediaPlayer (this should be impossible)"); - this.amp = new AndroidMediaPlayer(this, context); - } - switchMediaPlayerImpl(this.sbmp, this.amp); - } - } finally { - lock.unlock(); - } - } - - private void switchMediaPlayerImpl(MediaPlayerImpl from, MediaPlayerImpl to) { - lock.lock(); - try { - Log.d(MP_TAG, "switchMediaPlayerImpl"); - if ((from == to) - // Same object, nothing to synchronize - || (to == null) - // Nothing to copy to (maybe this should throw an error?) - || ((to instanceof ServiceBackedMediaPlayer) && !((ServiceBackedMediaPlayer) to).isConnected()) - // ServiceBackedMediaPlayer hasn't yet connected, onServiceConnected will take care of the transition - || (MediaPlayer.this.state == State.END)) { - // State.END is after a release(), no further functions should - // be called on this class and from is likely to have problems - // retrieving state that won't be used anyway - return; - } - // Extract all that we can from the existing implementation - // and copy it to the new implementation - - Log.d(MP_TAG, "switchMediaPlayerImpl(), current state is " - + this.state.toString()); - - to.reset(); - - // Do this first so we don't have to prepare the same - // data file twice - to.setEnableSpeedAdjustment(MediaPlayer.this.enableSpeedAdjustment); - - // This is a reasonable place to set all of these, - // none of them require prepare() or the like first - to.setAudioStreamType(this.mAudioStreamType); - to.setSpeedAdjustmentAlgorithm(this.speedAdjustmentAlgorithm); - to.setLooping(this.mIsLooping); - to.setPitchStepsAdjustment(this.mPitchStepsAdjustment); - Log.d(MP_TAG, "Setting playback speed to " + this.mSpeedMultiplier); - to.setPlaybackSpeed(this.mSpeedMultiplier); - to.setVolume(MediaPlayer.this.mLeftVolume, - MediaPlayer.this.mRightVolume); - to.setWakeMode(this.mContext, this.mWakeMode); - - Log.d(MP_TAG, "asserting at least one data source is null"); - assert ((MediaPlayer.this.stringDataSource == null) || (MediaPlayer.this.uriDataSource == null)); - - if (uriDataSource != null) { - Log.d(MP_TAG, "switchMediaPlayerImpl(): uriDataSource != null"); - try { - to.setDataSource(this.mContext, uriDataSource); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalStateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - if (stringDataSource != null) { - Log.d(MP_TAG, - "switchMediaPlayerImpl(): stringDataSource != null"); - try { - to.setDataSource(stringDataSource); - } catch (IllegalArgumentException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalStateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - if ((this.state == State.PREPARED) - || (this.state == State.PREPARING) - || (this.state == State.PAUSED) - || (this.state == State.STOPPED) - || (this.state == State.STARTED) - || (this.state == State.PLAYBACK_COMPLETED)) { - Log.d(MP_TAG, "switchMediaPlayerImpl(): prepare and seek"); - // Use prepare here instead of prepareAsync so that - // we wait for it to be ready before we try to use it - try { - to.muteNextOnPrepare(); - to.prepare(); - } catch (IllegalStateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - int seekPos = 0; - if (from != null) { - seekPos = from.getCurrentPosition(); - } else if (this.lastKnownPosition < to.getDuration()) { - // This can happen if the Service unexpectedly - // disconnected. Because it would result in too much - // information being passed around, we don't constantly - // poll for the lastKnownPosition, but we'll save it - // when getCurrentPosition is called - seekPos = this.lastKnownPosition; - } - to.muteNextSeek(); - to.seekTo(seekPos); - } - if ((from != null) - && from.isPlaying()) { - from.pause(); - } - if ((this.state == State.STARTED) - || (this.state == State.PAUSED) - || (this.state == State.STOPPED)) { - Log.d(MP_TAG, "switchMediaPlayerImpl(): start"); - if (to != null) { - to.start(); - } - } - - if (this.state == State.PAUSED) { - Log.d(MP_TAG, "switchMediaPlayerImpl(): paused"); - if (to != null) { - to.pause(); - } - } else if (this.state == State.STOPPED) { - Log.d(MP_TAG, "switchMediaPlayerImpl(): stopped"); - if (to != null) { - to.stop(); - } - } - - this.mpi = to; - - // Cheating here by relying on the side effect in - // on(Pitch|Speed)AdjustmentAvailableChanged - if ((to.canSetPitch() != this.pitchAdjustmentAvailable) - && (this.onPitchAdjustmentAvailableChangedListener != null)) { - this.onPitchAdjustmentAvailableChangedListener - .onPitchAdjustmentAvailableChanged(this, to - .canSetPitch()); - } - if ((to.canSetSpeed() != this.speedAdjustmentAvailable) - && (this.onSpeedAdjustmentAvailableChangedListener != null)) { - this.onSpeedAdjustmentAvailableChangedListener - .onSpeedAdjustmentAvailableChanged(this, to - .canSetSpeed()); - } - Log.d(MP_TAG, "switchMediaPlayerImpl() 625 " + this.state.toString()); - } finally { - lock.unlock(); - } - } - - /** - * Returns true if pitch can be changed at this moment - * - * @return True if pitch can be changed - */ - public boolean canSetPitch() { - lock.lock(); - try { - return this.mpi.canSetPitch(); - } finally { - lock.unlock(); - } - } - - /** - * Returns true if speed can be changed at this moment - * - * @return True if speed can be changed - */ - public boolean canSetSpeed() { - lock.lock(); - try { - return this.mpi.canSetSpeed(); - } finally { - lock.unlock(); - } - } - - protected void finalize() throws Throwable { - lock.lock(); - try { - Log.d(MP_TAG, "finalize() 626"); - this.release(); - } finally { - lock.unlock(); - } - } - - /** - * Returns the number of steps (in a musical scale) by which playback is - * currently shifted. When greater than zero, pitch is shifted up. When less - * than zero, pitch is shifted down. - * - * @return The number of steps pitch is currently shifted by - */ - public float getCurrentPitchStepsAdjustment() { - lock.lock(); - try { - return this.mpi.getCurrentPitchStepsAdjustment(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.getCurrentPosition() - * Accurate only to frame size of encoded data (26 ms for MP3s) - * - * @return Current position (in milliseconds) - */ - public int getCurrentPosition() { - lock.lock(); - try { - return (this.lastKnownPosition = this.mpi.getCurrentPosition()); - } finally { - lock.unlock(); - } - } - - /** - * Returns the current speed multiplier. Defaults to 1.0 (normal speed) - * - * @return The current speed multiplier - */ - public float getCurrentSpeedMultiplier() { - lock.lock(); - try { - return this.mpi.getCurrentSpeedMultiplier(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.getDuration() - * - * @return Length of the track (in milliseconds) - */ - public int getDuration() { - lock.lock(); - try { - return this.mpi.getDuration(); - } finally { - lock.unlock(); - } - } - - /** - * Get the maximum value that can be passed to setPlaybackSpeed - * - * @return The maximum speed multiplier - */ - public float getMaxSpeedMultiplier() { - lock.lock(); - try { - return this.mpi.getMaxSpeedMultiplier(); - } finally { - lock.unlock(); - } - } - - /** - * Get the minimum value that can be passed to setPlaybackSpeed - * - * @return The minimum speed multiplier - */ - public float getMinSpeedMultiplier() { - lock.lock(); - try { - return this.mpi.getMinSpeedMultiplier(); - } finally { - lock.unlock(); - } - } - - /** - * Gets the version code of the backing service - * - * @return -1 if ServiceBackedMediaPlayer is not used, 0 if the service is not - * connected, otherwise the version code retrieved from the service - */ - public int getServiceVersionCode() { - lock.lock(); - try { - if (this.mpi instanceof ServiceBackedMediaPlayer) { - return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionCode(); - } else { - return -1; - } - } finally { - lock.unlock(); - } - } - - /** - * Gets the version name of the backing service - * - * @return null if ServiceBackedMediaPlayer is not used, empty string if - * the service is not connected, otherwise the version name retrieved from - * the service - */ - public String getServiceVersionName() { - lock.lock(); - try { - if (this.mpi instanceof ServiceBackedMediaPlayer) { - return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionName(); - } else { - return null; - } - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.isLooping() - * - * @return True if the track is looping - */ - public boolean isLooping() { - lock.lock(); - try { - return this.mpi.isLooping(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.isPlaying() - * - * @return True if the track is playing - */ - public boolean isPlaying() { - lock.lock(); - try { - return this.mpi.isPlaying(); - } finally { - lock.unlock(); - } - } - - /** - * Returns true if this MediaPlayer has access to the Presto - * library - * - * @return True if the Presto library is installed - */ - public boolean isPrestoLibraryInstalled() { - if ((this.mpi == null) || (this.mpi.mContext == null)) { - return false; - } - return isPrestoLibraryInstalled(this.mpi.mContext); - } - - /** - * Open the Android Market page in the same context as this MediaPlayer - */ - public void openPrestoMarketIntent() { - if ((this.mpi != null) && (this.mpi.mContext != null)) { - openPrestoMarketIntent(this.mpi.mContext); - } - } - - /** - * Functions identically to android.media.MediaPlayer.pause() Pauses the - * track - */ - public void pause() { - lock.lock(); - try { - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.PAUSED; - this.mpi.pause(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.prepare() Prepares the - * track. This or prepareAsync must be called before start() - */ - public void prepare() throws IllegalStateException, IOException { - lock.lock(); - try { - Log.d(MP_TAG, "prepare() 746 using " + ((this.mpi == null) ? "null (this shouldn't happen)" : this.mpi.getClass().toString()) + " state " + this.state.toString()); - Log.d(MP_TAG, "onPreparedListener is: " + ((this.onPreparedListener == null) ? "null" : "non-null")); - Log.d(MP_TAG, "preparedListener is: " + ((this.preparedListener == null) ? "null" : "non-null")); - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.mpi.prepare(); - this.state = State.PREPARED; - Log.d(MP_TAG, "prepare() finished 778"); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.prepareAsync() - * Prepares the track. This or prepare must be called before start() - */ - public void prepareAsync() { - lock.lock(); - try { - Log.d(MP_TAG, "prepareAsync() 779"); - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.PREPARING; - this.mpi.prepareAsync(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.release() Releases the - * underlying resources used by the media player. - */ - public void release() { - lock.lock(); - try { - Log.d(MP_TAG, "Releasing MediaPlayer 791"); - - this.state = State.END; - if (this.amp != null) { - this.amp.release(); - } - if (this.sbmp != null) { - this.sbmp.release(); - } - - this.onBufferingUpdateListener = null; - this.onCompletionListener = null; - this.onErrorListener = null; - this.onInfoListener = null; - this.preparedListener = null; - this.onPitchAdjustmentAvailableChangedListener = null; - this.pitchAdjustmentAvailableChangedListener = null; - Log.d(MP_TAG, "Setting onSeekCompleteListener to null 871"); - this.onSeekCompleteListener = null; - this.onSpeedAdjustmentAvailableChangedListener = null; - this.speedAdjustmentAvailableChangedListener = null; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.reset() Resets the - * track to idle state - */ - public void reset() { - lock.lock(); - try { - this.state = State.IDLE; - this.stringDataSource = null; - this.uriDataSource = null; - this.mpi.reset(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.seekTo(int msec) Seeks - * to msec in the track - */ - public void seekTo(int msec) throws IllegalStateException { - lock.lock(); - try { - this.mpi.seekTo(msec); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setAudioStreamType(int - * streamtype) Sets the audio stream type. - */ - public void setAudioStreamType(int streamtype) { - lock.lock(); - try { - this.mAudioStreamType = streamtype; - this.mpi.setAudioStreamType(streamtype); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setDataSource(Context - * context, Uri uri) Sets uri as data source in the context given - */ - public void setDataSource(Context context, Uri uri) - throws IllegalArgumentException, IllegalStateException, IOException { - lock.lock(); - try { - Log.d(MP_TAG, "In setDataSource(context, " + uri.toString() + "), using " + this.mpi.getClass().toString()); - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.INITIALIZED; - this.stringDataSource = null; - this.uriDataSource = uri; - this.mpi.setDataSource(context, uri); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setDataSource(String - * path) Sets the data source of the track to a file given. - */ - public void setDataSource(String path) throws IllegalArgumentException, - IllegalStateException, IOException { - lock.lock(); - try { - Log.d(MP_TAG, "In setDataSource(context, " + path + ")"); - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.INITIALIZED; - this.stringDataSource = path; - this.uriDataSource = null; - this.mpi.setDataSource(path); - } finally { - lock.unlock(); - } - } - - /** - * Sets whether to use speed adjustment or not. Speed adjustment on is more - * computation-intensive than with it off. - * - * @param enableSpeedAdjustment Whether speed adjustment should be supported. - */ - public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { - lock.lock(); - try { - this.enableSpeedAdjustment = enableSpeedAdjustment; - this.mpi.setEnableSpeedAdjustment(enableSpeedAdjustment); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setLooping(boolean - * loop) Sets the track to loop infinitely if loop is true, play once if - * loop is false - */ - public void setLooping(boolean loop) { - lock.lock(); - try { - this.mIsLooping = loop; - this.mpi.setLooping(loop); - } finally { - lock.unlock(); - } - } - - /** - * Sets the number of steps (in a musical scale) by which playback is - * currently shifted. When greater than zero, pitch is shifted up. When less - * than zero, pitch is shifted down. - * - * @param pitchSteps The number of steps by which to shift playback - */ - public void setPitchStepsAdjustment(float pitchSteps) { - lock.lock(); - try { - this.mPitchStepsAdjustment = pitchSteps; - this.mpi.setPitchStepsAdjustment(pitchSteps); - } finally { - lock.unlock(); - } - } - - /** - * Set the algorithm to use for changing the speed and pitch of audio - * See SpeedAdjustmentAlgorithm constants for more details - * - * @param algorithm The algorithm to use. - */ - public void setSpeedAdjustmentAlgorithm(int algorithm) { - lock.lock(); - try { - this.speedAdjustmentAlgorithm = algorithm; - if (this.mpi != null) { - this.mpi.setSpeedAdjustmentAlgorithm(algorithm); - } - } finally { - lock.unlock(); - } - } - - private static float getPitchStepsAdjustment(float pitch) { - return (float) (Math.log(pitch) / (2 * Math.log(PITCH_STEP_CONSTANT))); - } - - /** - * Sets the percentage by which pitch is currently shifted. When greater - * than zero, pitch is shifted up. When less than zero, pitch is shifted - * down - * - * @param f The percentage to shift pitch - */ - public void setPlaybackPitch(float pitch) { - lock.lock(); - try { - this.mPitchStepsAdjustment = getPitchStepsAdjustment(pitch); - this.mpi.setPlaybackPitch(pitch); - } finally { - lock.unlock(); - } - } - - /** - * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so on. - * Speed should never be set to 0 or below. - * - * @param f The speed multiplier to use for further playback - */ - public void setPlaybackSpeed(float f) { - lock.lock(); - try { - this.mSpeedMultiplier = f; - this.mpi.setPlaybackSpeed(f); - } finally { - lock.unlock(); - } - } - - /** - * Sets whether to use speed adjustment or not. Speed adjustment on is more - * computation-intensive than with it off. - * - * @param enableSpeedAdjustment Whether speed adjustment should be supported. - */ - public void setUseService(boolean useService) { - lock.lock(); - try { - this.useService = useService; - setupMpi(this.mpi.mContext); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setVolume(float - * leftVolume, float rightVolume) Sets the stereo volume - */ - public void setVolume(float leftVolume, float rightVolume) { - lock.lock(); - try { - this.mLeftVolume = leftVolume; - this.mRightVolume = rightVolume; - this.mpi.setVolume(leftVolume, rightVolume); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setWakeMode(Context - * context, int mode) Acquires a wake lock in the context given. You must - * request the appropriate permissions in your AndroidManifest.xml file. - */ - public void setWakeMode(Context context, int mode) { - lock.lock(); - try { - this.mWakeMode = mode; - this.mpi.setWakeMode(context, mode); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener - * listener) Sets a listener to be used when a track completes playing. - */ - public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { - lock.lock(); - try { - this.onBufferingUpdateListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener - * listener) Sets a listener to be used when a track completes playing. - */ - public void setOnCompletionListener(OnCompletionListener listener) { - lock.lock(); - try { - this.onCompletionListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnErrorListener(OnErrorListener listener) - * Sets a listener to be used when a track encounters an error. - */ - public void setOnErrorListener(OnErrorListener listener) { - lock.lock(); - try { - this.onErrorListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnInfoListener(OnInfoListener listener) Sets - * a listener to be used when a track has info. - */ - public void setOnInfoListener(OnInfoListener listener) { - lock.lock(); - try { - this.onInfoListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Sets a listener that will fire when pitch adjustment becomes available or - * stops being available - */ - public void setOnPitchAdjustmentAvailableChangedListener( - OnPitchAdjustmentAvailableChangedListener listener) { - lock.lock(); - try { - this.pitchAdjustmentAvailableChangedListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnPreparedListener(OnPreparedListener - * listener) Sets a listener to be used when a track finishes preparing. - */ - public void setOnPreparedListener(OnPreparedListener listener) { - lock.lock(); - Log.d(MP_TAG, " ++++++++++++++++++++++++++++++++++++++++++++ setOnPreparedListener"); - try { - this.preparedListener = listener; - // For this one, we do not explicitly set the MediaPlayer or the - // Service listener. This is because in addition to calling the - // listener provided by the client, it's necessary to change - // state to PREPARED. See prepareAsync for implementation details - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to - * android.media.MediaPlayer.setOnSeekCompleteListener - * (OnSeekCompleteListener listener) Sets a listener to be used when a track - * finishes seeking. - */ - public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { - lock.lock(); - try { - this.onSeekCompleteListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Sets a listener that will fire when speed adjustment becomes available or - * stops being available - */ - public void setOnSpeedAdjustmentAvailableChangedListener( - OnSpeedAdjustmentAvailableChangedListener listener) { - lock.lock(); - try { - this.speedAdjustmentAvailableChangedListener = listener; - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.start() Starts a track - * playing - */ - public void start() { - lock.lock(); - try { - Log.d(MP_TAG, "start() 1149"); - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.STARTED; - Log.d(MP_TAG, "start() 1154"); - this.mpi.start(); - } finally { - lock.unlock(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.stop() Stops a track - * playing and resets its position to the start. - */ - public void stop() { - lock.lock(); - try { - if (invalidServiceConnectionConfiguration()) { - setupMpi(this.mpi.mContext); - } - this.state = State.STOPPED; - this.mpi.stop(); - } finally { - lock.unlock(); - } - } -}
\ No newline at end of file diff --git a/core/src/main/java/com/aocate/media/MediaPlayerImpl.java b/core/src/main/java/com/aocate/media/MediaPlayerImpl.java deleted file mode 100644 index 856ab47ce..000000000 --- a/core/src/main/java/com/aocate/media/MediaPlayerImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.media; - -import java.io.IOException; -import java.util.concurrent.locks.ReentrantLock; - -import android.content.Context; -import android.net.Uri; -import android.util.Log; - -public abstract class MediaPlayerImpl { - private static final String MPI_TAG = "AocateMediaPlayerImpl"; - protected final MediaPlayer owningMediaPlayer; - protected final Context mContext; - protected int muteOnPreparedCount = 0; - protected int muteOnSeekCount = 0; - - public MediaPlayerImpl(MediaPlayer owningMediaPlayer, Context context) { - this.owningMediaPlayer = owningMediaPlayer; - - this.mContext = context; - } - - public abstract boolean canSetPitch(); - - public abstract boolean canSetSpeed(); - - public abstract float getCurrentPitchStepsAdjustment(); - - public abstract int getCurrentPosition(); - - public abstract float getCurrentSpeedMultiplier(); - - public abstract int getDuration(); - - public abstract float getMaxSpeedMultiplier(); - - public abstract float getMinSpeedMultiplier(); - - public abstract boolean isLooping(); - - public abstract boolean isPlaying(); - - public abstract void pause(); - - public abstract void prepare() throws IllegalStateException, IOException; - - public abstract void prepareAsync(); - - public abstract void release(); - - public abstract void reset(); - - public abstract void seekTo(int msec) throws IllegalStateException; - - public abstract void setAudioStreamType(int streamtype); - - public abstract void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException; - - public abstract void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException; - - public abstract void setEnableSpeedAdjustment(boolean enableSpeedAdjustment); - - public abstract void setLooping(boolean loop); - - public abstract void setPitchStepsAdjustment(float pitchSteps); - - public abstract void setPlaybackPitch(float f); - - public abstract void setPlaybackSpeed(float f); - - public abstract void setSpeedAdjustmentAlgorithm(int algorithm); - - public abstract void setVolume(float leftVolume, float rightVolume); - - public abstract void setWakeMode(Context context, int mode); - - public abstract void start(); - - public abstract void stop(); - - protected ReentrantLock lockMuteOnPreparedCount = new ReentrantLock(); - public void muteNextOnPrepare() { - lockMuteOnPreparedCount.lock(); - Log.d(MPI_TAG, "muteNextOnPrepare()"); - try { - this.muteOnPreparedCount++; - } - finally { - lockMuteOnPreparedCount.unlock(); - } - } - - protected ReentrantLock lockMuteOnSeekCount = new ReentrantLock(); - public void muteNextSeek() { - lockMuteOnSeekCount.lock(); - Log.d(MPI_TAG, "muteNextOnSeek()"); - try { - this.muteOnSeekCount++; - } - finally { - lockMuteOnSeekCount.unlock(); - } - } -} diff --git a/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java b/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java deleted file mode 100644 index 0e27a8014..000000000 --- a/core/src/main/java/com/aocate/media/ServiceBackedMediaPlayer.java +++ /dev/null @@ -1,1203 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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. -// -// ----------------------------------------------------------------------- -// Compared to the original version, this class been slightly modified so -// that any acquired WakeLocks are only held while the MediaPlayer is -// playing (see the stayAwake method for more details). - - -package com.aocate.media; - -import java.io.IOException; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.media.AudioManager; -import android.net.Uri; -import android.os.IBinder; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.PowerManager.WakeLock; -import android.util.Log; - -import com.aocate.media.MediaPlayer.State; -import com.aocate.presto.service.IDeathCallback_0_8; -import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8; -import com.aocate.presto.service.IOnCompletionListenerCallback_0_8; -import com.aocate.presto.service.IOnErrorListenerCallback_0_8; -import com.aocate.presto.service.IOnInfoListenerCallback_0_8; -import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8; -import com.aocate.presto.service.IOnPreparedListenerCallback_0_8; -import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8; -import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8; -import com.aocate.presto.service.IPlayMedia_0_8; - -import de.danoeh.antennapod.core.BuildConfig; - -/** - * Class for connecting to remote speed-altering, media playing Service - * Note that there is unusually high coupling between MediaPlayer and this - * class. This is an unfortunate compromise, since the alternative was to - * track state in two different places in this code (plus the internal state - * of the remote media player). - * @author aocate - * - */ -public class ServiceBackedMediaPlayer extends MediaPlayerImpl { - static final String INTENT_NAME = "com.aocate.intent.PLAY_AUDIO_ADJUST_SPEED_0_8"; - - private static final String SBMP_TAG = "AocateServiceBackedMediaPlayer"; - - private ServiceConnection mPlayMediaServiceConnection = null; - protected IPlayMedia_0_8 pmInterface = null; - private Intent playMediaServiceIntent = null; - // In some cases, we're going to have to replace the - // android.media.MediaPlayer on the fly, and we don't want to touch the - // wrong media player. - - private long sessionId = 0; - private boolean isErroring = false; - private int mAudioStreamType = AudioManager.STREAM_MUSIC; - - private WakeLock mWakeLock = null; - - // So here's the major problem - // Sometimes the service won't exist or won't be connected, - // so start with an android.media.MediaPlayer, and when - // the service is connected, use that from then on - public ServiceBackedMediaPlayer(MediaPlayer owningMediaPlayer, final Context context, final ServiceConnection serviceConnection) { - super(owningMediaPlayer, context); - Log.d(SBMP_TAG, "Instantiating ServiceBackedMediaPlayer 87"); - this.playMediaServiceIntent = - MediaPlayer.getPrestoServiceIntent(context, INTENT_NAME); - this.mPlayMediaServiceConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName name, IBinder service) { - IPlayMedia_0_8 tmpPlayMediaInterface = IPlayMedia_0_8.Stub.asInterface((IBinder) service); - - Log.d(SBMP_TAG, "Setting up pmInterface 94"); - if (ServiceBackedMediaPlayer.this.sessionId == 0) { - try { - // The IDeathCallback isn't a conventional callback. - // It exists so that if the client ceases to exist, - // the Service becomes aware of that and can shut - // down whatever it needs to shut down - ServiceBackedMediaPlayer.this.sessionId = tmpPlayMediaInterface.startSession(new IDeathCallback_0_8.Stub() { - }); - // This is really bad if this fails - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - Log.d(SBMP_TAG, "Assigning pmInterface"); - - ServiceBackedMediaPlayer.this.setOnBufferingUpdateCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnCompletionCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnErrorCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnInfoCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnPitchAdjustmentAvailableChangedListener(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnPreparedCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnSeekCompleteCallback(tmpPlayMediaInterface); - ServiceBackedMediaPlayer.this.setOnSpeedAdjustmentAvailableChangedCallback(tmpPlayMediaInterface); - - // In order to avoid race conditions from the sessionId or listener not being assigned - pmInterface = tmpPlayMediaInterface; - - Log.d(SBMP_TAG, "Invoking onServiceConnected"); - serviceConnection.onServiceConnected(name, service); - } - - public void onServiceDisconnected(ComponentName name) { - Log.d(SBMP_TAG, "onServiceDisconnected 114"); - - pmInterface = null; - - sessionId = 0; - - serviceConnection.onServiceDisconnected(name); - } - }; - - Log.d(SBMP_TAG, "Connecting PlayMediaService 124"); - if (!ConnectPlayMediaService()) { - Log.e(SBMP_TAG, "bindService failed"); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private boolean ConnectPlayMediaService() { - Log.d(SBMP_TAG, "ConnectPlayMediaService()"); - - if (MediaPlayer.isIntentAvailable(mContext, INTENT_NAME)) { - Log.d(SBMP_TAG, INTENT_NAME + " is available"); - if (pmInterface == null) { - try { - Log.d(SBMP_TAG, "Binding service"); - return mContext.bindService(playMediaServiceIntent, mPlayMediaServiceConnection, Context.BIND_AUTO_CREATE); - } catch (Exception e) { - Log.e(SBMP_TAG, "Could not bind with service", e); - return false; - } - } else { - Log.d(SBMP_TAG, "Service already bound"); - return true; - } - } - else { - Log.d(SBMP_TAG, INTENT_NAME + " is not available"); - return false; - } - } - - /** - * Returns true if pitch can be changed at this moment - * @return True if pitch can be changed - */ - @Override - public boolean canSetPitch() { - Log.d(SBMP_TAG, "canSetPitch() 155"); - - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set pitch if the service isn't connected - try { - return pmInterface.canSetPitch(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return false; - } - - /** - * Returns true if speed can be changed at this moment - * @return True if speed can be changed - */ - @Override - public boolean canSetSpeed() { - Log.d(SBMP_TAG, "canSetSpeed() 180"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the service isn't connected - try { - return pmInterface.canSetSpeed(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return false; - } - - void error(int what, int extra) { - owningMediaPlayer.lock.lock(); - Log.e(SBMP_TAG, "error(" + what + ", " + extra + ")"); - stayAwake(false); - try { - if (!this.isErroring) { - this.isErroring = true; - owningMediaPlayer.state = State.ERROR; - if (owningMediaPlayer.onErrorListener != null) { - if (owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra)) { - return; - } - } - if (owningMediaPlayer.onCompletionListener != null) { - owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); - } - } - } - finally { - this.isErroring = false; - owningMediaPlayer.lock.unlock(); - } - } - - protected void finalize() throws Throwable { - owningMediaPlayer.lock.lock(); - try { - Log.d(SBMP_TAG, "finalize() 224"); - this.release(); - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - /** - * Returns the number of steps (in a musical scale) by which playback is - * currently shifted. When greater than zero, pitch is shifted up. - * When less than zero, pitch is shifted down. - * @return The number of steps pitch is currently shifted by - */ - @Override - public float getCurrentPitchStepsAdjustment() { - Log.d(SBMP_TAG, "getCurrentPitchStepsAdjustment() 240"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set pitch if the service isn't connected - try { - return pmInterface.getCurrentPitchStepsAdjustment( - ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return 0f; - } - - /** - * Functions identically to android.media.MediaPlayer.getCurrentPosition() - * @return Current position (in milliseconds) - */ - @Override - public int getCurrentPosition() { - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - return pmInterface.getCurrentPosition( - ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - return 0; - } - - /** - * Returns the current speed multiplier. Defaults to 1.0 (normal speed) - * @return The current speed multiplier - */ - @Override - public float getCurrentSpeedMultiplier() { - Log.d(SBMP_TAG, "getCurrentSpeedMultiplier() 286"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the service isn't connected - try { - return pmInterface.getCurrentSpeedMultiplier( - ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return 1; - } - - /** - * Functions identically to android.media.MediaPlayer.getDuration() - * @return Length of the track (in milliseconds) - */ - @Override - public int getDuration() { - Log.d(SBMP_TAG, "getDuration() 311"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - return pmInterface.getDuration(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - return 0; - } - - /** - * Get the maximum value that can be passed to setPlaybackSpeed - * @return The maximum speed multiplier - */ - @Override - public float getMaxSpeedMultiplier() { - Log.d(SBMP_TAG, "getMaxSpeedMultiplier() 332"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - return pmInterface.getMaxSpeedMultiplier( - ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return 1f; - } - - /** - * Get the minimum value that can be passed to setPlaybackSpeed - * @return The minimum speed multiplier - */ - @Override - public float getMinSpeedMultiplier() { - Log.d(SBMP_TAG, "getMinSpeedMultiplier() 357"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - return pmInterface.getMinSpeedMultiplier( - ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return 1f; - } - - public int getServiceVersionCode() { - Log.d(SBMP_TAG, "getVersionCode"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - return pmInterface.getVersionCode(); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - return 0; - } - - public String getServiceVersionName() { - Log.d(SBMP_TAG, "getVersionName"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - return pmInterface.getVersionName(); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - return ""; - } - - public boolean isConnected() { - return (pmInterface != null); - } - - /** - * Functions identically to android.media.MediaPlayer.isLooping() - * @return True if the track is looping - */ - @Override - public boolean isLooping() { - Log.d(SBMP_TAG, "isLooping() 382"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - return pmInterface.isLooping(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - return false; - } - - /** - * Functions identically to android.media.MediaPlayer.isPlaying() - * @return True if the track is playing - */ - @Override - public boolean isPlaying() { - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - try { - return pmInterface.isPlaying(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - return false; - } - - /** - * Functions identically to android.media.MediaPlayer.pause() - * Pauses the track - */ - @Override - public void pause() { - Log.d(SBMP_TAG, "pause() 424"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.pause(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - stayAwake(false); - } - - /** - * Functions identically to android.media.MediaPlayer.prepare() - * Prepares the track. This or prepareAsync must be called before start() - */ - @Override - public void prepare() throws IllegalStateException, IOException { - Log.d(SBMP_TAG, "prepare() 444"); - Log.d(SBMP_TAG, "onPreparedCallback is: " + ((this.mOnPreparedCallback == null) ? "null" : "non-null")); - if (pmInterface == null) { - Log.d(SBMP_TAG, "prepare: pmInterface is null"); - if (!ConnectPlayMediaService()) { - Log.d(SBMP_TAG, "prepare: Failed to connect play media service"); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - Log.d(SBMP_TAG, "prepare: pmInterface isn't null"); - try { - Log.d(SBMP_TAG, "prepare: Remote invoke pmInterface.prepare(" + ServiceBackedMediaPlayer.this.sessionId + ")"); - pmInterface.prepare(ServiceBackedMediaPlayer.this.sessionId); - Log.d(SBMP_TAG, "prepare: prepared"); - } catch (RemoteException e) { - Log.d(SBMP_TAG, "prepare: RemoteException"); - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - Log.d(SBMP_TAG, "Done with prepare()"); - } - - /** - * Functions identically to android.media.MediaPlayer.prepareAsync() - * Prepares the track. This or prepare must be called before start() - */ - @Override - public void prepareAsync() { - Log.d(SBMP_TAG, "prepareAsync() 469"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.prepareAsync(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.release() - * Releases the underlying resources used by the media player. - */ - @Override - public void release() { - Log.d(SBMP_TAG, "release() 492"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - Log.d(SBMP_TAG, "release() 500"); - try { - pmInterface.release(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - mContext.unbindService(this.mPlayMediaServiceConnection); - // Don't try to keep awake (if we were) - this.setWakeMode(mContext, 0); - pmInterface = null; - this.sessionId = 0; - } - - if ((this.mWakeLock != null) && this.mWakeLock.isHeld()) { - Log.d(SBMP_TAG, "Releasing wakelock"); - this.mWakeLock.release(); - } - } - - /** - * Functions identically to android.media.MediaPlayer.reset() - * Resets the track to idle state - */ - @Override - public void reset() { - Log.d(SBMP_TAG, "reset() 523"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.reset(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - stayAwake(false); - } - - /** - * Functions identically to android.media.MediaPlayer.seekTo(int msec) - * Seeks to msec in the track - */ - @Override - public void seekTo(int msec) throws IllegalStateException { - Log.d(SBMP_TAG, "seekTo(" + msec + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.seekTo(ServiceBackedMediaPlayer.this.sessionId, msec); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setAudioStreamType(int streamtype) - * Sets the audio stream type. - */ - @Override - public void setAudioStreamType(int streamtype) { - Log.d(SBMP_TAG, "setAudioStreamType(" + streamtype + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.setAudioStreamType( - ServiceBackedMediaPlayer.this.sessionId, - this.mAudioStreamType); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - - /** - * Functions identically to android.media.MediaPlayer.setDataSource(Context context, Uri uri) - * Sets uri as data source in the context given - */ - @Override - public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException { - Log.d(SBMP_TAG, "setDataSource(context, uri)"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.setDataSourceUri( - ServiceBackedMediaPlayer.this.sessionId, - uri); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setDataSource(String path) - * Sets the data source of the track to a file given. - */ - @Override - public void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException { - Log.d(SBMP_TAG, "setDataSource(path)"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface == null) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - else { - try { - pmInterface.setDataSourceString( - ServiceBackedMediaPlayer.this.sessionId, - path); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - } - - /** - * Sets whether to use speed adjustment or not. Speed adjustment on is - * more computation-intensive than with it off. - * @param enableSpeedAdjustment Whether speed adjustment should be supported. - */ - @Override - public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { - // TODO: This has no business being here, I think - owningMediaPlayer.lock.lock(); - Log.d(SBMP_TAG, "setEnableSpeedAdjustment(enableSpeedAdjustment)"); - try { - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - pmInterface.setEnableSpeedAdjustment( - ServiceBackedMediaPlayer.this.sessionId, - enableSpeedAdjustment); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - - - /** - * Functions identically to android.media.MediaPlayer.setLooping(boolean loop) - * Sets the track to loop infinitely if loop is true, play once if loop is false - */ - @Override - public void setLooping(boolean loop) { - Log.d(SBMP_TAG, "setLooping(" + loop + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.setLooping(ServiceBackedMediaPlayer.this.sessionId, loop); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Sets the number of steps (in a musical scale) by which playback is - * currently shifted. When greater than zero, pitch is shifted up. - * When less than zero, pitch is shifted down. - * - * @param pitchSteps The number of steps by which to shift playback - */ - @Override - public void setPitchStepsAdjustment(float pitchSteps) { - Log.d(SBMP_TAG, "setPitchStepsAdjustment(" + pitchSteps + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - pmInterface.setPitchStepsAdjustment( - ServiceBackedMediaPlayer.this.sessionId, - pitchSteps); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - } - - /** - * Sets the percentage by which pitch is currently shifted. When - * greater than zero, pitch is shifted up. When less than zero, pitch - * is shifted down - * @param f The percentage to shift pitch - */ - @Override - public void setPlaybackPitch(float f) { - Log.d(SBMP_TAG, "setPlaybackPitch(" + f + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - pmInterface.setPlaybackPitch( - ServiceBackedMediaPlayer.this.sessionId, - f); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - } - - /** - * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so - * on. Speed should never be set to 0 or below. - * @param f The speed multiplier to use for further playback - */ - @Override - public void setPlaybackSpeed(float f) { - Log.d(SBMP_TAG, "setPlaybackSpeed(" + f + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - if (pmInterface != null) { - // Can't set speed if the Service isn't connected - try { - pmInterface.setPlaybackSpeed( - ServiceBackedMediaPlayer.this.sessionId, - f); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - } - - @Override - public void setSpeedAdjustmentAlgorithm(int algorithm) { - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.setSpeedAdjustmentAlgorithm( - ServiceBackedMediaPlayer.this.sessionId, - algorithm); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setVolume(float leftVolume, float rightVolume) - * Sets the stereo volume - */ - @Override - public void setVolume(float leftVolume, float rightVolume) { - Log.d(SBMP_TAG, "setVolume(" + leftVolume + ", " + rightVolume + ")"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.setVolume( - ServiceBackedMediaPlayer.this.sessionId, - leftVolume, - rightVolume); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.setWakeMode(Context context, int mode) - * Acquires a wake lock in the context given. You must request the appropriate permissions - * in your AndroidManifest.xml file. - */ - @Override - // This does not just call .setWakeMode() in the Service because doing so - // would add a permission requirement to the Service. Do it here, and it's - // the client app's responsibility to request that permission - public void setWakeMode(Context context, int mode) { - Log.d(SBMP_TAG, "setWakeMode(context, " + mode + ")"); - if ((this.mWakeLock != null) - && (this.mWakeLock.isHeld())) { - this.mWakeLock.release(); - } - if (mode != 0) { - if (this.mWakeLock == null) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - // Since mode can't be changed on the fly, we have to allocate a new one - this.mWakeLock = pm.newWakeLock(mode, this.getClass().getName()); - this.mWakeLock.setReferenceCounted(false); - } - - this.mWakeLock.acquire(); - } - } - - /** - * Changes the state of the WakeLock if it has been acquired. - * If no WakeLock has been acquired with setWakeMode, this method does nothing. - * */ - private void stayAwake(boolean awake) { - if (BuildConfig.DEBUG) Log.d(SBMP_TAG, "stayAwake(" + awake + ")"); - if (mWakeLock != null) { - if (awake && !mWakeLock.isHeld()) { - mWakeLock.acquire(); - } else if (!awake && mWakeLock.isHeld()) { - mWakeLock.release(); - } - } - } - - private IOnBufferingUpdateListenerCallback_0_8.Stub mOnBufferingUpdateCallback = null; - private void setOnBufferingUpdateCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnBufferingUpdateCallback == null) { - mOnBufferingUpdateCallback = new IOnBufferingUpdateListenerCallback_0_8.Stub() { - public void onBufferingUpdate(int percent) - throws RemoteException { - owningMediaPlayer.lock.lock(); - try { - if ((owningMediaPlayer.onBufferingUpdateListener != null) - && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) { - owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnBufferingUpdateCallback( - ServiceBackedMediaPlayer.this.sessionId, - mOnBufferingUpdateCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnCompletionListenerCallback_0_8.Stub mOnCompletionCallback = null; - private void setOnCompletionCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnCompletionCallback == null) { - this.mOnCompletionCallback = new IOnCompletionListenerCallback_0_8.Stub() { - public void onCompletion() throws RemoteException { - owningMediaPlayer.lock.lock(); - Log.d(SBMP_TAG, "onCompletionListener being called"); - stayAwake(false); - try { - if (owningMediaPlayer.onCompletionListener != null) { - owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnCompletionCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnCompletionCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnErrorListenerCallback_0_8.Stub mOnErrorCallback = null; - private void setOnErrorCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnErrorCallback == null) { - this.mOnErrorCallback = new IOnErrorListenerCallback_0_8.Stub() { - public boolean onError(int what, int extra) throws RemoteException { - owningMediaPlayer.lock.lock(); - stayAwake(false); - try { - if (owningMediaPlayer.onErrorListener != null) { - return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra); - } - return false; - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnErrorCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnErrorCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnInfoListenerCallback_0_8.Stub mOnInfoCallback = null; - private void setOnInfoCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnInfoCallback == null) { - this.mOnInfoCallback = new IOnInfoListenerCallback_0_8.Stub() { - public boolean onInfo(int what, int extra) throws RemoteException { - owningMediaPlayer.lock.lock(); - try { - if ((owningMediaPlayer.onInfoListener != null) - && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) { - return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - return false; - } - }; - } - iface.registerOnInfoCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnInfoCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnPitchAdjustmentAvailableChangedCallback = null; - private void setOnPitchAdjustmentAvailableChangedListener(IPlayMedia_0_8 iface) { - try { - if (this.mOnPitchAdjustmentAvailableChangedCallback == null) { - this.mOnPitchAdjustmentAvailableChangedCallback = new IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub() { - public void onPitchAdjustmentAvailableChanged( - boolean pitchAdjustmentAvailable) - throws RemoteException { - owningMediaPlayer.lock.lock(); - try { - if (owningMediaPlayer.onPitchAdjustmentAvailableChangedListener != null) { - owningMediaPlayer.onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged(owningMediaPlayer, pitchAdjustmentAvailable); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnPitchAdjustmentAvailableChangedCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnPitchAdjustmentAvailableChangedCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnPreparedListenerCallback_0_8.Stub mOnPreparedCallback = null; - private void setOnPreparedCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnPreparedCallback == null) { - this.mOnPreparedCallback = new IOnPreparedListenerCallback_0_8.Stub() { - public void onPrepared() throws RemoteException { - owningMediaPlayer.lock.lock(); - Log.d(SBMP_TAG, "setOnPreparedCallback.mOnPreparedCallback.onPrepared 1050"); - try { - Log.d(SBMP_TAG, "owningMediaPlayer.onPreparedListener is " + ((owningMediaPlayer.onPreparedListener == null) ? "null" : "non-null")); - Log.d(SBMP_TAG, "owningMediaPlayer.mpi is " + ((owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this) ? "this" : "not this")); - ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.lock(); - try { - if (ServiceBackedMediaPlayer.this.muteOnPreparedCount > 0) { - ServiceBackedMediaPlayer.this.muteOnPreparedCount--; - } - else { - ServiceBackedMediaPlayer.this.muteOnPreparedCount = 0; - if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) { - owningMediaPlayer.onPreparedListener.onPrepared(owningMediaPlayer); - } - } - } - finally { - ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.unlock(); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnPreparedCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnPreparedCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnSeekCompleteListenerCallback_0_8.Stub mOnSeekCompleteCallback = null; - private void setOnSeekCompleteCallback(IPlayMedia_0_8 iface) { - try { - if (this.mOnSeekCompleteCallback == null) { - this.mOnSeekCompleteCallback = new IOnSeekCompleteListenerCallback_0_8.Stub() { - public void onSeekComplete() throws RemoteException { - Log.d(SBMP_TAG, "onSeekComplete() 941"); - owningMediaPlayer.lock.lock(); - try { - if (ServiceBackedMediaPlayer.this.muteOnSeekCount > 0) { - Log.d(SBMP_TAG, "The next " + ServiceBackedMediaPlayer.this.muteOnSeekCount + " seek events are muted (counting this one)"); - ServiceBackedMediaPlayer.this.muteOnSeekCount--; - } - else { - ServiceBackedMediaPlayer.this.muteOnSeekCount = 0; - Log.d(SBMP_TAG, "Attempting to invoke next seek event"); - if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) { - Log.d(SBMP_TAG, "Invoking onSeekComplete"); - owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer); - } - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnSeekCompleteCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnSeekCompleteCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - private IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnSpeedAdjustmentAvailableChangedCallback = null; - private void setOnSpeedAdjustmentAvailableChangedCallback(IPlayMedia_0_8 iface) { - try { - Log.d(SBMP_TAG, "Setting the service of on speed adjustment available changed"); - if (this.mOnSpeedAdjustmentAvailableChangedCallback == null) { - this.mOnSpeedAdjustmentAvailableChangedCallback = new IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub() { - public void onSpeedAdjustmentAvailableChanged( - boolean speedAdjustmentAvailable) - throws RemoteException { - owningMediaPlayer.lock.lock(); - try { - if (owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener != null) { - owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged(owningMediaPlayer, speedAdjustmentAvailable); - } - } - finally { - owningMediaPlayer.lock.unlock(); - } - } - }; - } - iface.registerOnSpeedAdjustmentAvailableChangedCallback( - ServiceBackedMediaPlayer.this.sessionId, - this.mOnSpeedAdjustmentAvailableChangedCallback); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - - /** - * Functions identically to android.media.MediaPlayer.start() - * Starts a track playing - */ - @Override - public void start() { - Log.d(SBMP_TAG, "start()"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.start(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - stayAwake(true); - } - - /** - * Functions identically to android.media.MediaPlayer.stop() - * Stops a track playing and resets its position to the start. - */ - @Override - public void stop() { - Log.d(SBMP_TAG, "stop()"); - if (pmInterface == null) { - if (!ConnectPlayMediaService()) { - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - } - try { - pmInterface.stop(ServiceBackedMediaPlayer.this.sessionId); - } catch (RemoteException e) { - e.printStackTrace(); - ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); - } - stayAwake(false); - } -}
\ No newline at end of file diff --git a/core/src/main/java/com/aocate/media/SpeedAdjustmentAlgorithm.java b/core/src/main/java/com/aocate/media/SpeedAdjustmentAlgorithm.java deleted file mode 100644 index d337a0452..000000000 --- a/core/src/main/java/com/aocate/media/SpeedAdjustmentAlgorithm.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2011, Aocate, Inc. -// -// 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.aocate.media; - -public class SpeedAdjustmentAlgorithm { - /** - * Use this to use the user-specified algorithm - */ - public static int DEFAULT = 0; - - /** - * Better for voice audio - */ - public static int SONIC = 1; - /** - * Better for music audio - */ - public static int WSOLA = 2; -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index 879b28096..c1d21552e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -55,7 +55,7 @@ public class FeedItemFilter { } } - public List<FeedItem> filter(Context context, List<FeedItem> items) { + public List<FeedItem> filter(List<FeedItem> items) { if(properties.length == 0) { return items; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index c0d44dff3..e6a2a2464 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -89,6 +89,10 @@ public class UserPreferences { public static final String IMAGE_CACHE_DEFAULT_VALUE = "100"; public static final int IMAGE_CACHE_SIZE_MINIMUM = 20; + // Experimental + public static final String PREF_SONIC = "prefSonic"; + public static final String PREF_NORMALIZER = "prefNormalizer"; + // Constants private static int EPISODE_CACHE_SIZE_UNLIMITED = -1; public static int FEED_ORDER_COUNTER = 0; @@ -469,6 +473,9 @@ public class UserPreferences { return selectedSpeeds; } + public static boolean useSonic() { + return prefs.getBoolean(PREF_SONIC, false); + } /** * Return the folder where the app stores all of its data. This method will diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java index 757b2e980..7cf7eb622 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java @@ -1047,9 +1047,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre return mp; } - private final com.aocate.media.MediaPlayer.OnCompletionListener audioCompletionListener = new com.aocate.media.MediaPlayer.OnCompletionListener() { + private final org.antennapod.audio.MediaPlayer.OnCompletionListener audioCompletionListener = new org.antennapod.audio.MediaPlayer.OnCompletionListener() { @Override - public void onCompletion(com.aocate.media.MediaPlayer mp) { + public void onCompletion(org.antennapod.audio.MediaPlayer mp) { genericOnCompletion(); } }; @@ -1065,9 +1065,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre endPlayback(); } - private final com.aocate.media.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = new com.aocate.media.MediaPlayer.OnBufferingUpdateListener() { + private final org.antennapod.audio.MediaPlayer.OnBufferingUpdateListener audioBufferingUpdateListener = new org.antennapod.audio.MediaPlayer.OnBufferingUpdateListener() { @Override - public void onBufferingUpdate(com.aocate.media.MediaPlayer mp, + public void onBufferingUpdate(org.antennapod.audio.MediaPlayer mp, int percent) { genericOnBufferingUpdate(percent); } @@ -1084,9 +1084,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre callback.onBufferingUpdate(percent); } - private final com.aocate.media.MediaPlayer.OnInfoListener audioInfoListener = new com.aocate.media.MediaPlayer.OnInfoListener() { + private final org.antennapod.audio.MediaPlayer.OnInfoListener audioInfoListener = new org.antennapod.audio.MediaPlayer.OnInfoListener() { @Override - public boolean onInfo(com.aocate.media.MediaPlayer mp, int what, + public boolean onInfo(org.antennapod.audio.MediaPlayer mp, int what, int extra) { return genericInfoListener(what); } @@ -1103,9 +1103,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre return callback.onMediaPlayerInfo(what); } - private final com.aocate.media.MediaPlayer.OnErrorListener audioErrorListener = new com.aocate.media.MediaPlayer.OnErrorListener() { + private final org.antennapod.audio.MediaPlayer.OnErrorListener audioErrorListener = new org.antennapod.audio.MediaPlayer.OnErrorListener() { @Override - public boolean onError(com.aocate.media.MediaPlayer mp, int what, + public boolean onError(org.antennapod.audio.MediaPlayer mp, int what, int extra) { return genericOnError(mp, what, extra); } @@ -1122,9 +1122,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre return callback.onMediaPlayerError(inObj, what, extra); } - private final com.aocate.media.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = new com.aocate.media.MediaPlayer.OnSeekCompleteListener() { + private final org.antennapod.audio.MediaPlayer.OnSeekCompleteListener audioSeekCompleteListener = new org.antennapod.audio.MediaPlayer.OnSeekCompleteListener() { @Override - public void onSeekComplete(com.aocate.media.MediaPlayer mp) { + public void onSeekComplete(org.antennapod.audio.MediaPlayer mp) { genericSeekCompleteListener(); } }; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 73037d771..fa4a5726a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -309,7 +309,11 @@ public class PodDBAdapter { dbHelper.close(); dbHelper = null; } - return context.deleteDatabase(PodDBAdapter.DATABASE_NAME); + if(context != null) { // may not have been initialized + return context.deleteDatabase(PodDBAdapter.DATABASE_NAME); + } else { + return false; + } } /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java index aafcea307..b6beb5bf1 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java @@ -3,7 +3,9 @@ package de.danoeh.antennapod.core.util.playback; import android.content.Context; import android.util.Log; import android.view.SurfaceHolder; -import com.aocate.media.MediaPlayer; +import org.antennapod.audio.MediaPlayer; + +import de.danoeh.antennapod.core.preferences.UserPreferences; public class AudioPlayer extends MediaPlayer implements IPlayer { private static final String TAG = "AudioPlayer"; @@ -16,7 +18,6 @@ public class AudioPlayer extends MediaPlayer implements IPlayer { public void setScreenOnWhilePlaying(boolean screenOn) { Log.e(TAG, "Setting screen on while playing not supported in Audio Player"); throw new UnsupportedOperationException("Setting screen on while playing not supported in Audio Player"); - } @Override @@ -31,4 +32,9 @@ public class AudioPlayer extends MediaPlayer implements IPlayer { public void setVideoScalingMode(int mode) { throw new UnsupportedOperationException("Setting scaling mode is not supported in Audio Player"); } + + @Override + protected boolean useSonic() { + return UserPreferences.useSonic(); + } } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 68c5150e5..ff9891bab 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -344,6 +344,9 @@ <string name="pref_smart_mark_as_played_disabled">Disabled</string> <string name="pref_image_cache_size_title">Image Cache Size</string> <string name="pref_image_cache_size_sum">Size of the disk cache for images.</string> + <string name="experimental_pref">Experimental</string> + <string name="pref_sonic_title">Sonic media player</string> + <string name="pref_sonic_message">Use built-in sonic media player as a replacement for Prestissimo</string> <!-- Auto-Flattr dialog --> <string name="auto_flattr_enable">Enable automatic flattring</string> |