Merge pull request #4925 from ByteHamster/remove-playback-service-callbacks

Remove PlaybackServiceCallbacks
This commit is contained in:
ByteHamster 2021-02-12 20:05:20 +01:00 committed by GitHub
commit 87b149b764
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 212 additions and 100 deletions

View File

@ -45,7 +45,7 @@ workflows:
destination: app-play-debug.apk
- run:
name: Execute debug unit tests
command: ./gradlew :core:testPlayDebugUnitTest -PdisablePreDex
command: ./gradlew testPlayDebugUnitTest -PdisablePreDex
- build:
name: Build release
build-steps:
@ -54,13 +54,13 @@ workflows:
command: ./gradlew assembleRelease -PdisablePreDex
- run:
name: Execute release unit tests
command: ./gradlew :core:testPlayReleaseUnitTest -PdisablePreDex
command: ./gradlew testPlayReleaseUnitTest -PdisablePreDex
- build:
name: Build integration tests
build-steps:
- run:
name: Build integration tests
command: ./gradlew :app:assemblePlayDebugAndroidTest -PdisablePreDex
command: ./gradlew assemblePlayDebugAndroidTest -PdisablePreDex
- build:
name: Build free
build-steps:
@ -85,19 +85,8 @@ workflows:
curl -s -L https://github.com/yangziwen/diff-checkstyle/releases/download/0.0.4/diff-checkstyle.jar > diff-checkstyle.jar
java -Dconfig_loc=config/checkstyle -jar diff-checkstyle.jar -c config/checkstyle/checkstyle-new-code.xml --git-dir . --base-rev $branchBaseCommit
- build:
name: Lint app
name: Lint
build-steps:
- run:
name: Lint app
command: ./gradlew app:lintPlayRelease
- run:
name: Lint core
command: ./gradlew core:lintPlayRelease
- store_artifacts:
name: Uploading app lint reports
path: app/build/reports/lint-results-playRelease.html
destination: lint-results-app.html
- store_artifacts:
name: Uploading core lint reports
path: core/build/reports/lint-results-playRelease.html
destination: lint-results-core.html
name: Lint
command: ./gradlew lintPlayRelease

View File

@ -164,6 +164,7 @@ dependencies {
} else {
System.out.println("app: free build hack, skipping some dependencies")
}
implementation project(':ui:app-start-intent')
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"

View File

