summaryrefslogtreecommitdiff
path: root/packages/SettingsLib/src
diff options
context:
space:
mode:
author Santiago Seifert <aquilescanta@google.com> 2025-02-04 09:06:07 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-04 09:06:07 -0800
commit976910dcaa0f245dfb2d190ae370e56528c9342c (patch)
tree32db3cee01a13015d3d6c675166d3cdb1bcd3bec /packages/SettingsLib/src
parent63b7d688c1496460106d05d6623e05d5a01bb341 (diff)
parent1f01fadbfc9d0e898a532629dc2ca2d72d6c9023 (diff)
Merge "Migrate the MediaSessions file to kotlin" into main
Diffstat (limited to 'packages/SettingsLib/src')
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java402
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.kt364
2 files changed, 364 insertions, 402 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
deleted file mode 100644
index 89f3cf5e9aab..000000000000
--- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * 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.android.settingslib.volume;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaController.PlaybackInfo;
-import android.media.session.MediaSession;
-import android.media.session.MediaSession.QueueItem;
-import android.media.session.MediaSession.Token;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
-import android.media.session.MediaSessionManager.RemoteSessionCallback;
-import android.media.session.PlaybackState;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Convenience client for all media session updates. Provides a callback interface for events
- * related to remote media sessions.
- */
-public class MediaSessions {
- private static final String TAG = Util.logTag(MediaSessions.class);
-
- private static final boolean USE_SERVICE_LABEL = false;
-
- private final Context mContext;
- private final H mHandler;
- private final HandlerExecutor mHandlerExecutor;
- private final MediaSessionManager mMgr;
- private final Map<Token, MediaControllerRecord> mRecords = new HashMap<>();
- private final Callbacks mCallbacks;
-
- private boolean mInit;
-
- public MediaSessions(Context context, Looper looper, Callbacks callbacks) {
- mContext = context;
- mHandler = new H(looper);
- mHandlerExecutor = new HandlerExecutor(mHandler);
- mMgr = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
- mCallbacks = callbacks;
- }
-
- /**
- * Dump to {@code writer}
- */
- public void dump(PrintWriter writer) {
- writer.println(getClass().getSimpleName() + " state:");
- writer.print(" mInit: ");
- writer.println(mInit);
- writer.print(" mRecords.size: ");
- writer.println(mRecords.size());
- int i = 0;
- for (MediaControllerRecord r : mRecords.values()) {
- dump(++i, writer, r.controller);
- }
- }
-
- /**
- * init MediaSessions
- */
- public void init() {
- if (D.BUG) Log.d(TAG, "init");
- // will throw if no permission
- mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
- mInit = true;
- postUpdateSessions();
- mMgr.registerRemoteSessionCallback(mHandlerExecutor,
- mRemoteSessionCallback);
- }
-
- protected void postUpdateSessions() {
- if (!mInit) return;
- mHandler.sendEmptyMessage(H.UPDATE_SESSIONS);
- }
-
- /**
- * Destroy MediaSessions
- */
- public void destroy() {
- if (D.BUG) Log.d(TAG, "destroy");
- mInit = false;
- mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
- mMgr.unregisterRemoteSessionCallback(mRemoteSessionCallback);
- }
-
- /**
- * Set volume {@code level} to remote media {@code token}
- */
- public void setVolume(Token token, int level) {
- final MediaControllerRecord r = mRecords.get(token);
- if (r == null) {
- Log.w(TAG, "setVolume: No record found for token " + token);
- return;
- }
- if (D.BUG) Log.d(TAG, "Setting level to " + level);
- r.controller.setVolumeTo(level, 0);
- }
-
- private void onRemoteVolumeChangedH(Token sessionToken, int flags) {
- final MediaController controller = new MediaController(mContext, sessionToken);
- if (D.BUG) {
- Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " "
- + Util.audioManagerFlagsToString(flags));
- }
- final Token token = controller.getSessionToken();
- mCallbacks.onRemoteVolumeChanged(token, flags);
- }
-
- private void onUpdateRemoteSessionListH(Token sessionToken) {
- final MediaController controller =
- sessionToken != null ? new MediaController(mContext, sessionToken) : null;
- final String pkg = controller != null ? controller.getPackageName() : null;
- if (D.BUG) Log.d(TAG, "onUpdateRemoteSessionListH " + pkg);
- // this may be our only indication that a remote session is changed, refresh
- postUpdateSessions();
- }
-
- protected void onActiveSessionsUpdatedH(List<MediaController> controllers) {
- if (D.BUG) Log.d(TAG, "onActiveSessionsUpdatedH n=" + controllers.size());
- final Set<Token> toRemove = new HashSet<Token>(mRecords.keySet());
- for (MediaController controller : controllers) {
- final Token token = controller.getSessionToken();
- final PlaybackInfo pi = controller.getPlaybackInfo();
- toRemove.remove(token);
- if (!mRecords.containsKey(token)) {
- final MediaControllerRecord r = new MediaControllerRecord(controller);
- r.name = getControllerName(controller);
- mRecords.put(token, r);
- controller.registerCallback(r, mHandler);
- }
- final MediaControllerRecord r = mRecords.get(token);
- final boolean remote = isRemote(pi);
- if (remote) {
- updateRemoteH(token, r.name, pi);
- r.sentRemote = true;
- }
- }
- for (Token t : toRemove) {
- final MediaControllerRecord r = mRecords.get(t);
- r.controller.unregisterCallback(r);
- mRecords.remove(t);
- if (D.BUG) Log.d(TAG, "Removing " + r.name + " sentRemote=" + r.sentRemote);
- if (r.sentRemote) {
- mCallbacks.onRemoteRemoved(t);
- r.sentRemote = false;
- }
- }
- }
-
- private static boolean isRemote(PlaybackInfo pi) {
- return pi != null && pi.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
- }
-
- protected String getControllerName(MediaController controller) {
- final PackageManager pm = mContext.getPackageManager();
- final String pkg = controller.getPackageName();
- try {
- if (USE_SERVICE_LABEL) {
- final List<ResolveInfo> ris = pm.queryIntentServices(
- new Intent("android.media.MediaRouteProviderService").setPackage(pkg), 0);
- if (ris != null) {
- for (ResolveInfo ri : ris) {
- if (ri.serviceInfo == null) continue;
- if (pkg.equals(ri.serviceInfo.packageName)) {
- final String serviceLabel =
- Objects.toString(ri.serviceInfo.loadLabel(pm), "").trim();
- if (serviceLabel.length() > 0) {
- return serviceLabel;
- }
- }
- }
- }
- }
- final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
- final String appLabel = Objects.toString(ai.loadLabel(pm), "").trim();
- if (appLabel.length() > 0) {
- return appLabel;
- }
- } catch (NameNotFoundException e) {
- }
- return pkg;
- }
-
- private void updateRemoteH(Token token, String name, PlaybackInfo pi) {
- if (mCallbacks != null) {
- mCallbacks.onRemoteUpdate(token, name, pi);
- }
- }
-
- private static void dump(int n, PrintWriter writer, MediaController c) {
- writer.println(" Controller " + n + ": " + c.getPackageName());
- final Bundle extras = c.getExtras();
- final long flags = c.getFlags();
- final MediaMetadata mm = c.getMetadata();
- final PlaybackInfo pi = c.getPlaybackInfo();
- final PlaybackState playbackState = c.getPlaybackState();
- final List<QueueItem> queue = c.getQueue();
- final CharSequence queueTitle = c.getQueueTitle();
- final int ratingType = c.getRatingType();
- final PendingIntent sessionActivity = c.getSessionActivity();
-
- writer.println(" PlaybackState: " + Util.playbackStateToString(playbackState));
- writer.println(" PlaybackInfo: " + Util.playbackInfoToString(pi));
- if (mm != null) {
- writer.println(" MediaMetadata.desc=" + mm.getDescription());
- }
- writer.println(" RatingType: " + ratingType);
- writer.println(" Flags: " + flags);
- if (extras != null) {
- writer.println(" Extras:");
- for (String key : extras.keySet()) {
- writer.println(" " + key + "=" + extras.get(key));
- }
- }
- if (queueTitle != null) {
- writer.println(" QueueTitle: " + queueTitle);
- }
- if (queue != null && !queue.isEmpty()) {
- writer.println(" Queue:");
- for (QueueItem qi : queue) {
- writer.println(" " + qi);
- }
- }
- if (pi != null) {
- writer.println(" sessionActivity: " + sessionActivity);
- }
- }
-
- private final class MediaControllerRecord extends MediaController.Callback {
- public final MediaController controller;
-
- public boolean sentRemote;
- public String name;
-
- private MediaControllerRecord(MediaController controller) {
- this.controller = controller;
- }
-
- private String cb(String method) {
- return method + " " + controller.getPackageName() + " ";
- }
-
- @Override
- public void onAudioInfoChanged(@NonNull PlaybackInfo info) {
- if (D.BUG) {
- Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info)
- + " sentRemote=" + sentRemote);
- }
- final boolean remote = isRemote(info);
- if (!remote && sentRemote) {
- mCallbacks.onRemoteRemoved(controller.getSessionToken());
- sentRemote = false;
- } else if (remote) {
- updateRemoteH(controller.getSessionToken(), name, info);
- sentRemote = true;
- }
- }
-
- @Override
- public void onExtrasChanged(Bundle extras) {
- if (D.BUG) Log.d(TAG, cb("onExtrasChanged") + extras);
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- if (D.BUG) Log.d(TAG, cb("onMetadataChanged") + Util.mediaMetadataToString(metadata));
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- if (D.BUG) Log.d(TAG, cb("onPlaybackStateChanged") + Util.playbackStateToString(state));
- }
-
- @Override
- public void onQueueChanged(List<QueueItem> queue) {
- if (D.BUG) Log.d(TAG, cb("onQueueChanged") + queue);
- }
-
- @Override
- public void onQueueTitleChanged(CharSequence title) {
- if (D.BUG) Log.d(TAG, cb("onQueueTitleChanged") + title);
- }
-
- @Override
- public void onSessionDestroyed() {
- if (D.BUG) Log.d(TAG, cb("onSessionDestroyed"));
- }
-
- @Override
- public void onSessionEvent(String event, Bundle extras) {
- if (D.BUG) Log.d(TAG, cb("onSessionEvent") + "event=" + event + " extras=" + extras);
- }
- }
-
- private final OnActiveSessionsChangedListener mSessionsListener =
- new OnActiveSessionsChangedListener() {
- @Override
- public void onActiveSessionsChanged(List<MediaController> controllers) {
- onActiveSessionsUpdatedH(controllers);
- }
- };
-
- private final RemoteSessionCallback mRemoteSessionCallback =
- new RemoteSessionCallback() {
- @Override
- public void onVolumeChanged(@NonNull MediaSession.Token sessionToken,
- int flags) {
- mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0,
- sessionToken).sendToTarget();
- }
-
- @Override
- public void onDefaultRemoteSessionChanged(
- @Nullable MediaSession.Token sessionToken) {
- mHandler.obtainMessage(H.UPDATE_REMOTE_SESSION_LIST,
- sessionToken).sendToTarget();
- }
- };
-
- private final class H extends Handler {
- private static final int UPDATE_SESSIONS = 1;
- private static final int REMOTE_VOLUME_CHANGED = 2;
- private static final int UPDATE_REMOTE_SESSION_LIST = 3;
-
- private H(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case UPDATE_SESSIONS:
- onActiveSessionsUpdatedH(mMgr.getActiveSessions(null));
- break;
- case REMOTE_VOLUME_CHANGED:
- onRemoteVolumeChangedH((Token) msg.obj, msg.arg1);
- break;
- case UPDATE_REMOTE_SESSION_LIST:
- onUpdateRemoteSessionListH((Token) msg.obj);
- break;
- }
- }
- }
-
- /**
- * Callback for remote media sessions
- */
- public interface Callbacks {
- /**
- * Invoked when remote media session is updated
- */
- void onRemoteUpdate(Token token, String name, PlaybackInfo pi);
-
- /**
- * Invoked when remote media session is removed
- */
- void onRemoteRemoved(Token t);
-
- /**
- * Invoked when remote volume is changed
- */
- void onRemoteVolumeChanged(Token token, int flags);
- }
-
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.kt b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.kt
new file mode 100644
index 000000000000..10156c404ebf
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.kt
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * 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.android.settingslib.volume
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.MediaSessionManager
+import android.media.session.PlaybackState
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.Looper
+import android.os.Message
+import android.util.Log
+import java.io.PrintWriter
+import java.util.Objects
+
+/**
+ * Convenience client for all media session updates. Provides a callback interface for events
+ * related to remote media sessions.
+ */
+class MediaSessions(context: Context, looper: Looper, callbacks: Callbacks) {
+
+ private val mContext = context
+ private val mHandler: H = H(looper)
+ private val mHandlerExecutor: HandlerExecutor = HandlerExecutor(mHandler)
+ private val mMgr: MediaSessionManager =
+ mContext.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager
+ private val mRecords: MutableMap<MediaSession.Token, MediaControllerRecord> = HashMap()
+ private val mCallbacks: Callbacks = callbacks
+ private val mSessionsListener =
+ MediaSessionManager.OnActiveSessionsChangedListener { controllers ->
+ onActiveSessionsUpdatedH(controllers!!)
+ }
+
+ private val mRemoteSessionCallback: MediaSessionManager.RemoteSessionCallback =
+ object : MediaSessionManager.RemoteSessionCallback {
+ override fun onVolumeChanged(sessionToken: MediaSession.Token, flags: Int) {
+ mHandler.obtainMessage(REMOTE_VOLUME_CHANGED, flags, 0, sessionToken).sendToTarget()
+ }
+
+ override fun onDefaultRemoteSessionChanged(sessionToken: MediaSession.Token?) {
+ mHandler.obtainMessage(UPDATE_REMOTE_SESSION_LIST, sessionToken).sendToTarget()
+ }
+ }
+
+ private var mInit = false
+
+ /** Dump to `writer` */
+ fun dump(writer: PrintWriter) {
+ writer.println(javaClass.simpleName + " state:")
+ writer.print(" mInit: ")
+ writer.println(mInit)
+ writer.print(" mRecords.size: ")
+ writer.println(mRecords.size)
+ for ((i, r) in mRecords.values.withIndex()) {
+ r.controller.dump(i + 1, writer)
+ }
+ }
+
+ /** init MediaSessions */
+ fun init() {
+ if (D.BUG) {
+ Log.d(TAG, "init")
+ }
+ // will throw if no permission
+ mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler)
+ mInit = true
+ postUpdateSessions()
+ mMgr.registerRemoteSessionCallback(mHandlerExecutor, mRemoteSessionCallback)
+ }
+
+ /** Destroy MediaSessions */
+ fun destroy() {
+ if (D.BUG) {
+ Log.d(TAG, "destroy")
+ }
+ mInit = false
+ mMgr.removeOnActiveSessionsChangedListener(mSessionsListener)
+ mMgr.unregisterRemoteSessionCallback(mRemoteSessionCallback)
+ }
+
+ /** Set volume `level` to remote media `token` */
+ fun setVolume(token: MediaSession.Token, level: Int) {
+ val record = mRecords[token]
+ if (record == null) {
+ Log.w(TAG, "setVolume: No record found for token $token")
+ return
+ }
+ if (D.BUG) {
+ Log.d(TAG, "Setting level to $level")
+ }
+ record.controller.setVolumeTo(level, 0)
+ }
+
+ private fun onRemoteVolumeChangedH(sessionToken: MediaSession.Token, flags: Int) {
+ val controller = MediaController(mContext, sessionToken)
+ if (D.BUG) {
+ Log.d(
+ TAG,
+ "remoteVolumeChangedH " +
+ controller.packageName +
+ " " +
+ Util.audioManagerFlagsToString(flags),
+ )
+ }
+ val token = controller.sessionToken
+ mCallbacks.onRemoteVolumeChanged(token, flags)
+ }
+
+ private fun onUpdateRemoteSessionListH(sessionToken: MediaSession.Token?) {
+ if (D.BUG) {
+ Log.d(
+ TAG,
+ "onUpdateRemoteSessionListH ${sessionToken?.let {MediaController(mContext, it)}?.packageName}",
+ )
+ }
+ // this may be our only indication that a remote session is changed, refresh
+ postUpdateSessions()
+ }
+
+ private fun postUpdateSessions() {
+ if (mInit) {
+ mHandler.sendEmptyMessage(UPDATE_SESSIONS)
+ }
+ }
+
+ private fun onActiveSessionsUpdatedH(controllers: List<MediaController>) {
+ if (D.BUG) {
+ Log.d(TAG, "onActiveSessionsUpdatedH n=" + controllers.size)
+ }
+ val toRemove: MutableSet<MediaSession.Token> = HashSet(mRecords.keys)
+ for (controller in controllers) {
+ val token = controller.sessionToken
+ val playbackInfo = controller.playbackInfo
+ toRemove.remove(token)
+ if (!mRecords.containsKey(token)) {
+ val record = MediaControllerRecord(controller)
+ record.name = getControllerName(controller)
+ mRecords[token] = record
+ controller.registerCallback(record, mHandler)
+ }
+ val record = mRecords[token]
+ val remote = isRemote(playbackInfo)
+ if (remote) {
+ updateRemoteH(token, record!!.name, playbackInfo)
+ record.sentRemote = true
+ }
+ }
+ for (token in toRemove) {
+ val record = mRecords[token]!!
+ record.controller.unregisterCallback(record)
+ mRecords.remove(token)
+ if (D.BUG) {
+ Log.d(TAG, "Removing " + record.name + " sentRemote=" + record.sentRemote)
+ }
+ if (record.sentRemote) {
+ mCallbacks.onRemoteRemoved(token)
+ record.sentRemote = false
+ }
+ }
+ }
+
+ private fun getControllerName(controller: MediaController): String {
+ val pm = mContext.packageManager
+ val pkg = controller.packageName
+ try {
+ if (USE_SERVICE_LABEL) {
+ val services =
+ pm.queryIntentServices(
+ Intent("android.media.MediaRouteProviderService").setPackage(pkg),
+ 0,
+ )
+ if (services != null) {
+ for (ri in services) {
+ if (ri.serviceInfo == null) continue
+ if (pkg == ri.serviceInfo.packageName) {
+ val serviceLabel =
+ Objects.toString(ri.serviceInfo.loadLabel(pm), "").trim()
+ if (serviceLabel.isNotEmpty()) {
+ return serviceLabel
+ }
+ }
+ }
+ }
+ }
+ val ai = pm.getApplicationInfo(pkg, 0)
+ val appLabel = Objects.toString(ai.loadLabel(pm), "").trim { it <= ' ' }
+ if (appLabel.isNotEmpty()) {
+ return appLabel
+ }
+ } catch (_: PackageManager.NameNotFoundException) {}
+ return pkg
+ }
+
+ private fun updateRemoteH(
+ token: MediaSession.Token,
+ name: String?,
+ pi: MediaController.PlaybackInfo,
+ ) = mCallbacks.onRemoteUpdate(token, name, pi)
+
+ private inner class MediaControllerRecord(val controller: MediaController) :
+ MediaController.Callback() {
+ var sentRemote: Boolean = false
+ var name: String? = null
+
+ fun cb(method: String): String {
+ return method + " " + controller.packageName + " "
+ }
+
+ override fun onAudioInfoChanged(info: MediaController.PlaybackInfo) {
+ if (D.BUG) {
+ Log.d(
+ TAG,
+ (cb("onAudioInfoChanged") +
+ Util.playbackInfoToString(info) +
+ " sentRemote=" +
+ sentRemote),
+ )
+ }
+ val remote = isRemote(info)
+ if (!remote && sentRemote) {
+ mCallbacks.onRemoteRemoved(controller.sessionToken)
+ sentRemote = false
+ } else if (remote) {
+ updateRemoteH(controller.sessionToken, name, info)
+ sentRemote = true
+ }
+ }
+
+ override fun onExtrasChanged(extras: Bundle?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onExtrasChanged") + extras)
+ }
+ }
+
+ override fun onMetadataChanged(metadata: MediaMetadata?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onMetadataChanged") + Util.mediaMetadataToString(metadata))
+ }
+ }
+
+ override fun onPlaybackStateChanged(state: PlaybackState?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onPlaybackStateChanged") + Util.playbackStateToString(state))
+ }
+ }
+
+ override fun onQueueChanged(queue: List<MediaSession.QueueItem>?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onQueueChanged") + queue)
+ }
+ }
+
+ override fun onQueueTitleChanged(title: CharSequence?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onQueueTitleChanged") + title)
+ }
+ }
+
+ override fun onSessionDestroyed() {
+ if (D.BUG) {
+ Log.d(TAG, cb("onSessionDestroyed"))
+ }
+ }
+
+ override fun onSessionEvent(event: String, extras: Bundle?) {
+ if (D.BUG) {
+ Log.d(TAG, cb("onSessionEvent") + "event=" + event + " extras=" + extras)
+ }
+ }
+ }
+
+ private inner class H(looper: Looper) : Handler(looper) {
+
+ override fun handleMessage(msg: Message) {
+ when (msg.what) {
+ UPDATE_SESSIONS -> onActiveSessionsUpdatedH(mMgr.getActiveSessions(null))
+ REMOTE_VOLUME_CHANGED ->
+ onRemoteVolumeChangedH(msg.obj as MediaSession.Token, msg.arg1)
+ UPDATE_REMOTE_SESSION_LIST ->
+ onUpdateRemoteSessionListH(msg.obj as MediaSession.Token?)
+ }
+ }
+ }
+
+ /** Callback for remote media sessions */
+ interface Callbacks {
+ /** Invoked when remote media session is updated */
+ fun onRemoteUpdate(
+ token: MediaSession.Token?,
+ name: String?,
+ pi: MediaController.PlaybackInfo?,
+ )
+
+ /** Invoked when remote media session is removed */
+ fun onRemoteRemoved(token: MediaSession.Token?)
+
+ /** Invoked when remote volume is changed */
+ fun onRemoteVolumeChanged(token: MediaSession.Token?, flags: Int)
+ }
+
+ companion object {
+ private val TAG: String = Util.logTag(MediaSessions::class.java)
+
+ const val UPDATE_SESSIONS: Int = 1
+ const val REMOTE_VOLUME_CHANGED: Int = 2
+ const val UPDATE_REMOTE_SESSION_LIST: Int = 3
+
+ private const val USE_SERVICE_LABEL = false
+
+ private fun isRemote(pi: MediaController.PlaybackInfo?): Boolean =
+ pi != null && pi.playbackType == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE
+ }
+}
+
+private fun MediaController.dump(n: Int, writer: PrintWriter) {
+ writer.println(" Controller $n: $packageName")
+
+ writer.println(" PlaybackState: ${Util.playbackStateToString(playbackState)}")
+ writer.println(" PlaybackInfo: ${Util.playbackInfoToString(playbackInfo)}")
+ val metadata = this.metadata
+ if (metadata != null) {
+ writer.println(" MediaMetadata.desc=${metadata.description}")
+ }
+ writer.println(" RatingType: $ratingType")
+ writer.println(" Flags: $flags")
+
+ writer.println(" Extras:")
+ val extras = this.extras
+ if (extras == null) {
+ writer.println(" <null>")
+ } else {
+ for (key in extras.keySet()) {
+ writer.println(" $key=${extras[key]}")
+ }
+ }
+ writer.println(" QueueTitle: $queueTitle")
+ val queue = this.queue
+ if (!queue.isNullOrEmpty()) {
+ writer.println(" Queue:")
+ for (qi in queue) {
+ writer.println(" $qi")
+ }
+ }
+ writer.println(" sessionActivity: $sessionActivity")
+}