MediasessionService के साथ बैकग्राउंड में वीडियो चलाने की सुविधा

अक्सर ऐसा होता है कि ऐप्लिकेशन के फ़ोरग्राउंड में न होने पर भी मीडिया चलाना ज़रूरी होता है. उदाहरण के लिए, जब उपयोगकर्ता अपने डिवाइस को लॉक कर देता है या किसी दूसरे ऐप्लिकेशन का इस्तेमाल करता है, तब भी संगीत प्लेयर आम तौर पर संगीत चलाता रहता है. Media3 लाइब्रेरी में कई इंटरफ़ेस होते हैं. इनकी मदद से, बैकग्राउंड में वीडियो चलाने की सुविधा चालू की जा सकती है.

MediaSessionService का इस्तेमाल करना

बैकग्राउंड में वीडियो चलाने की सुविधा चालू करने के लिए, आपको Player और MediaSession को एक अलग सेवा में शामिल करना चाहिए. इससे डिवाइस पर मीडिया चलता रहता है, भले ही आपका ऐप्लिकेशन फ़ोरग्राउंड में न हो.

MediaSessionService, मीडिया सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाने की अनुमति देता है
पहली इमेज: MediaSessionService की मदद से, मीडिया सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाया जा सकता है

किसी सेवा में प्लेयर को होस्ट करते समय, आपको MediaSessionService का इस्तेमाल करना चाहिए. इसके लिए, MediaSessionService को एक्सटेंड करने वाली क्लास बनाएं और उसके अंदर अपना मीडिया सेशन बनाएं.

MediaSessionService का इस्तेमाल करने से, Google Assistant, सिस्टम मीडिया कंट्रोल, पेरिफ़ेरल डिवाइसों पर मौजूद मीडिया बटन या Wear OS जैसे कंपैनियन डिवाइसों जैसे बाहरी क्लाइंट को आपकी सेवा खोजने, उससे कनेक्ट करने, और प्लेबैक को कंट्रोल करने की सुविधा मिलती है. इसके लिए, आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की गतिविधि को ऐक्सेस करने की ज़रूरत नहीं पड़ती. एक ही समय पर, एक ही MediaSessionService से कई क्लाइंट ऐप्लिकेशन कनेक्ट किए जा सकते हैं. हर ऐप्लिकेशन का अपना MediaController होता है.

सेवा की लाइफ़साइकल लागू करना

आपको अपनी सेवा के लिए, लाइफ़साइकल के दो तरीके लागू करने होंगे:

  • onCreate() को तब कॉल किया जाता है, जब पहला कंट्रोलर कनेक्ट होने वाला होता है और सेवा को इंस्टैंशिएट करके शुरू किया जाता है. यह Player और MediaSession बनाने के लिए सबसे सही जगह है.
  • सेवा बंद होने पर, onDestroy() को कॉल किया जाता है. प्लेयर और सेशन के साथ-साथ, सभी संसाधनों को रिलीज़ करना होगा.

आपके पास onTaskRemoved(Intent) को पसंद के मुताबिक बनाने का विकल्प होता है. इससे यह तय किया जा सकता है कि जब उपयोगकर्ता, हाल ही के टास्क से ऐप्लिकेशन को खारिज करे, तो क्या हो. डिफ़ॉल्ट रूप से, अगर वीडियो चल रहा है, तो सेवा चालू रहती है. ऐसा न होने पर, सेवा बंद हो जाती है.

Kotlin

class PlaybackService : MediaSessionService() {
  private var mediaSession: MediaSession? = null

  // Create your Player and MediaSession in the onCreate lifecycle event
  override fun onCreate() {
    super.onCreate()
    val player = ExoPlayer.Builder(this).build()
    mediaSession = MediaSession.Builder(this, player).build()
  }

  // Remember to release the player and media session in onDestroy
  override fun onDestroy() {
    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }
    super.onDestroy()
  }

  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? =
    mediaSession
}

Java

class PlaybackService extends MediaSessionService {
  private MediaSession mediaSession = null;

