• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.systemui.media;
18 
19 import android.content.Context;
20 import android.media.IAudioService;
21 import android.media.IRingtonePlayer;
22 import android.media.Ringtone;
23 import android.net.Uri;
24 import android.os.Binder;
25 import android.os.IBinder;
26 import android.os.Process;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.util.Slog;
30 
31 import com.android.systemui.SystemUI;
32 import com.google.android.collect.Maps;
33 
34 import java.io.FileDescriptor;
35 import java.io.PrintWriter;
36 import java.util.HashMap;
37 
38 /**
39  * Service that offers to play ringtones by {@link Uri}, since our process has
40  * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}.
41  */
42 public class RingtonePlayer extends SystemUI {
43     private static final String TAG = "RingtonePlayer";
44     private static final boolean LOGD = false;
45 
46     // TODO: support Uri switching under same IBinder
47 
48     private IAudioService mAudioService;
49 
50     private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
51     private final HashMap<IBinder, Client> mClients = Maps.newHashMap();
52 
53     @Override
start()54     public void start() {
55         mAsyncPlayer.setUsesWakeLock(mContext);
56 
57         mAudioService = IAudioService.Stub.asInterface(
58                 ServiceManager.getService(Context.AUDIO_SERVICE));
59         try {
60             mAudioService.setRingtonePlayer(mCallback);
61         } catch (RemoteException e) {
62             Slog.e(TAG, "Problem registering RingtonePlayer: " + e);
63         }
64     }
65 
66     /**
67      * Represents an active remote {@link Ringtone} client.
68      */
69     private class Client implements IBinder.DeathRecipient {
70         private final IBinder mToken;
71         private final Ringtone mRingtone;
72 
Client(IBinder token, Uri uri, int streamType)73         public Client(IBinder token, Uri uri, int streamType) {
74             mToken = token;
75             mRingtone = new Ringtone(mContext, false);
76             mRingtone.setStreamType(streamType);
77             mRingtone.setUri(uri);
78         }
79 
80         @Override
binderDied()81         public void binderDied() {
82             if (LOGD) Slog.d(TAG, "binderDied() token=" + mToken);
83             synchronized (mClients) {
84                 mClients.remove(mToken);
85             }
86             mRingtone.stop();
87         }
88     }
89 
90     private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
91         @Override
92         public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
93             if (LOGD) Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ")");
94             Client client;
95             synchronized (mClients) {
96                 client = mClients.get(token);
97                 if (client == null) {
98                     client = new Client(token, uri, streamType);
99                     token.linkToDeath(client, 0);
100                     mClients.put(token, client);
101                 }
102             }
103             client.mRingtone.play();
104         }
105 
106         @Override
107         public void stop(IBinder token) {
108             if (LOGD) Slog.d(TAG, "stop(token=" + token + ")");
109             Client client;
110             synchronized (mClients) {
111                 client = mClients.remove(token);
112             }
113             if (client != null) {
114                 client.mToken.unlinkToDeath(client, 0);
115                 client.mRingtone.stop();
116             }
117         }
118 
119         @Override
120         public boolean isPlaying(IBinder token) {
121             if (LOGD) Slog.d(TAG, "isPlaying(token=" + token + ")");
122             Client client;
123             synchronized (mClients) {
124                 client = mClients.get(token);
125             }
126             if (client != null) {
127                 return client.mRingtone.isPlaying();
128             } else {
129                 return false;
130             }
131         }
132 
133         @Override
134         public void playAsync(Uri uri, boolean looping, int streamType) {
135             if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ")");
136             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
137                 throw new SecurityException("Async playback only available from system UID.");
138             }
139             mAsyncPlayer.play(mContext, uri, looping, streamType);
140         }
141 
142         @Override
143         public void stopAsync() {
144             if (LOGD) Slog.d(TAG, "stopAsync()");
145             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
146                 throw new SecurityException("Async playback only available from system UID.");
147             }
148             mAsyncPlayer.stop();
149         }
150     };
151 
152     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)153     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
154         pw.println("Clients:");
155         synchronized (mClients) {
156             for (Client client : mClients.values()) {
157                 pw.print("  mToken=");
158                 pw.print(client.mToken);
159                 pw.print(" mUri=");
160                 pw.println(client.mRingtone.getUri());
161             }
162         }
163     }
164 }
165