From fe6e60cd6734c9adca2b557d4d647efb02e76597 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 5 Jun 2020 09:02:37 +0100 Subject: [PATCH] implement background playback with control notification --- .../java/io/lbry/browser/MainActivity.java | 80 ++++++++++++++++--- .../ui/findcontent/FileViewFragment.java | 9 ++- 2 files changed, 77 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 761dbc45..0b73b93e 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -16,6 +16,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.TypedArray; import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -44,9 +45,12 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import com.bumptech.glide.Glide; +import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.ext.cast.CastPlayer; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; +import com.google.android.exoplayer2.ui.PlayerNotificationManager; import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.upstream.cache.Cache; import com.google.android.gms.cast.framework.CastContext; @@ -99,6 +103,7 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -307,6 +312,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private static boolean appStarted; private boolean serviceRunning; private CheckSdkReadyTask checkSdkReadyTask; + private PlayerNotificationManager playerNotificationManager; private MediaSessionCompat mediaSession; private boolean receivedStopService; private ActionBarDrawerToggle toggle; @@ -346,11 +352,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private static final int STARTUP_STAGE_SUBSCRIPTIONS_LOADED = 6; private static final int STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED = 7; - public boolean isDarkMode() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - return sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false); - } - @Override protected void onCreate(Bundle savedInstanceState) { // workaround to fix dark theme because https://issuetracker.google.com/issues/37124582 @@ -392,6 +393,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); + playerNotificationManager = new PlayerNotificationManager( + this, LbrynetService.NOTIFICATION_CHANNEL_ID, PLAYBACK_NOTIFICATION_ID, new PlayerNotificationDescriptionAdapter()); + // TODO: Check Google Play Services availability // castContext = CastContext.getSharedInstance(this); @@ -529,6 +533,16 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener }); } + public boolean isDarkMode() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + return sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false); + } + + public boolean isBackgroundPlaybackEnabled() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + return sp.getBoolean(PREFERENCE_KEY_BACKGROUND_PLAYBACK, false); + } + private void initSpecialRouteMap() { specialRouteFragmentClassMap = new HashMap<>(); specialRouteFragmentClassMap.put("about", AboutFragment.class); @@ -899,12 +913,15 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener if (dbHelper != null) { dbHelper.close(); } - if (mediaSession != null) { + if (mediaSession != null && !isBackgroundPlaybackEnabled()) { mediaSession.release(); } - stopExoplayer(); - nowPlayingClaim = null; - nowPlayingClaimUrl = null; + if (!isBackgroundPlaybackEnabled()) { + playerNotificationManager.setPlayer(null); + stopExoplayer(); + nowPlayingClaim = null; + nowPlayingClaimUrl = null; + } appStarted = false; if (!keepSdkBackground()) { @@ -1002,7 +1019,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener @Override protected void onPause() { - if (!enteringPIPMode && !inPictureInPictureMode && appPlayer != null) { + if (!enteringPIPMode && !inPictureInPictureMode && appPlayer != null && !isBackgroundPlaybackEnabled()) { appPlayer.setPlayWhenReady(false); } super.onPause(); @@ -1593,6 +1610,47 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener mediaSession.setActive(true); } + private static final String CHANNEL_ID_PLAYBACK = "io.lbry.browser.LBRY_PLAYBACK_CHANNEL"; + private static final int PLAYBACK_NOTIFICATION_ID = 3; + + public void initPlaybackNotification() { + if (isBackgroundPlaybackEnabled()) { + playerNotificationManager.setPlayer(MainActivity.appPlayer); + if (mediaSession != null) { + playerNotificationManager.setMediaSessionToken(mediaSession.getSessionToken()); + } + } + } + + private class PlayerNotificationDescriptionAdapter implements PlayerNotificationManager.MediaDescriptionAdapter { + + @Override + public CharSequence getCurrentContentTitle(Player player) { + return nowPlayingClaim != null ? nowPlayingClaim.getTitle() : ""; + } + + @Nullable + @Override + public PendingIntent createCurrentContentIntent(Player player) { + Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(nowPlayingClaimUrl)); + launchIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); + PendingIntent intent = PendingIntent.getActivity(MainActivity.this, 0, launchIntent, 0); + return intent; + } + + @Nullable + @Override + public CharSequence getCurrentContentText(Player player) { + return nowPlayingClaim != null && nowPlayingClaim.getSigningChannel() != null ? nowPlayingClaim.getSigningChannel().getTitleOrName() : null; + } + + @Nullable + @Override + public Bitmap getCurrentLargeIcon(Player player, PlayerNotificationManager.BitmapCallback callback) { + return null; + } + } + public void showFloatingWalletBalance() { findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE); } @@ -2793,7 +2851,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } protected void onStop() { - if (appPlayer != null && inPictureInPictureMode) { + if (appPlayer != null && inPictureInPictureMode && !isBackgroundPlaybackEnabled()) { appPlayer.setPlayWhenReady(false); } super.onStop(); diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java index cc5140ff..12d8afd1 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java @@ -1520,12 +1520,19 @@ public class FileViewFragment extends BaseFragment implements new SimpleCache(context.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 256), new ExoDatabaseProvider(context)); if (context instanceof MainActivity) { - ((MainActivity) context).initMediaSession(); + MainActivity activity = (MainActivity) context; + activity.initMediaSession(); + activity.initPlaybackNotification(); } newPlayerCreated = true; } + if (context instanceof MainActivity) { + MainActivity activity = (MainActivity) context; + activity.initPlaybackNotification(); + } + View root = getView(); if (root != null) { PlayerView view = root.findViewById(R.id.file_view_exoplayer_view);