mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	PlayerService: Convert to kotlin (mechanical)
This commit is contained in:
		| @@ -16,103 +16,101 @@ | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| package org.schabi.newpipe.player | ||||
| 
 | ||||
| package org.schabi.newpipe.player; | ||||
| 
 | ||||
| import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.Bundle; | ||||
| import android.os.IBinder; | ||||
| import android.support.v4.media.MediaBrowserCompat; | ||||
| import android.support.v4.media.session.MediaSessionCompat; | ||||
| import android.util.Log; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.core.app.ServiceCompat; | ||||
| import androidx.media.MediaBrowserServiceCompat; | ||||
| 
 | ||||
| import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; | ||||
| 
 | ||||
| import org.schabi.newpipe.ktx.BundleKt; | ||||
| import org.schabi.newpipe.player.mediabrowser.MediaBrowserImpl; | ||||
| import org.schabi.newpipe.player.mediabrowser.MediaBrowserPlaybackPreparer; | ||||
| import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi; | ||||
| import org.schabi.newpipe.player.notification.NotificationPlayerUi; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
| 
 | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.util.List; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.os.Binder | ||||
| import android.os.Bundle | ||||
| import android.os.IBinder | ||||
| import android.support.v4.media.MediaBrowserCompat | ||||
| import android.support.v4.media.session.MediaSessionCompat | ||||
| import android.util.Log | ||||
| import androidx.core.app.ServiceCompat | ||||
| import androidx.media.MediaBrowserServiceCompat | ||||
| import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector | ||||
| import org.schabi.newpipe.ktx.toDebugString | ||||
| import org.schabi.newpipe.player.mediabrowser.MediaBrowserImpl | ||||
| import org.schabi.newpipe.player.mediabrowser.MediaBrowserPlaybackPreparer | ||||
| import org.schabi.newpipe.player.mediasession.MediaSessionPlayerUi | ||||
| import org.schabi.newpipe.player.notification.NotificationPlayerUi | ||||
| import org.schabi.newpipe.util.Localization | ||||
| import org.schabi.newpipe.util.ThemeHelper | ||||
| import java.lang.ref.WeakReference | ||||
| import java.util.function.BiConsumer | ||||
| import java.util.function.Consumer | ||||
| 
 | ||||
| /** | ||||
|  * One service for all players. | ||||
|  */ | ||||
| public final class PlayerService extends MediaBrowserServiceCompat { | ||||
|     private static final String TAG = PlayerService.class.getSimpleName(); | ||||
|     private static final boolean DEBUG = Player.DEBUG; | ||||
| 
 | ||||
|     public static final String SHOULD_START_FOREGROUND_EXTRA = "should_start_foreground_extra"; | ||||
|     public static final String BIND_PLAYER_HOLDER_ACTION = "bind_player_holder_action"; | ||||
| 
 | ||||
| class PlayerService : MediaBrowserServiceCompat() { | ||||
|     // These objects are used to cleanly separate the Service implementation (in this file) and the | ||||
|     // media browser and playback preparer implementations. At the moment the playback preparer is | ||||
|     // only used in conjunction with the media browser. | ||||
|     private MediaBrowserImpl mediaBrowserImpl; | ||||
|     private MediaBrowserPlaybackPreparer mediaBrowserPlaybackPreparer; | ||||
|     private var mediaBrowserImpl: MediaBrowserImpl? = null | ||||
|     private var mediaBrowserPlaybackPreparer: MediaBrowserPlaybackPreparer? = null | ||||
| 
 | ||||
|     // these are instantiated in onCreate() as per | ||||
|     // https://developer.android.com/training/cars/media#browser_workflow | ||||
|     private MediaSessionCompat mediaSession; | ||||
|     private MediaSessionConnector sessionConnector; | ||||
| 
 | ||||
|     @Nullable | ||||
|     private Player player; | ||||
| 
 | ||||
|     private final IBinder mBinder = new PlayerService.LocalBinder(this); | ||||
|     private var mediaSession: MediaSessionCompat? = null | ||||
|     private var sessionConnector: MediaSessionConnector? = null | ||||
| 
 | ||||
|     /** | ||||
|      * The parameter taken by this {@link Consumer} can be null to indicate the player is being | ||||
|      * @return the current active player instance. May be null, since the player service can outlive | ||||
|      * the player e.g. to respond to Android Auto media browser queries. | ||||
|      */ | ||||
|     var player: Player? = null | ||||
|         private set | ||||
| 
 | ||||
|     private val mBinder: IBinder = LocalBinder(this) | ||||
| 
 | ||||
|     /** | ||||
|      * The parameter taken by this [Consumer] can be null to indicate the player is being | ||||
|      * stopped. | ||||
|      */ | ||||
|     @Nullable | ||||
|     private Consumer<Player> onPlayerStartedOrStopped = null; | ||||
| 
 | ||||
|     private var onPlayerStartedOrStopped: Consumer<Player?>? = null | ||||
| 
 | ||||
|     //region Service lifecycle | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|     override fun onCreate() { | ||||
|         super.onCreate() | ||||
| 
 | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "onCreate() called"); | ||||
|             Log.d(TAG, "onCreate() called") | ||||
|         } | ||||
|         assureCorrectAppLanguage(this); | ||||
|         ThemeHelper.setTheme(this); | ||||
|         Localization.assureCorrectAppLanguage(this) | ||||
|         ThemeHelper.setTheme(this) | ||||
| 
 | ||||
