1f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock/*
2f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * Copyright (C) 2015 The Android Open Source Project
3f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock *
4f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
5f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * you may not use this file except in compliance with the License.
6f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * You may obtain a copy of the License at
7f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock *
8f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
9f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock *
10f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * Unless required by applicable law or agreed to in writing, software
11f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
12f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * See the License for the specific language governing permissions and
14f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * limitations under the License.
15f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock */
16f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
17f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockpackage com.android.systemui.volume;
18f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
19f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.app.PendingIntent;
20f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.Context;
21f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.Intent;
22f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.pm.ApplicationInfo;
23f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.pm.PackageManager;
24f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.pm.PackageManager.NameNotFoundException;
25f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.content.pm.ResolveInfo;
26f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.IRemoteVolumeController;
27f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.MediaMetadata;
28f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.ISessionController;
29f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaController;
30f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaController.PlaybackInfo;
31f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaSession.QueueItem;
32f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaSession.Token;
33f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaSessionManager;
34f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
35f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.media.session.PlaybackState;
36f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.os.Bundle;
37f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.os.Handler;
38f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.os.Looper;
39f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.os.Message;
40f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.os.RemoteException;
41f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport android.util.Log;
42f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
43f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.io.PrintWriter;
44f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.io.StringWriter;
45f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.HashMap;
46f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.HashSet;
47f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.List;
48f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.Map;
49f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.Objects;
50f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockimport java.util.Set;
51f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
52f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock/**
53f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * Convenience client for all media session updates.  Provides a callback interface for events
54f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock * related to remote media sessions.
55f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock */
56f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlockpublic class MediaSessions {
57f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private static final String TAG = Util.logTag(MediaSessions.class);
58f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
59f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private static final boolean USE_SERVICE_LABEL = false;
60f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
61f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final Context mContext;
62f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final H mHandler;
63f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final MediaSessionManager mMgr;
64f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final Map<Token, MediaControllerRecord> mRecords = new HashMap<>();
65f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final Callbacks mCallbacks;
66f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
67f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private boolean mInit;
68f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
69f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public MediaSessions(Context context, Looper looper, Callbacks callbacks) {
70f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mContext = context;
71f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mHandler = new H(looper);
72f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mMgr = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
73f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mCallbacks = callbacks;
74f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
75f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
76f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public void dump(PrintWriter writer) {
77f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println(getClass().getSimpleName() + " state:");
78f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.print("  mInit: "); writer.println(mInit);
79f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.print("  mRecords.size: "); writer.println(mRecords.size());
80f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        int i = 0;
81f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        for (MediaControllerRecord r : mRecords.values()) {
82f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            dump(++i, writer, r.controller);
83f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
84f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
85f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
86f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public void init() {
87f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "init");
88f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        // will throw if no permission
89f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
90f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mInit = true;
91f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        postUpdateSessions();
92f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mMgr.setRemoteVolumeController(mRvc);
93f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
94f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
95f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    protected void postUpdateSessions() {
96f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (!mInit) return;
97f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mHandler.sendEmptyMessage(H.UPDATE_SESSIONS);
98f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
99f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
100f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public void destroy() {
101f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "destroy");
102f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mInit = false;
103f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
104f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
105f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
106f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public void setVolume(Token token, int level) {
107f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final MediaControllerRecord r = mRecords.get(token);
108f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (r == null) {
109f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            Log.w(TAG, "setVolume: No record found for token " + token);
110f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            return;
111f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
112f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "Setting level to " + level);
113f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        r.controller.setVolumeTo(level, 0);
114f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
115f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
116f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private void onRemoteVolumeChangedH(ISessionController session, int flags) {
117f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final MediaController controller = new MediaController(mContext, session);
118f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " "
119f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                + Util.audioManagerFlagsToString(flags));
120f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final Token token = controller.getSessionToken();
121f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        mCallbacks.onRemoteVolumeChanged(token, flags);
122f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
123f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
124f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private void onUpdateRemoteControllerH(ISessionController session) {
125f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final MediaController controller = session != null ? new MediaController(mContext, session)
126f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                : null;
127f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final String pkg = controller != null ? controller.getPackageName() : null;
128f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "updateRemoteControllerH " + pkg);
129f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        // this may be our only indication that a remote session is changed, refresh
130f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        postUpdateSessions();
131f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
132f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
133f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    protected void onActiveSessionsUpdatedH(List<MediaController> controllers) {
134f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (D.BUG) Log.d(TAG, "onActiveSessionsUpdatedH n=" + controllers.size());
135f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final Set<Token> toRemove = new HashSet<Token>(mRecords.keySet());
136f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        for (MediaController controller : controllers) {
137f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final Token token = controller.getSessionToken();
138f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final PlaybackInfo pi = controller.getPlaybackInfo();
139f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            toRemove.remove(token);
140f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (!mRecords.containsKey(token)) {
141f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                final MediaControllerRecord r = new MediaControllerRecord(controller);
142f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                r.name = getControllerName(controller);
143f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                mRecords.put(token, r);
144f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                controller.registerCallback(r, mHandler);
145f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
146f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final MediaControllerRecord r = mRecords.get(token);
147f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final boolean remote = isRemote(pi);
148f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (remote) {
149f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                updateRemoteH(token, r.name, pi);
150f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                r.sentRemote = true;
151f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
152f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
153f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        for (Token t : toRemove) {
154f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final MediaControllerRecord r = mRecords.get(t);
155f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            r.controller.unregisterCallback(r);
156f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            mRecords.remove(t);
157f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, "Removing " + r.name + " sentRemote=" + r.sentRemote);
158f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (r.sentRemote) {
159f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                mCallbacks.onRemoteRemoved(t);
160f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                r.sentRemote = false;
161f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
162f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
163f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
164f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
165f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private static boolean isRemote(PlaybackInfo pi) {
166f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        return pi != null && pi.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
167f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
168f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
169f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    protected String getControllerName(MediaController controller) {
170f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final PackageManager pm = mContext.getPackageManager();
171f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final String pkg = controller.getPackageName();
172f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        try {
173f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (USE_SERVICE_LABEL) {
174f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                final List<ResolveInfo> ris = pm.queryIntentServices(
175f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                        new Intent("android.media.MediaRouteProviderService").setPackage(pkg), 0);
176f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                if (ris != null) {
177f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    for (ResolveInfo ri : ris) {
178f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                        if (ri.serviceInfo == null) continue;
179f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                        if (pkg.equals(ri.serviceInfo.packageName)) {
180f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                            final String serviceLabel =
181f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                                    Objects.toString(ri.serviceInfo.loadLabel(pm), "").trim();
182f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                            if (serviceLabel.length() > 0) {
183f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                                return serviceLabel;
184f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                            }
185f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                        }
186f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    }
187f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                }
188f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
189f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
190f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final String appLabel = Objects.toString(ai.loadLabel(pm), "").trim();
191f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (appLabel.length() > 0) {
192f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                return appLabel;
193f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
194f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        } catch (NameNotFoundException e) { }
195f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        return pkg;
196f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
197f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
198f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private void updateRemoteH(Token token, String name, PlaybackInfo pi) {
199f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (mCallbacks != null) {
200f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            mCallbacks.onRemoteUpdate(token, name, pi);
201f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
202f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
203f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
204f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private static void dump(int n, PrintWriter writer, MediaController c) {
205f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println("  Controller " + n + ": " + c.getPackageName());
206f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final Bundle extras = c.getExtras();
207f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final long flags = c.getFlags();
208f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final MediaMetadata mm = c.getMetadata();
209f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final PlaybackInfo pi = c.getPlaybackInfo();
210f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final PlaybackState playbackState = c.getPlaybackState();
211f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final List<QueueItem> queue = c.getQueue();
212f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final CharSequence queueTitle = c.getQueueTitle();
213f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final int ratingType = c.getRatingType();
214f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final PendingIntent sessionActivity = c.getSessionActivity();
215f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
216f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println("    PlaybackState: " + Util.playbackStateToString(playbackState));
217f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println("    PlaybackInfo: " + Util.playbackInfoToString(pi));
218f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (mm != null) {
219f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            writer.println("  MediaMetadata.desc=" + mm.getDescription());
220f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
221f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println("    RatingType: " + ratingType);
222f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        writer.println("    Flags: " + flags);
223f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (extras != null) {
224f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            writer.println("    Extras:");
225f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            for (String key : extras.keySet()) {
226f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                writer.println("      " + key + "=" + extras.get(key));
227f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
228f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
229f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (queueTitle != null) {
230f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            writer.println("    QueueTitle: " + queueTitle);
231f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
232f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (queue != null && !queue.isEmpty()) {
233f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            writer.println("    Queue:");
234f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            for (QueueItem qi : queue) {
235f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                writer.println("      " + qi);
236f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
237f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
238f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        if (pi != null) {
239f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            writer.println("    sessionActivity: " + sessionActivity);
240f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
241f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
242f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
243f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public static void dumpMediaSessions(Context context) {
244f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        final MediaSessionManager mgr = (MediaSessionManager) context
245f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                .getSystemService(Context.MEDIA_SESSION_SERVICE);
246f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        try {
247f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final List<MediaController> controllers = mgr.getActiveSessions(null);
248f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final int N = controllers.size();
249f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, N + " controllers");
250f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            for (int i = 0; i < N; i++) {
251f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                final StringWriter sw = new StringWriter();
252f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                final PrintWriter pw = new PrintWriter(sw, true);
253f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                dump(i + 1, pw, controllers.get(i));
254f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                if (D.BUG) Log.d(TAG, sw.toString());
255f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
256f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        } catch (SecurityException e) {
257f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            Log.w(TAG, "Not allowed to get sessions", e);
258f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
259f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
260f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
261f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final class MediaControllerRecord extends MediaController.Callback {
262f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private final MediaController controller;
263f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
264f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private boolean sentRemote;
265f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private String name;
266f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
267f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private MediaControllerRecord(MediaController controller) {
268f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            this.controller = controller;
269f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
270f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
271f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private String cb(String method) {
272f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            return method + " " + controller.getPackageName() + " ";
273f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
274f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
275f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
276f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onAudioInfoChanged(PlaybackInfo info) {
277f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info)
278f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    + " sentRemote=" + sentRemote);
279f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            final boolean remote = isRemote(info);
280f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (!remote && sentRemote) {
281f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                mCallbacks.onRemoteRemoved(controller.getSessionToken());
282f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                sentRemote = false;
283f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            } else if (remote) {
284f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                updateRemoteH(controller.getSessionToken(), name, info);
285f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                sentRemote = true;
286f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
287f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
288f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
289f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
290f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onExtrasChanged(Bundle extras) {
291f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onExtrasChanged") + extras);
292f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
293f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
294f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
295f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onMetadataChanged(MediaMetadata metadata) {
296f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onMetadataChanged") + Util.mediaMetadataToString(metadata));
297f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
298f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
299f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
300f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onPlaybackStateChanged(PlaybackState state) {
301f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onPlaybackStateChanged") + Util.playbackStateToString(state));
302f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
303f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
304f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
305f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onQueueChanged(List<QueueItem> queue) {
306f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onQueueChanged") + queue);
307f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
308f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
309f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
310f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onQueueTitleChanged(CharSequence title) {
311f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onQueueTitleChanged") + title);
312f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
313f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
314f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
315f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onSessionDestroyed() {
316f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onSessionDestroyed"));
317f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
318f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
319f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
320f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onSessionEvent(String event, Bundle extras) {
321f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            if (D.BUG) Log.d(TAG, cb("onSessionEvent") + "event=" + event + " extras=" + extras);
322f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
323f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
324f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
325f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final OnActiveSessionsChangedListener mSessionsListener =
326f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            new OnActiveSessionsChangedListener() {
327f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
328f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void onActiveSessionsChanged(List<MediaController> controllers) {
329f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            onActiveSessionsUpdatedH(controllers);
330f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
331f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    };
332f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
333f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() {
334f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
335f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void remoteVolumeChanged(ISessionController session, int flags)
336f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                throws RemoteException {
337f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, session).sendToTarget();
338f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
339f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
340f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
341f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void updateRemoteController(final ISessionController session)
342f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                throws RemoteException {
343f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, session).sendToTarget();
344f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
345f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    };
346f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
347f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    private final class H extends Handler {
348f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private static final int UPDATE_SESSIONS = 1;
349f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private static final int REMOTE_VOLUME_CHANGED = 2;
350f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private static final int UPDATE_REMOTE_CONTROLLER = 3;
351f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
352f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        private H(Looper looper) {
353f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            super(looper);
354f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
355f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
356f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        @Override
357f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        public void handleMessage(Message msg) {
358f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            switch (msg.what) {
359f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                case UPDATE_SESSIONS:
360f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    onActiveSessionsUpdatedH(mMgr.getActiveSessions(null));
361f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    break;
362f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                case REMOTE_VOLUME_CHANGED:
363f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    onRemoteVolumeChangedH((ISessionController) msg.obj, msg.arg1);
364f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    break;
365f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                case UPDATE_REMOTE_CONTROLLER:
366f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    onUpdateRemoteControllerH((ISessionController) msg.obj);
367f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock                    break;
368f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock            }
369f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        }
370f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
371f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
372f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    public interface Callbacks {
373f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        void onRemoteUpdate(Token token, String name, PlaybackInfo pi);
374f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        void onRemoteRemoved(Token t);
375f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock        void onRemoteVolumeChanged(Token token, int flags);
376f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock    }
377f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock
378f88d8082a86bee00c604cbbcfb5261f5573936feJohn Spurlock}
379