  // Create your Player and MediaSession in the onCreate lifecycle event
  @Override
  public void onCreate() {
    super.onCreate();
    ExoPlayer player = new ExoPlayer.Builder(this).build();
    mediaSession = new MediaSession.Builder(this, player).build();
  }

  // Remember to release the player and media session in onDestroy
  @Override
  public void onDestroy() {
    mediaSession.getPlayer().release();
    mediaSession.release();
    mediaSession = null;
    super.onDestroy();
  }

  @Override
  public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
    return mediaSession;
  }
}

बैकग्राउंड में प्लेबैक जारी रखने के बजाय, उपयोगकर्ता के ऐप्लिकेशन को खारिज करने पर, सेवा को किसी भी स्थिति में बंद किया जा सकता है:

Kotlin

@OptIn(UnstableApi::class)
override fun onTaskRemoved(rootIntent: Intent?) {
  pauseAllPlayersAndStopSelf()
}

Java

@OptIn(markerClass = UnstableApi.class)
@Override
public void onTaskRemoved(@Nullable Intent rootIntent) {
  pauseAllPlayersAndStopSelf();
}

onTaskRemoved को मैन्युअल तरीके से लागू करने के लिए, isPlaybackOngoing() का इस्तेमाल किया जा सकता है. इससे यह पता लगाया जा सकता है कि प्लेबैक जारी है या नहीं और फ़ोरग्राउंड सेवा शुरू हुई है या नहीं.

मीडिया सेशन का ऐक्सेस देना

onGetSession() तरीके को बदलें, ताकि दूसरे क्लाइंट को आपके मीडिया सेशन का ऐक्सेस मिल सके. यह सेशन, सेवा बनाते समय बनाया गया था.

Kotlin

class PlaybackService : MediaSessionService() {

  // [...] lifecycle methods omitted

  override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? =
    mediaSession
}

Java

class PlaybackService extends MediaSessionService {

  // [...] lifecycle methods omitted

  @Override
  public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
    return mediaSession;
  }
}

मेनिफ़ेस्ट में सेवा की जानकारी दें

किसी ऐप्लिकेशन को प्लेबैक फ़ोरग्राउंड सेवा चलाने के लिए, FOREGROUND_SERVICE और FOREGROUND_SERVICE_MEDIA_PLAYBACK अनुमतियों की ज़रूरत होती है:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

आपको मेनिफ़ेस्ट में अपनी Service क्लास का एलान भी करना होगा. इसके लिए, आपको MediaSessionService के इंटेंट फ़िल्टर और foregroundServiceType का इस्तेमाल करना होगा. इसमें mediaPlayback शामिल होना चाहिए.

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

MediaController का इस्तेमाल करके प्लेबैक कंट्रोल करना

जिस ऐक्टिविटी या फ़्रैगमेंट में आपके प्लेयर का यूज़र इंटरफ़ेस (यूआई) मौजूद है उसमें MediaController का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) और मीडिया सेशन के बीच लिंक बनाया जा सकता है. आपका यूज़र इंटरफ़ेस (यूआई), मीडिया कंट्रोलर का इस्तेमाल करके, सेशन के दौरान यूज़र इंटरफ़ेस (यूआई) से प्लेयर को निर्देश भेजता है. MediaController बनाने और इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, MediaController बनाएं गाइड देखें.

MediaController के निर्देशों को मैनेज करना

MediaSession को कंट्रोलर से निर्देश मिलते हैं. इसके लिए, वह MediaSession.Callback का इस्तेमाल करता है. MediaSession को शुरू करने पर, MediaSession.Callback का डिफ़ॉल्ट सेटअप बन जाता है. यह सेटअप, MediaController से आपके प्लेयर को भेजे जाने वाले सभी निर्देशों को अपने-आप मैनेज करता है.

सूचना

