• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.media;
18 
19 import android.media.MediaController2;
20 import android.media.Session2CommandGroup;
21 import android.media.Session2Token;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.ResultReceiver;
25 import android.os.UserHandle;
26 import android.util.Log;
27 import android.view.KeyEvent;
28 
29 import com.android.internal.annotations.GuardedBy;
30 
31 import java.io.PrintWriter;
32 
33 /**
34  * Keeps the record of {@link Session2Token} to help send command to the corresponding session.
35  */
36 // TODO(jaewan): Do not call service method directly -- introduce listener instead.
37 public class MediaSession2Record implements MediaSessionRecordImpl {
38     private static final String TAG = "MediaSession2Record";
39     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
40     private final Object mLock = new Object();
41 
42     @GuardedBy("mLock")
43     private final Session2Token mSessionToken;
44     @GuardedBy("mLock")
45     private final HandlerExecutor mHandlerExecutor;
46     @GuardedBy("mLock")
47     private final MediaController2 mController;
48     @GuardedBy("mLock")
49     private final MediaSessionService mService;
50     @GuardedBy("mLock")
51     private boolean mIsConnected;
52     @GuardedBy("mLock")
53     private int mPolicies;
54     @GuardedBy("mLock")
55     private boolean mIsClosed;
56 
MediaSession2Record(Session2Token sessionToken, MediaSessionService service, Looper handlerLooper, int policies)57     public MediaSession2Record(Session2Token sessionToken, MediaSessionService service,
58             Looper handlerLooper, int policies) {
59         // The lock is required to prevent `Controller2Callback` from using partially initialized
60         // `MediaSession2Record.this`.
61         synchronized (mLock) {
62             mSessionToken = sessionToken;
63             mService = service;
64             mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper));
65             mController = new MediaController2.Builder(service.getContext(), sessionToken)
66                     .setControllerCallback(mHandlerExecutor, new Controller2Callback())
67                     .build();
68             mPolicies = policies;
69         }
70     }
71 
72     @Override
getPackageName()73     public String getPackageName() {
74         return mSessionToken.getPackageName();
75     }
76 
getSession2Token()77     public Session2Token getSession2Token() {
78         return mSessionToken;
79     }
80 
81     @Override
getUid()82     public int getUid() {
83         return mSessionToken.getUid();
84     }
85 
86     @Override
getUserId()87     public int getUserId() {
88         return UserHandle.getUserHandleForUid(mSessionToken.getUid()).getIdentifier();
89     }
90 
91     @Override
isSystemPriority()92     public boolean isSystemPriority() {
93         // System priority session is currently only allowed for telephony, so it's OK to stick to
94         // the media1 API at this moment.
95         return false;
96     }
97 
98     @Override
adjustVolume(String packageName, String opPackageName, int pid, int uid, boolean asSystemService, int direction, int flags, boolean useSuggested)99     public void adjustVolume(String packageName, String opPackageName, int pid, int uid,
100             boolean asSystemService, int direction, int flags, boolean useSuggested) {
101         // TODO(jaewan): Add API to adjust volume.
102     }
103 
104     @Override
isActive()105     public boolean isActive() {
106         synchronized (mLock) {
107             return mIsConnected;
108         }
109     }
110 
111     @Override
checkPlaybackActiveState(boolean expected)112     public boolean checkPlaybackActiveState(boolean expected) {
113         synchronized (mLock) {
114             return mIsConnected && mController.isPlaybackActive() == expected;
115         }
116     }
117 
118     @Override
isPlaybackTypeLocal()119     public boolean isPlaybackTypeLocal() {
120         // TODO(jaewan): Implement -- need API to know whether the playback is remote or local.
121         return true;
122     }
123 
124     @Override
close()125     public void close() {
126         synchronized (mLock) {
127             mIsClosed = true;
128             // Call close regardless of the mIsConnected. This may be called when it's not yet
129             // connected.
130             mController.close();
131         }
132     }
133 
134     @Override
isClosed()135     public boolean isClosed() {
136         synchronized (mLock) {
137             return mIsClosed;
138         }
139     }
140 
141     @Override
sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, KeyEvent ke, int sequenceId, ResultReceiver cb)142     public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
143             KeyEvent ke, int sequenceId, ResultReceiver cb) {
144         // TODO(jaewan): Implement.
145         return false;
146     }
147 
148     @Override
canHandleVolumeKey()149     public boolean canHandleVolumeKey() {
150         // TODO: Implement when MediaSession2 starts to get key events.
151         return false;
152     }
153 
154     @Override
getSessionPolicies()155     public int getSessionPolicies() {
156         synchronized (mLock) {
157             return mPolicies;
158         }
159     }
160 
161     @Override
setSessionPolicies(int policies)162     public void setSessionPolicies(int policies) {
163         synchronized (mLock) {
164             mPolicies = policies;
165         }
166     }
167 
168     @Override
dump(PrintWriter pw, String prefix)169     public void dump(PrintWriter pw, String prefix) {
170         pw.println(prefix + "token=" + mSessionToken);
171         pw.println(prefix + "controller=" + mController);
172 
173         final String indent = prefix + "  ";
174         pw.println(indent + "playbackActive=" + mController.isPlaybackActive());
175     }
176 
177     @Override
toString()178     public String toString() {
179         // TODO(jaewan): Also add getId().
180         return getPackageName() + " (userId=" + getUserId() + ")";
181     }
182 
183     private class Controller2Callback extends MediaController2.ControllerCallback {
184         @Override
onConnected(MediaController2 controller, Session2CommandGroup allowedCommands)185         public void onConnected(MediaController2 controller, Session2CommandGroup allowedCommands) {
186             if (DEBUG) {
187                 Log.d(TAG, "connected to " + mSessionToken + ", allowed=" + allowedCommands);
188             }
189             MediaSessionService service;
190             synchronized (mLock) {
191                 mIsConnected = true;
192                 service = mService;
193             }
194             service.onSessionActiveStateChanged(MediaSession2Record.this);
195         }
196 
197         @Override
onDisconnected(MediaController2 controller)198         public void onDisconnected(MediaController2 controller) {
199             if (DEBUG) {
200                 Log.d(TAG, "disconnected from " + mSessionToken);
201             }
202             MediaSessionService service;
203             synchronized (mLock) {
204                 mIsConnected = false;
205                 service = mService;
206             }
207             service.onSessionDied(MediaSession2Record.this);
208         }
209 
210         @Override
onPlaybackActiveChanged(MediaController2 controller, boolean playbackActive)211         public void onPlaybackActiveChanged(MediaController2 controller, boolean playbackActive) {
212             if (DEBUG) {
213                 Log.d(TAG, "playback active changed, " + mSessionToken + ", active="
214                         + playbackActive);
215             }
216             MediaSessionService service;
217             synchronized (mLock) {
218                 service = mService;
219             }
220             service.onSessionPlaybackStateChanged(MediaSession2Record.this, playbackActive);
221         }
222     }
223 }
224