|         mediaBrowserImpl = new MediaBrowserImpl(this, this::notifyChildrenChanged); | ||||
|         mediaBrowserImpl = MediaBrowserImpl( | ||||
|             this, | ||||
|             Consumer { parentId: String? -> | ||||
|                 this.notifyChildrenChanged( | ||||
|                     parentId!! | ||||
|                 ) | ||||
|             } | ||||
|         ) | ||||
| 
 | ||||
|         // see https://developer.android.com/training/cars/media#browser_workflow | ||||
|         mediaSession = new MediaSessionCompat(this, "MediaSessionPlayerServ"); | ||||
|         setSessionToken(mediaSession.getSessionToken()); | ||||
|         sessionConnector = new MediaSessionConnector(mediaSession); | ||||
|         sessionConnector.setMetadataDeduplicationEnabled(true); | ||||
|         mediaSession = MediaSessionCompat(this, "MediaSessionPlayerServ") | ||||
|         setSessionToken(mediaSession!!.getSessionToken()) | ||||
|         sessionConnector = MediaSessionConnector(mediaSession!!) | ||||
|         sessionConnector!!.setMetadataDeduplicationEnabled(true) | ||||
| 
 | ||||
|         mediaBrowserPlaybackPreparer = new MediaBrowserPlaybackPreparer( | ||||
|         mediaBrowserPlaybackPreparer = MediaBrowserPlaybackPreparer( | ||||
|             this, | ||||
|                 sessionConnector::setCustomErrorMessage, | ||||
|                 () -> sessionConnector.setCustomErrorMessage(null), | ||||
|                 (playWhenReady) -> { | ||||
|             BiConsumer { message: String?, code: Int? -> | ||||
|                 sessionConnector!!.setCustomErrorMessage( | ||||
|                     message, | ||||
|                     code!! | ||||
|                 ) | ||||
|             }, | ||||
|             Runnable { sessionConnector!!.setCustomErrorMessage(null) }, | ||||
|             Consumer { playWhenReady: Boolean? -> | ||||
|                 if (player != null) { | ||||
|                         player.onPrepare(); | ||||
|                     player!!.onPrepare() | ||||
|                 } | ||||
|             } | ||||
|         ); | ||||
|         sessionConnector.setPlaybackPreparer(mediaBrowserPlaybackPreparer); | ||||
|         ) | ||||
|         sessionConnector!!.setPlaybackPreparer(mediaBrowserPlaybackPreparer) | ||||
| 
 | ||||
|         // Note: you might be tempted to create the player instance and call startForeground here, | ||||
|         // but be aware that the Android system might start the service just to perform media | ||||
| @@ -123,22 +121,26 @@ public final class PlayerService extends MediaBrowserServiceCompat { | ||||
|         // useless notification. | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int onStartCommand(final Intent intent, final int flags, final int startId) { | ||||
|     override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "onStartCommand() called with: intent = [" + intent | ||||
|                     + "], extras = [" + BundleKt.toDebugString(intent.getExtras()) | ||||
|                     + "], flags = [" + flags + "], startId = [" + startId + "]"); | ||||
|             Log.d( | ||||
|                 TAG, | ||||
|                 ( | ||||
|                     "onStartCommand() called with: intent = [" + intent + | ||||
|                         "], extras = [" + intent.getExtras().toDebugString() + | ||||
|                         "], flags = [" + flags + "], startId = [" + startId + "]" | ||||
|                     ) | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         // All internal NewPipe intents used to interact with the player, that are sent to the | ||||
|         // PlayerService using startForegroundService(), will have SHOULD_START_FOREGROUND_EXTRA, | ||||
|         // to ensure startForeground() is called (otherwise Android will force-crash the app). | ||||
|         if (intent.getBooleanExtra(SHOULD_START_FOREGROUND_EXTRA, false)) { | ||||
|             final boolean playerWasNull = (player == null); | ||||
|             val playerWasNull = (player == null) | ||||
|             if (playerWasNull) { | ||||
|                 // make sure the player exists, in case the service was resumed | ||||
|                 player = new Player(this, mediaSession, sessionConnector); | ||||
|                 player = Player(this, mediaSession!!, sessionConnector!!) | ||||
|             } | ||||
| 
 | ||||
|             // Be sure that the player notification is set and the service is started in foreground, | ||||
| @@ -148,107 +150,112 @@ public final class PlayerService extends MediaBrowserServiceCompat { | ||||
|             // no one already and starting the service in foreground should not create any issues. | ||||
|             // If the service is already started in foreground, requesting it to be started | ||||
|             // shouldn't do anything. | ||||
|             player.UIs().getOpt(NotificationPlayerUi.class) | ||||
|                     .ifPresent(NotificationPlayerUi::createNotificationAndStartForeground); | ||||
|             player!!.UIs().getOpt<NotificationPlayerUi>(NotificationPlayerUi::class.java) | ||||
|                 .ifPresent(Consumer { obj: NotificationPlayerUi? -> obj!!.createNotificationAndStartForeground() }) | ||||
| 
 | ||||
|             if (playerWasNull && onPlayerStartedOrStopped != null) { | ||||
|                 // notify that a new player was created (but do it after creating the foreground | ||||
|                 // notification just to make sure we don't incur, due to slowness, in | ||||
|                 // "Context.startForegroundService() did not then call Service.startForeground()") | ||||
|                 onPlayerStartedOrStopped.accept(player); | ||||
|                 onPlayerStartedOrStopped!!.accept(player) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()) | ||||
|                 && (player == null || player.getPlayQueue() == null)) { | ||||
|         if (Intent.ACTION_MEDIA_BUTTON == intent.getAction() && | ||||
|             (player == null || player!!.getPlayQueue() == null) | ||||
|         ) { | ||||
|             /* | ||||
|             No need to process media button's actions if the player is not working, otherwise | ||||
|             the player service would strangely start with nothing to play | ||||
|             Stop the service in this case, which will be removed from the foreground and its | ||||
|             notification cancelled in its destruction | ||||
|              */ | ||||
|             destroyPlayerAndStopService(); | ||||
|             return START_NOT_STICKY; | ||||
|             destroyPlayerAndStopService() | ||||
|             return START_NOT_STICKY | ||||
|         } | ||||
| 
 | ||||
|         if (player != null) { | ||||
|             player.handleIntent(intent); | ||||
|             player.UIs().getOpt(MediaSessionPlayerUi.class) | ||||
|                     .ifPresent(ui -> ui.handleMediaButtonIntent(intent)); | ||||
|             player!!.handleIntent(intent) | ||||
|             player!!.UIs().getOpt<MediaSessionPlayerUi>(MediaSessionPlayerUi::class.java) | ||||
|                 .ifPresent( | ||||
|                     Consumer { ui: MediaSessionPlayerUi? -> | ||||
|                         ui!!.handleMediaButtonIntent( | ||||
|                             intent | ||||
|                         ) | ||||
|                     } | ||||
|                 ) | ||||
|         } | ||||
| 
 | ||||
|         return START_NOT_STICKY; | ||||
|         return START_NOT_STICKY | ||||
|     } | ||||
| 
 | ||||
|     public void stopForImmediateReusing() { | ||||
|     fun stopForImmediateReusing() { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "stopForImmediateReusing() called"); | ||||
|             Log.d(TAG, "stopForImmediateReusing() called") | ||||
|         } | ||||
| 
 | ||||
|         if (player != null && !player.exoPlayerIsNull()) { | ||||
|         if (player != null && !player!!.exoPlayerIsNull()) { | ||||
|             // Releases wifi & cpu, disables keepScreenOn, etc. | ||||
|             // We can't just pause the player here because it will make transition | ||||
|             // from one stream to a new stream not smooth | ||||
|             player.smoothStopForImmediateReusing(); | ||||
|             player!!.smoothStopForImmediateReusing() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onTaskRemoved(final Intent rootIntent) { | ||||
|         super.onTaskRemoved(rootIntent); | ||||
|         if (player != null && !player.videoPlayerSelected()) { | ||||
|             return; | ||||
|     override fun onTaskRemoved(rootIntent: Intent?) { | ||||
|         super.onTaskRemoved(rootIntent) | ||||
|         if (player != null && !player!!.videoPlayerSelected()) { | ||||
|             return | ||||
|         } | ||||
|         onDestroy(); | ||||
|         onDestroy() | ||||
|         // Unload from memory completely | ||||
|         Runtime.getRuntime().halt(0); | ||||
|         Runtime.getRuntime().halt(0) | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|     override fun onDestroy() { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "destroy() called"); | ||||
|             Log.d(TAG, "destroy() called") | ||||
|         } | ||||
|         super.onDestroy(); | ||||
|         super.onDestroy() | ||||
| 
 | ||||
|         cleanup(); | ||||
|         cleanup() | ||||
| 
 | ||||
|         mediaBrowserPlaybackPreparer.dispose(); | ||||
|         mediaSession.release(); | ||||
|         mediaBrowserImpl.dispose(); | ||||
|         mediaBrowserPlaybackPreparer!!.dispose() | ||||
|         mediaSession!!.release() | ||||
|         mediaBrowserImpl!!.dispose() | ||||
|     } | ||||
| 
 | ||||
|     private void cleanup() { | ||||
|     private fun cleanup() { | ||||
|         if (player != null) { | ||||
|             if (onPlayerStartedOrStopped != null) { | ||||
|                 // notify that the player is being destroyed | ||||
|                 onPlayerStartedOrStopped.accept(null); | ||||
|                 onPlayerStartedOrStopped!!.accept(null) | ||||
|             } | ||||
|             player.destroy(); | ||||
|             player = null; | ||||
|             player!!.destroy() | ||||
|             player = null | ||||
|         } | ||||
| 
 | ||||
|         // Should already be handled by MediaSessionPlayerUi, but just to be sure. | ||||
|         mediaSession.setActive(false); | ||||
|         mediaSession!!.setActive(false) | ||||
| 
 | ||||
|         // Should already be handled by NotificationUtil.cancelNotificationAndStopForeground() in | ||||
|         // NotificationPlayerUi, but let's make sure that the foreground service is stopped. | ||||
|         ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE); | ||||
|         ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Destroys the player and allows the player instance to be garbage collected. Sets the media | ||||
|      * session to inactive. Stops the foreground service and removes the player notification | ||||
|      * associated with it. Tries to stop the {@link PlayerService} completely, but this step will | ||||
|      * associated with it. Tries to stop the [PlayerService] completely, but this step will | ||||
|      * have no effect in case some service connection still uses the service (e.g. the Android Auto | ||||
|      * system accesses the media browser even when no player is running). | ||||
|      */ | ||||
|     public void destroyPlayerAndStopService() { | ||||
|     fun destroyPlayerAndStopService() { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "destroyPlayerAndStopService() called"); | ||||
|             Log.d(TAG, "destroyPlayerAndStopService() called") | ||||
|         } | ||||
| 
 | ||||
|         cleanup(); | ||||
|         cleanup() | ||||
| 
 | ||||
|         // This only really stops the service if there are no other service connections (see docs): | ||||
|         // for example the (Android Auto) media browser binder will block stopService(). | ||||
| @@ -256,95 +263,96 @@ public final class PlayerService extends MediaBrowserServiceCompat { | ||||
|         // If we were to call stopSelf(), then the service would be surely stopped (regardless of | ||||
|         // other service connections), but this would be a waste of resources since the service | ||||
|         // would be immediately restarted by those same connections to perform the queries. | ||||
|         stopService(new Intent(this, PlayerService.class)); | ||||
|         stopService(Intent(this, PlayerService::class.java)) | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void attachBaseContext(final Context base) { | ||||
|         super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(base)); | ||||
|     override fun attachBaseContext(base: Context?) { | ||||
|         super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(base)) | ||||
|     } | ||||
| 
 | ||||
|     //endregion | ||||
| 
 | ||||
|     //region Bind | ||||
|     @Override | ||||
|     public IBinder onBind(final Intent intent) { | ||||
|     override fun onBind(intent: Intent): IBinder? { | ||||
|         if (DEBUG) { | ||||
|             Log.d(TAG, "onBind() called with: intent = [" + intent | ||||
|                     + "], extras = [" + BundleKt.toDebugString(intent.getExtras()) + "]"); | ||||
|             Log.d( | ||||
|                 TAG, | ||||
|                 ( | ||||
|                     "onBind() called with: intent = [" + intent + | ||||
|                         "], extras = [" + intent.getExtras().toDebugString() + "]" | ||||
|                     ) | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|         if (BIND_PLAYER_HOLDER_ACTION.equals(intent.getAction())) { | ||||
|         if (BIND_PLAYER_HOLDER_ACTION == intent.getAction()) { | ||||
|             // Note that this binder might be reused multiple times while the service is alive, even | ||||
|             // after unbind() has been called: https://stackoverflow.com/a/8794930 . | ||||
|             return mBinder; | ||||
| 
 | ||||
|         } else if (MediaBrowserServiceCompat.SERVICE_INTERFACE.equals(intent.getAction())) { | ||||
|             return mBinder | ||||
|         } else if (SERVICE_INTERFACE == intent.getAction()) { | ||||
|             // MediaBrowserService also uses its own binder, so for actions related to the media | ||||
|             // browser service, pass the onBind to the superclass. | ||||
|             return super.onBind(intent); | ||||
| 
 | ||||
|             return super.onBind(intent) | ||||
|         } else { | ||||
|             // This is an unknown request, avoid returning any binder to not leak objects. | ||||
|             return null; | ||||
|             return null | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static class LocalBinder extends Binder { | ||||
|         private final WeakReference<PlayerService> playerService; | ||||
|     class LocalBinder internal constructor(playerService: PlayerService?) : Binder() { | ||||
|         private val playerService: WeakReference<PlayerService?> | ||||
| 
 | ||||
|         LocalBinder(final PlayerService playerService) { | ||||
|             this.playerService = new WeakReference<>(playerService); | ||||
|         init { | ||||
|             this.playerService = WeakReference<PlayerService?>(playerService) | ||||
|         } | ||||
| 
 | ||||
|         public PlayerService getService() { | ||||
|             return playerService.get(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return the current active player instance. May be null, since the player service can outlive | ||||
|      * the player e.g. to respond to Android Auto media browser queries. | ||||
|      */ | ||||
|     @Nullable | ||||
|     public Player getPlayer() { | ||||
|         return player; | ||||
|         val service: PlayerService? | ||||
|             get() = playerService.get() | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sets the listener that will be called when the player is started or stopped. If a | ||||
|      * {@code null} listener is passed, then the current listener will be unset. The parameter taken | ||||
|      * by the {@link Consumer} can be null to indicate that the player is stopping. | ||||
|      * `null` listener is passed, then the current listener will be unset. The parameter taken | ||||
|      * by the [Consumer] can be null to indicate that the player is stopping. | ||||
|      * @param listener the listener to set or unset | ||||
|      */ | ||||
|     public void setPlayerListener(@Nullable final Consumer<Player> listener) { | ||||
|         this.onPlayerStartedOrStopped = listener; | ||||
|     fun setPlayerListener(listener: Consumer<Player?>?) { | ||||
|         this.onPlayerStartedOrStopped = listener | ||||
|         if (listener != null) { | ||||
|             // if there is no player, then `null` will be sent here, to ensure the state is synced | ||||
|             listener.accept(player); | ||||
|             listener.accept(player) | ||||
|         } | ||||
|     } | ||||
|     //endregion | ||||
| 
 | ||||
|     //endregion | ||||
|     //region Media browser | ||||
|     @Override | ||||
|     public BrowserRoot onGetRoot(@NonNull final String clientPackageName, | ||||
|                                  final int clientUid, | ||||
|                                  @Nullable final Bundle rootHints) { | ||||
|     override fun onGetRoot( | ||||
|         clientPackageName: String, | ||||
|         clientUid: Int, | ||||
|         rootHints: Bundle? | ||||
|     ): BrowserRoot { | ||||
|         // TODO check if the accessing package has permission to view data | ||||
|         return mediaBrowserImpl.onGetRoot(clientPackageName, clientUid, rootHints); | ||||
|         return mediaBrowserImpl!!.onGetRoot(clientPackageName, clientUid, rootHints) | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onLoadChildren(@NonNull final String parentId, | ||||
|                                @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) { | ||||
|         mediaBrowserImpl.onLoadChildren(parentId, result); | ||||
|     override fun onLoadChildren( | ||||
|         parentId: String, | ||||
|         result: Result<List<MediaBrowserCompat.MediaItem>> | ||||
|     ) { | ||||
|         mediaBrowserImpl!!.onLoadChildren(parentId, result) | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onSearch(@NonNull final String query, | ||||
|                          final Bundle extras, | ||||
|                          @NonNull final Result<List<MediaBrowserCompat.MediaItem>> result) { | ||||
|         mediaBrowserImpl.onSearch(query, result); | ||||
|     override fun onSearch( | ||||
|         query: String, | ||||
|         extras: Bundle?, | ||||
|         result: Result<List<MediaBrowserCompat.MediaItem>> | ||||
|     ) { | ||||
|         mediaBrowserImpl!!.onSearch(query, result) | ||||
|     } //endregion | ||||
| 
 | ||||
|     companion object { | ||||
|         private val TAG: String = PlayerService::class.java.getSimpleName() | ||||
|         private val DEBUG = Player.DEBUG | ||||
| 
 | ||||
|         const val SHOULD_START_FOREGROUND_EXTRA: String = "should_start_foreground_extra" | ||||
|         const val BIND_PLAYER_HOLDER_ACTION: String = "bind_player_holder_action" | ||||
|     } | ||||
|     //endregion | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Profpatsch
					Profpatsch