MediaSessionService आपके लिए अपने-आप एक MediaNotification बनाता है. यह ज़्यादातर मामलों में काम करता है. डिफ़ॉल्ट रूप से, पब्लिश की गई सूचना एक MediaStyle सूचना होती है. यह आपके मीडिया सेशन की नई जानकारी के साथ अपडेट रहती है. साथ ही, इसमें प्लेबैक कंट्रोल दिखते हैं. MediaNotification को आपके सेशन की जानकारी होती है. इसका इस्तेमाल, उसी सेशन से कनेक्ट किए गए किसी भी अन्य ऐप्लिकेशन के लिए, प्लेबैक को कंट्रोल करने के लिए किया जा सकता है.

उदाहरण के लिए, MediaSessionService का इस्तेमाल करने वाला कोई संगीत स्ट्रीमिंग ऐप्लिकेशन, MediaNotification बनाएगा. इसमें, चलाए जा रहे मौजूदा मीडिया आइटम का टाइटल, कलाकार, और एल्बम आर्ट दिखेगा. साथ ही, आपके MediaSession कॉन्फ़िगरेशन के आधार पर प्लेबैक कंट्रोल भी दिखेंगे.

ज़रूरी मेटाडेटा को मीडिया में दिया जा सकता है या मीडिया आइटम के हिस्से के तौर पर एलान किया जा सकता है. इसके लिए, यहां दिए गए स्निपेट को देखें:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setMediaId("media-1")
    .setUri(mediaUri)
    .setMediaMetadata(
      MediaMetadata.Builder()
        .setArtist("David Bowie")
        .setTitle("Heroes")
        .setArtworkUri(artworkUri)
        .build()
    )
    .build()

mediaController.setMediaItem(mediaItem)
mediaController.prepare()
mediaController.play()

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setMediaId("media-1")
        .setUri(mediaUri)
        .setMediaMetadata(
            new MediaMetadata.Builder()
                .setArtist("David Bowie")
                .setTitle("Heroes")
                .setArtworkUri(artworkUri)
                .build())
        .build();

mediaController.setMediaItem(mediaItem);
mediaController.prepare();
mediaController.play();

सूचना की लाइफ़साइकल

जैसे ही Player की प्लेलिस्ट में MediaItem इंस्टेंस होते हैं, सूचना बन जाती है.

सभी सूचनाएं, Player और MediaSession की स्थिति के आधार पर अपने-आप अपडेट होती हैं.

फ़ोरग्राउंड सेवा के चालू रहने के दौरान, सूचना को नहीं हटाया जा सकता. सूचना को तुरंत हटाने के लिए, आपको Player.release() को कॉल करना होगा या Player.clearMediaItems() का इस्तेमाल करके प्लेलिस्ट को मिटाना होगा.

अगर प्लेयर को 10 मिनट से ज़्यादा समय तक रोका जाता है, बंद किया जाता है या वह काम नहीं करता है और उपयोगकर्ता कोई और इंटरैक्शन नहीं करता है, तो सेवा अपने-आप फ़ोरग्राउंड सेवा की स्थिति से बाहर हो जाती है. इससे सिस्टम उसे बंद कर सकता है. प्लेबैक फिर से शुरू करने की सुविधा लागू की जा सकती है. इससे उपयोगकर्ता, सेवा की लाइफ़साइकल को रीस्टार्ट कर सकता है और बाद में प्लेबैक फिर से शुरू कर सकता है.

सूचना को पसंद के मुताबिक बनाना

MediaItem.MediaMetadata में बदलाव करके, फ़िलहाल चल रहे आइटम के मेटाडेटा को पसंद के मुताबिक बनाया जा सकता है. अगर आपको किसी मौजूदा आइटम का मेटाडेटा अपडेट करना है, तो Player.replaceMediaItem का इस्तेमाल करें. इससे, वीडियो के प्लेबैक में रुकावट डाले बिना मेटाडेटा अपडेट किया जा सकता है.

Android मीडिया कंट्रोल के लिए, कस्टम मीडिया बटन की प्राथमिकताएं सेट करके, सूचना में दिखाए गए कुछ बटन को भी पसंद के मुताबिक बनाया जा सकता है. Android मीडिया कंट्रोल को पसंद के मुताबिक बनाने के बारे में ज़्यादा जानें.