@ -15,6 +15,7 @@ import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.test.antennapod.EspressoTestUtils;
import de.test.antennapod.IgnoreOnCi;
import org.awaitility.Awaitility;
@ -71,7 +72,7 @@ public class SpeedChangeTest {
UserPreferences.setPlaybackSpeedArray(Arrays.asList(1.0f, 2.0f, 3.0f));
EspressoTestUtils.tryKillPlaybackService();
activityRule.launchActivity(new Intent().putExtra(MainActivity.EXTRA_OPEN_PLAYER, true));
activityRule.launchActivity(new Intent().putExtra(MainActivityStarter.EXTRA_OPEN_PLAYER, true));
controller = new PlaybackController(activityRule.getActivity());
controller.init();
controller.getMedia(); // To load media

View File

@ -106,6 +106,10 @@
android:pathPrefix="/deeplink/search"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="de.danoeh.antennapod.intents.MAIN_ACTIVITY" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
@ -212,6 +216,10 @@
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.danoeh.antennapod.activity.MainActivity"/>
<intent-filter>
<action android:name="de.danoeh.antennapod.intents.VIDEO_PLAYER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity

View File

@ -56,6 +56,7 @@ import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.fragment.SubscriptionFragment;
import de.danoeh.antennapod.fragment.TransitionEffect;
import de.danoeh.antennapod.preferences.PreferenceUpgrader;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.view.LockableBottomSheetBehavior;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.Validate;
@ -77,7 +78,6 @@ public class MainActivity extends CastEnabledActivity {
public static final String EXTRA_FRAGMENT_TAG = "fragment_tag";
public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
public static final String EXTRA_FEED_ID = "fragment_feed_id";
public static final String EXTRA_OPEN_PLAYER = "open_player";
public static final String EXTRA_REFRESH_ON_START = "refresh_on_start";
public static final String EXTRA_STARTED_FROM_SEARCH = "started_from_search";
public static final String KEY_GENERATED_VIEW_ID = "generated_view_id";
@ -510,7 +510,7 @@ public class MainActivity extends CastEnabledActivity {
}
}
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
} else if (intent.getBooleanExtra(EXTRA_OPEN_PLAYER, false)) {
} else if (intent.getBooleanExtra(MainActivityStarter.EXTRA_OPEN_PLAYER, false)) {
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
bottomSheetCallback.onSlide(null, 1.0f);
} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {

View File

@ -41,6 +41,7 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.view.AspectRatioVideoView;
/**
@ -343,7 +344,7 @@ public class VideoplayerActivity extends MediaplayerActivity {
Log.d(TAG, "ReloadNotification received, switching to Castplayer now");
destroyingDueToReload = true;
finish();
startActivity(new Intent(this, MainActivity.class).putExtra(MainActivity.EXTRA_OPEN_PLAYER, true));
new MainActivityStarter(this).withOpenPlayer().start();
}
}

View File

@ -15,7 +15,6 @@ class ClientConfigurator {
ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
ClientConfig.castCallbacks = new CastCallbackImpl();
}
}

View File

@ -1,24 +0,0 @@
package de.danoeh.antennapod.config;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.VideoplayerActivity;
import de.danoeh.antennapod.core.PlaybackServiceCallbacks;
import de.danoeh.antennapod.core.feed.MediaType;
public class PlaybackServiceCallbacksImpl implements PlaybackServiceCallbacks {
@Override
public Intent getPlayerActivityIntent(Context context, MediaType mediaType, boolean remotePlayback) {
if (mediaType == MediaType.AUDIO || remotePlayback) {
return new Intent(context, MainActivity.class).putExtra(MainActivity.EXTRA_OPEN_PLAYER, true);
} else {
Intent i = new Intent(context, VideoplayerActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
return i;
}
}
}

View File

@ -71,6 +71,8 @@ android {
}
dependencies {
implementation project(':ui:app-start-intent')
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation 'androidx.documentfile:documentfile:1.0.1'

View File

@ -30,8 +30,6 @@ public class ClientConfig {
public static DownloadServiceCallbacks downloadServiceCallbacks;
public static PlaybackServiceCallbacks playbackServiceCallbacks;
public static CastCallbacks castCallbacks;
private static boolean initialized = false;

View File

@ -1,22 +0,0 @@
package de.danoeh.antennapod.core;
import android.content.Context;
import android.content.Intent;
import de.danoeh.antennapod.core.feed.MediaType;
/**
* Callbacks for the PlaybackService of the core module
*/
public interface PlaybackServiceCallbacks {
/**
* Returns an intent which starts an audio- or videoplayer, depending on the
* type of media that is being played.
*
* @param mediaType The type of media that is being played.
* @param remotePlayback true if the media is played on a remote device.
* @return A non-null activity intent.
*/
Intent getPlayerActivityIntent(Context context, MediaType mediaType, boolean remotePlayback);
}

View File

@ -50,7 +50,6 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.MessageEvent;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
@ -81,6 +80,8 @@ import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.core.widget.WidgetUpdater;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.appstartintent.VideoPlayerActivityStarter;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -245,24 +246,31 @@ public class PlaybackService extends MediaBrowserServiceCompat {
* running, the type of the last played media will be looked up.
*/
public static Intent getPlayerActivityIntent(Context context) {
boolean showVideoPlayer;
if (isRunning) {
return ClientConfig.playbackServiceCallbacks.getPlayerActivityIntent(context, currentMediaType, isCasting);
showVideoPlayer = currentMediaType == MediaType.VIDEO && !isCasting;
} else {
if (PlaybackPreferences.getCurrentEpisodeIsVideo()) {
return ClientConfig.playbackServiceCallbacks.getPlayerActivityIntent(context, MediaType.VIDEO, isCasting);
} else {
return ClientConfig.playbackServiceCallbacks.getPlayerActivityIntent(context, MediaType.AUDIO, isCasting);
}
showVideoPlayer = PlaybackPreferences.getCurrentEpisodeIsVideo();
}
if (showVideoPlayer) {
return new VideoPlayerActivityStarter(context).getIntent();
} else {
return new MainActivityStarter(context).withOpenPlayer().getIntent();
}
}
/**
* Same as getPlayerActivityIntent(context), but here the type of activity
* Same as {@link #getPlayerActivityIntent(Context)}, but here the type of activity
* depends on the FeedMedia that is provided as an argument.
*/
public static Intent getPlayerActivityIntent(Context context, Playable media) {
MediaType mt = media.getMediaType();
return ClientConfig.playbackServiceCallbacks.getPlayerActivityIntent(context, mt, isCasting);
if (media.getMediaType() == MediaType.VIDEO && !isCasting) {
return new VideoPlayerActivityStarter(context).getIntent();
} else {
return new MainActivityStarter(context).withOpenPlayer().getIntent();
}
}
@Override
@ -796,7 +804,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public WidgetUpdater.WidgetState requestWidgetState() {
return new WidgetUpdater.WidgetState(getPlayable(), getStatus(),
getCurrentPosition(), getDuration(), getCurrentPlaybackSpeed());
getCurrentPosition(), getDuration(), getCurrentPlaybackSpeed(), isCasting());
}
@Override

View File

@ -19,15 +19,17 @@ import com.bumptech.glide.request.RequestOptions;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.receiver.PlayerWidget;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.appstartintent.VideoPlayerActivityStarter;
/**
* Updates the state of the player widget.
@ -41,17 +43,20 @@ public abstract class WidgetUpdater {
final int position;
final int duration;
final float playbackSpeed;
final boolean isCasting;
public WidgetState(Playable media, PlayerStatus status, int position, int duration, float playbackSpeed) {
public WidgetState(Playable media, PlayerStatus status, int position, int duration,
float playbackSpeed, boolean isCasting) {
this.media = media;
this.status = status;
this.position = position;
this.duration = duration;
this.playbackSpeed = playbackSpeed;
this.isCasting = isCasting;
}
public WidgetState(PlayerStatus status) {
this(null, status, Playable.INVALID_TIME, Playable.INVALID_TIME, 1.0f);
this(null, status, Playable.INVALID_TIME, Playable.INVALID_TIME, 1.0f, false);
}
}
@ -65,8 +70,14 @@ public abstract class WidgetUpdater {
ComponentName playerWidget = new ComponentName(context, PlayerWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
int[] widgetIds = manager.getAppWidgetIds(playerWidget);
final PendingIntent startMediaPlayer = PendingIntent.getActivity(context, R.id.pending_intent_player_activity,
PlaybackService.getPlayerActivityIntent(context), PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent startMediaPlayer;
if (widgetState.media != null && widgetState.media.getMediaType() == MediaType.VIDEO
&& !widgetState.isCasting) {
startMediaPlayer = new VideoPlayerActivityStarter(context).getPendingIntent();
} else {
startMediaPlayer = new MainActivityStarter(context).withOpenPlayer().getPendingIntent();
}
RemoteViews views;
views = new RemoteViews(context.getPackageName(), R.layout.player_widget);

View File

@ -5,6 +5,7 @@ import android.content.Intent;
import androidx.annotation.NonNull;
import androidx.core.app.SafeJobIntentService;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.playback.Playable;
@ -24,7 +25,8 @@ public class WidgetUpdaterJobService extends SafeJobIntentService {
Playable media = Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext());
if (media != null) {
WidgetUpdater.updateWidget(this, new WidgetUpdater.WidgetState(media, PlayerStatus.STOPPED,
media.getPosition(), media.getDuration(), PlaybackSpeedUtils.getCurrentPlaybackSpeed(media)));
media.getPosition(), media.getDuration(), PlaybackSpeedUtils.getCurrentPlaybackSpeed(media),
PlaybackPreferences.getCurrentEpisodeIsStream()));
} else {
WidgetUpdater.updateWidget(this, new WidgetUpdater.WidgetState(PlayerStatus.STOPPED));
}

View File

@ -23,14 +23,4 @@
<item name="notification_auto_download_report" type="id"/>
<item name="notification_playing" type="id"/>
<item name="notification_streaming_confirmation" type="id"/>
<!-- PendingIntent objects that use the same action but different extras need to use a unique request code -->
<item name="pending_intent_download_service_notification" type="id"/>
<item name="pending_intent_download_service_auth" type="id"/>
<item name="pending_intent_download_service_report" type="id"/>
<item name="pending_intent_download_service_autodownload_report" type="id"/>
<item name="pending_intent_allow_stream_always" type="id"/>
<item name="pending_intent_allow_stream_this_time" type="id"/>
<item name="pending_intent_player_activity" type="id"/>
<item name="pending_intent_sync_error" type="id"/>
</resources>

View File

@ -36,8 +36,6 @@ public class ClientConfig {
public static DownloadServiceCallbacks downloadServiceCallbacks;
public static PlaybackServiceCallbacks playbackServiceCallbacks;
public static CastCallbacks castCallbacks;
private static boolean initialized = false;

View File

@ -1 +1,3 @@
include ':app', ':core'
include ':app'
include ':core'
include ':ui:app-start-intent'

3
ui/README.md Normal file
View File

@ -0,0 +1,3 @@
# :ui
This folder contains modules that display or directly interact with the UI.

View File

@ -0,0 +1,3 @@
# :ui:app-start-intent
This module provides classes that can start the main activities of the app with specific arguments. It does not require a dependency on the actual implementation of the activities, so it can be used to decouple the services from the UI.

View File

@ -0,0 +1,50 @@
apply plugin: "com.android.library"
android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled false
testApplicationId "de.danoeh.antennapod.core.tests"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android.txt")
}
debug {
// debug build has method count over 64k single-dex threshold.
// For building debug build to use on Android < 21 (pre-Android 5) devices,
// you need to manually change class
// de.danoeh.antennapod.PodcastApp to extend MultiDexApplication .
// See Issue #2813
multiDexEnabled true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
lintOptions {
warningsAsErrors true
abortOnError true
}
}
dependencies {
annotationProcessor "androidx.annotation:annotation:$annotationVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
}

View File

@ -0,0 +1 @@
<manifest package="de.danoeh.antennapod.ui.appstartintent" />

View File

@ -0,0 +1,41 @@
package de.danoeh.antennapod.ui.appstartintent;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
/**
* Launches the main activity of the app with specific arguments.
* Does not require a dependency on the actual implementation of the activity.
*/
public class MainActivityStarter {
public static final String INTENT = "de.danoeh.antennapod.intents.MAIN_ACTIVITY";
public static final String EXTRA_OPEN_PLAYER = "open_player";
private final Intent intent;
private final Context context;
public MainActivityStarter(Context context) {
this.context = context;
intent = new Intent(INTENT);
intent.setPackage(context.getPackageName());
}
public Intent getIntent() {
return intent;
}
public PendingIntent getPendingIntent() {
return PendingIntent.getActivity(context, R.id.pending_intent_player_activity,
getIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
}
public void start() {
context.startActivity(getIntent());
}
public MainActivityStarter withOpenPlayer() {
intent.putExtra(EXTRA_OPEN_PLAYER, true);
return this;
}
}

View File

@ -0,0 +1,38 @@
package de.danoeh.antennapod.ui.appstartintent;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
/**
* Launches the video player activity of the app with specific arguments.
* Does not require a dependency on the actual implementation of the activity.
*/
public class VideoPlayerActivityStarter {
public static final String INTENT = "de.danoeh.antennapod.intents.VIDEO_PLAYER";
private final Intent intent;
private final Context context;
public VideoPlayerActivityStarter(Context context) {
this.context = context;
intent = new Intent(INTENT);
intent.setPackage(context.getPackageName());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
}
public Intent getIntent() {
return intent;
}
public PendingIntent getPendingIntent() {
return PendingIntent.getActivity(context, R.id.pending_intent_video_player,
getIntent(), PendingIntent.FLAG_UPDATE_CURRENT);
}
public void start() {
context.startActivity(getIntent());
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="pending_intent_download_service_notification" type="id"/>
<item name="pending_intent_download_service_auth" type="id"/>
<item name="pending_intent_download_service_report" type="id"/>
<item name="pending_intent_download_service_autodownload_report" type="id"/>
<item name="pending_intent_allow_stream_always" type="id"/>
<item name="pending_intent_allow_stream_this_time" type="id"/>
<item name="pending_intent_player_activity" type="id"/>
<item name="pending_intent_video_player" type="id"/>
<item name="pending_intent_sync_error" type="id"/>
</resources>