सूचना को और ज़्यादा कस्टमाइज़ करने के लिए, DefaultMediaNotificationProvider.Builder की मदद से MediaNotification.Provider बनाएं या सेवा देने वाली कंपनी के इंटरफ़ेस को पसंद के मुताबिक बनाएं. setMediaNotificationProvider की मदद से, स्वास्थ्य सेवा देने वाली कंपनी या व्यक्ति की जानकारी को अपने MediaSessionService में जोड़ें.

वीडियो फिर से शुरू करना

MediaSessionService के बंद होने और डिवाइस के रीबूट होने के बाद भी, उपयोगकर्ताओं को प्लेबैक फिर से शुरू करने की सुविधा दी जा सकती है. इससे उपयोगकर्ता, सेवा को फिर से शुरू कर सकते हैं और प्लेबैक को वहीं से शुरू कर सकते हैं जहां उन्होंने छोड़ा था. डिफ़ॉल्ट रूप से, प्लेबैक फिर से शुरू करने की सुविधा बंद होती है. इसका मतलब है कि जब आपकी सेवा नहीं चल रही हो, तब उपयोगकर्ता प्लेबैक फिर से शुरू नहीं कर सकता. इस सुविधा में शामिल होने के लिए, आपको मीडिया बटन रिसीवर का एलान करना होगा और onPlaybackResumption तरीका लागू करना होगा.

Media3 मीडिया बटन रिसीवर का एलान करना

अपने मेनिफ़ेस्ट में MediaButtonReceiver का एलान करके शुरुआत करें:

<receiver android:name="androidx.media3.session.MediaButtonReceiver"
  android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MEDIA_BUTTON" />
  </intent-filter>
</receiver>

वीडियो फिर से शुरू करने के लिए कॉलबैक लागू करना

जब ब्लूटूथ डिवाइस या Android सिस्टम यूज़र इंटरफ़ेस (यूआई) की फिर से शुरू करने की सुविधा, प्लेबैक को फिर से शुरू करने का अनुरोध करती है, तो onPlaybackResumption() कॉलबैक का तरीका कॉल किया जाता है.

Kotlin

override fun onPlaybackResumption(
  mediaSession: MediaSession,
  controller: MediaSession.ControllerInfo,
  isForPlayback: Boolean,
): ListenableFuture<MediaSession.MediaItemsWithStartPosition> {
  val settableFuture = SettableFuture.create<MediaSession.MediaItemsWithStartPosition>()
  settableFuture.addListener(
    {
      // Your app is responsible for storing the playlist, metadata (like title
      // and artwork) of the current item and the start position to use here.
      val resumptionPlaylist = restorePlaylist()
      settableFuture.set(resumptionPlaylist)
    },
    MoreExecutors.directExecutor(),
  )
  return settableFuture
}

Java

@Override
public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption(
    MediaSession mediaSession, ControllerInfo controller, boolean isForPlayback) {
  SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create();
  settableFuture.addListener(
      () -> {
        // Your app is responsible for storing the playlist, metadata (like title
        // and artwork) of the current item and the start position to use here.
        MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist();
        settableFuture.set(resumptionPlaylist);
      },
      MoreExecutors.directExecutor());
  return settableFuture;
}

अगर आपने वीडियो चलाने की स्पीड, रिपीट मोड या शफ़ल मोड जैसे अन्य पैरामीटर सेव किए हैं, तो onPlaybackResumption() इन पैरामीटर के साथ प्लेयर को कॉन्फ़िगर करने के लिए एक अच्छी जगह है. इसके बाद, Media3 प्लेयर को तैयार करता है और कॉलबैक पूरा होने पर वीडियो चलाना शुरू करता है.

इस तरीके को बूट टाइम के दौरान कॉल किया जाता है, ताकि डिवाइस के फिर से चालू होने के बाद, Android सिस्टम के यूज़र इंटरफ़ेस (यूआई) को फिर से शुरू करने की सूचना बनाई जा सके. इसके लिए, isForPlayback को false पर सेट किया जाता है. रिच नोटिफ़िकेशन के लिए, हमारा सुझाव है कि आप मौजूदा आइटम के MediaMetadata फ़ील्ड, जैसे कि title और artworkData या artworkUri को स्थानीय तौर पर उपलब्ध वैल्यू से भरें. ऐसा इसलिए, क्योंकि हो सकता है कि नेटवर्क ऐक्सेस अभी उपलब्ध न हो. MediaMetadata.extras में MediaConstants.EXTRAS_KEY_COMPLETION_STATUS और MediaConstants.EXTRAS_KEY_COMPLETION_PERCENTAGE को भी जोड़ा जा सकता है, ताकि यह पता चल सके कि वीडियो को फिर से कहां से चलाना है.

बेहतर कंट्रोलर कॉन्फ़िगरेशन और पुराने सिस्टम के साथ काम करने की सुविधा

आम तौर पर, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में MediaController का इस्तेमाल, प्लेबैक को कंट्रोल करने और प्लेलिस्ट दिखाने के लिए किया जाता है. साथ ही, सेशन को बाहरी क्लाइंट के लिए एक्सपोज़ किया जाता है. जैसे, मोबाइल या टीवी पर Android मीडिया कंट्रोल और Assistant, स्मार्टवॉच के लिए Wear OS, और कारों में Android Auto. Media3 सेशन डेमो ऐप्लिकेशन, ऐसे ऐप्लिकेशन का उदाहरण है जो इस तरह की स्थिति को लागू करता है.

ये बाहरी क्लाइंट, लेगसी AndroidX लाइब्रेरी के MediaControllerCompat या Android प्लैटफ़ॉर्म के android.media.session.MediaController जैसे एपीआई का इस्तेमाल कर सकते हैं. Media3, लेगसी लाइब्रेरी के साथ पूरी तरह से काम करता है. साथ ही, यह Android प्लैटफ़ॉर्म एपीआई के साथ इंटरऑपरेबिलिटी की सुविधा देता है.

भरोसेमंद कंट्रोलर की पहचान करना

कोई भी ऐप्लिकेशन, आपके मीडिया सेशन या लाइब्रेरी से कनेक्ट करने की कोशिश कर सकता है. अगर आपको सिस्टम कंट्रोलर, मीडिया कॉन्टेंट कंट्रोल करने की अनुमति वाले कंट्रोलर, और अपने ऐप्लिकेशन के ऐक्सेस को सीमित करना है, तो ऐक्सेस की बुनियादी जांच के लिए ControllerInfo.isTrusted() का इस्तेमाल करें. इसके अलावा, मीडिया सूचना कंट्रोलर या Android Auto कंट्रोलर जैसे ज़्यादा खास कंट्रोलर की पहचान की जा सकती है. इसके बारे में यहां दिए गए सेक्शन में बताया गया है.

मीडिया नोटिफ़िकेशन कंट्रोलर का इस्तेमाल करना

यह समझना ज़रूरी है कि ये लेगसी और प्लैटफ़ॉर्म कंट्रोलर, एक ही स्टेटस शेयर करते हैं. साथ ही, कंट्रोलर के हिसाब से विज़िबिलिटी को पसंद के मुताबिक नहीं बनाया जा सकता. उदाहरण के लिए, उपलब्ध PlaybackState.getActions() और PlaybackState.getCustomActions(). मीडिया नोटिफ़िकेशन कंट्रोलर का इस्तेमाल करके, प्लैटफ़ॉर्म मीडिया सेशन में सेट किए गए स्टेटस को कॉन्फ़िगर किया जा सकता है, ताकि ये लेगसी और प्लैटफ़ॉर्म कंट्रोलर के साथ काम कर सकें.

उदाहरण के लिए, कोई ऐप्लिकेशन MediaSession.Callback.onConnect() को लागू कर सकता है, ताकि प्लैटफ़ॉर्म सेशन के लिए उपलब्ध कमांड और मीडिया बटन की सेटिंग को इस तरह सेट किया जा सके:

Kotlin

override fun onConnectAsync(
  session: MediaSession,
  controller: MediaSession.ControllerInfo,
): ListenableFuture<ConnectionResult> {
  if (session.isMediaNotificationController(controller)) {
    val playerCommands =
      ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon()
        .remove(COMMAND_SEEK_TO_PREVIOUS)
        .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
        .remove(COMMAND_SEEK_TO_NEXT)
        .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
        .build()
    // Custom button preferences and commands to configure the platform session.
    return immediateFuture(
      AcceptedResultBuilder(session, controller)
        .setMediaButtonPreferences(listOf(seekBackButton, seekForwardButton))
        .setAvailablePlayerCommands(playerCommands)
        .build()
    )
  }
  // Default commands with default button preferences for all other controllers.
  return immediateFuture(AcceptedResultBuilder(session, controller).build())
}

Java

@Override
public ListenableFuture<ConnectionResult> onConnectAsync(
    MediaSession session, MediaSession.ControllerInfo controller) {
  if (session.isMediaNotificationController(controller)) {
    Player.Commands playerCommands =
        ConnectionResult.DEFAULT_PLAYER_COMMANDS
            .buildUpon()
            .remove(COMMAND_SEEK_TO_PREVIOUS)
            .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
            .remove(COMMAND_SEEK_TO_NEXT)
            .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
            .build();
    // Custom button preferences and commands to configure the platform session.
    return immediateFuture(
        new AcceptedResultBuilder(session, controller)
            .setMediaButtonPreferences(ImmutableList.of(seekBackButton, seekForwardButton))
            .setAvailablePlayerCommands(playerCommands)
            .build());
  }
  // Default commands with default button preferences for all other controllers.
  return immediateFuture(new AcceptedResultBuilder(session, controller).build());
}

Android Auto को कस्टम कमांड भेजने की अनुमति देना

MediaLibraryService का इस्तेमाल करते समय और मोबाइल ऐप्लिकेशन के साथ Android Auto का इस्तेमाल करने के लिए, Android Auto कंट्रोलर को सही कमांड की ज़रूरत होती है. ऐसा न होने पर, Media3 उस कंट्रोलर से आने वाले कस्टम कमांड को अस्वीकार कर देगा:

Kotlin

override fun onConnectAsync(
  session: MediaSession,
  controller: MediaSession.ControllerInfo,
): ListenableFuture<ConnectionResult> {
  val sessionCommands =
    ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build()
  if (session.isMediaNotificationController(controller)) {
    // ... See above.
  } else if (session.isAutoCompanionController(controller)) {
    // Available commands to accept incoming custom commands from Auto.
    return immediateFuture(
      AcceptedResultBuilder(session, controller)
        .setAvailableSessionCommands(sessionCommands)
        .build()
    )
  }
  // Default commands for all other controllers.
  return immediateFuture(AcceptedResultBuilder(session, controller).build())
}

Java

@Override
public ListenableFuture<ConnectionResult> onConnectAsync(
    MediaSession session, MediaSession.ControllerInfo controller) {
  SessionCommands sessionCommands =
      ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon().add(customCommand).build();
  if (session.isMediaNotificationController(controller)) {
    // ... See above.
  } else if (session.isAutoCompanionController(controller)) {
    // Available commands to accept incoming custom commands from Auto.
    return immediateFuture(
        new AcceptedResultBuilder(session, controller)
            .setAvailableSessionCommands(sessionCommands)
            .build());
  }
  // Default commands for all other controllers.
  return immediateFuture(new AcceptedResultBuilder(session, controller).build());
}

सेशन के डेमो ऐप्लिकेशन में एक ऑटोमोटिव मॉड्यूल है. इससे पता चलता है कि Automotive OS के लिए, एक अलग APK की ज़रूरत होती है.