blob: 5e5fb935a1e8e26bc6adf2da34018c771b3f910e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package com.android.server;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.os.Binder;
23import android.os.Bundle;
24import android.os.IBinder;
25import android.os.RemoteException;
26import android.telephony.CellLocation;
27import android.telephony.PhoneStateListener;
28import android.telephony.ServiceState;
29import android.telephony.TelephonyManager;
30import android.text.TextUtils;
31
32import java.util.ArrayList;
33import java.io.FileDescriptor;
34import java.io.PrintWriter;
35
36import com.android.internal.app.IBatteryStats;
37import com.android.internal.telephony.ITelephonyRegistry;
38import com.android.internal.telephony.IPhoneStateListener;
39import com.android.internal.telephony.DefaultPhoneNotifier;
40import com.android.internal.telephony.Phone;
41import com.android.internal.telephony.PhoneStateIntentReceiver;
42import com.android.internal.telephony.TelephonyIntents;
43import com.android.server.am.BatteryStatsService;
44
45
46/**
47 * Since phone process can be restarted, this class provides a centralized
48 * place that applications can register and be called back from.
49 */
50class TelephonyRegistry extends ITelephonyRegistry.Stub {
51 private static final String TAG = "TelephonyRegistry";
52
53 private static class Record {
54 String pkgForDebug;
55 IBinder binder;
56 IPhoneStateListener callback;
57 int events;
58 }
59
60 private final Context mContext;
61 private final ArrayList<Record> mRecords = new ArrayList();
62 private final IBatteryStats mBatteryStats;
63
64 private int mCallState = TelephonyManager.CALL_STATE_IDLE;
65 private String mCallIncomingNumber = "";
66 private ServiceState mServiceState = new ServiceState();
67 private int mSignalStrength = -1;
68 private boolean mMessageWaiting = false;
69 private boolean mCallForwarding = false;
70 private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
71 private int mDataConnectionState = TelephonyManager.DATA_CONNECTED;
72 private boolean mDataConnectionPossible = false;
73 private String mDataConnectionReason = "";
74 private String mDataConnectionApn = "";
75 private String mDataConnectionInterfaceName = "";
76 private Bundle mCellLocation = new Bundle();
77
78 // we keep a copy of all of the sate so we can send it out when folks register for it
79 //
80 // In these calls we call with the lock held. This is safe becasuse remote
81 // calls go through a oneway interface and local calls going through a handler before
82 // they get to app code.
83
84 TelephonyRegistry(Context context) {
85 CellLocation.getEmpty().fillInNotifierBundle(mCellLocation);
86 mContext = context;
87 mBatteryStats = BatteryStatsService.getService();
88 }
89
90 public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
91 boolean notifyNow) {
92 //Log.d(TAG, "listen pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events));
93 if (events != 0) {
94 // check permissions
95 if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
96 mContext.enforceCallingOrSelfPermission(
97 android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
98
99 }
100
101 synchronized (mRecords) {
102 // register
103 Record r = null;
104 find_and_add: {
105 IBinder b = callback.asBinder();
106 final int N = mRecords.size();
107 for (int i=0; i<N; i++) {
108 r = mRecords.get(i);
109 if (b == r.binder) {
110 break find_and_add;
111 }
112 }
113 r = new Record();
114 r.binder = b;
115 r.callback = callback;
116 r.pkgForDebug = pkgForDebug;
117 mRecords.add(r);
118 }
119 int send = events & (events ^ r.events);
120 r.events = events;
121 if (notifyNow) {
122 if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
123 sendServiceState(r, mServiceState);
124 }
125 if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
126 try {
127 r.callback.onSignalStrengthChanged(mSignalStrength);
128 } catch (RemoteException ex) {
129 remove(r.binder);
130 }
131 }
132 if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
133 try {
134 r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
135 } catch (RemoteException ex) {
136 remove(r.binder);
137 }
138 }
139 if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
140 try {
141 r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
142 } catch (RemoteException ex) {
143 remove(r.binder);
144 }
145 }
146 if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
147 sendCellLocation(r, mCellLocation);
148 }
149 if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
150 try {
151 r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
152 } catch (RemoteException ex) {
153 remove(r.binder);
154 }
155 }
156 if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
157 try {
158 r.callback.onDataConnectionStateChanged(mDataConnectionState);
159 } catch (RemoteException ex) {
160 remove(r.binder);
161 }
162 }
163 if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
164 try {
165 r.callback.onDataActivity(mDataActivity);
166 } catch (RemoteException ex) {
167 remove(r.binder);
168 }
169 }
170 }
171 }
172 } else {
173 remove(callback.asBinder());
174 }
175 }
176
177 private void remove(IBinder binder) {
178 synchronized (mRecords) {
179 final int N = mRecords.size();
180 for (int i=0; i<N; i++) {
181 if (mRecords.get(i).binder == binder) {
182 mRecords.remove(i);
183 return;
184 }
185 }
186 }
187 }
188
189 public void notifyCallState(int state, String incomingNumber) {
190 synchronized (mRecords) {
191 mCallState = state;
192 mCallIncomingNumber = incomingNumber;
193 final int N = mRecords.size();
194 for (int i=N-1; i>=0; i--) {
195 Record r = mRecords.get(i);
196 if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
197 try {
198 r.callback.onCallStateChanged(state, incomingNumber);
199 } catch (RemoteException ex) {
200 remove(r.binder);
201 }
202 }
203 }
204 }
205 broadcastCallStateChanged(state, incomingNumber);
206 }
207
208 public void notifyServiceState(ServiceState state) {
209 synchronized (mRecords) {
210 mServiceState = state;
211 final int N = mRecords.size();
212 for (int i=N-1; i>=0; i--) {
213 Record r = mRecords.get(i);
214 if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
215 sendServiceState(r, state);
216 }
217 }
218 }
219 broadcastServiceStateChanged(state);
220 }
221
222 public void notifySignalStrength(int signalStrengthASU) {
223 synchronized (mRecords) {
224 mSignalStrength = signalStrengthASU;
225 final int N = mRecords.size();
226 for (int i=N-1; i>=0; i--) {
227 Record r = mRecords.get(i);
228 if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
229 try {
230 r.callback.onSignalStrengthChanged(signalStrengthASU);
231 } catch (RemoteException ex) {
232 remove(r.binder);
233 }
234 }
235 }
236 }
237 broadcastSignalStrengthChanged(signalStrengthASU);
238 }
239
240 public void notifyMessageWaitingChanged(boolean mwi) {
241 synchronized (mRecords) {
242 mMessageWaiting = mwi;
243 final int N = mRecords.size();
244 for (int i=N-1; i>=0; i--) {
245 Record r = mRecords.get(i);
246 if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
247 try {
248 r.callback.onMessageWaitingIndicatorChanged(mwi);
249 } catch (RemoteException ex) {
250 remove(r.binder);
251 }
252 }
253 }
254 }
255 }
256
257 public void notifyCallForwardingChanged(boolean cfi) {
258 synchronized (mRecords) {
259 mCallForwarding = cfi;
260 final int N = mRecords.size();
261 for (int i=N-1; i>=0; i--) {
262 Record r = mRecords.get(i);
263 if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
264 try {
265 r.callback.onCallForwardingIndicatorChanged(cfi);
266 } catch (RemoteException ex) {
267 remove(r.binder);
268 }
269 }
270 }
271 }
272 }
273
274 public void notifyDataActivity(int state) {
275 synchronized (mRecords) {
276 mDataActivity = state;
277 final int N = mRecords.size();
278 for (int i=N-1; i>=0; i--) {
279 Record r = mRecords.get(i);
280 if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
281 try {
282 r.callback.onDataActivity(state);
283 } catch (RemoteException ex) {
284 remove(r.binder);
285 }
286 }
287 }
288 }
289 }
290
291 public void notifyDataConnection(int state, boolean isDataConnectivityPissible,
292 String reason, String apn, String interfaceName) {
293 synchronized (mRecords) {
294 mDataConnectionState = state;
295 mDataConnectionPossible = isDataConnectivityPissible;
296 mDataConnectionReason = reason;
297 mDataConnectionApn = apn;
298 mDataConnectionInterfaceName = interfaceName;
299 final int N = mRecords.size();
300 for (int i=N-1; i>=0; i--) {
301 Record r = mRecords.get(i);
302 if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
303 try {
304 r.callback.onDataConnectionStateChanged(state);
305 } catch (RemoteException ex) {
306 remove(r.binder);
307 }
308 }
309 }
310 }
311 broadcastDataConnectionStateChanged(state, isDataConnectivityPissible,
312 reason, apn, interfaceName);
313 }
314
315 public void notifyDataConnectionFailed(String reason) {
316 /*
317 * This is commented out because there is on onDataConnectionFailed callback
318 * on PhoneStateListener. There should be.
319 synchronized (mRecords) {
320 mDataConnectionFailedReason = reason;
321 final int N = mRecords.size();
322 for (int i=N-1; i>=0; i--) {
323 Record r = mRecords.get(i);
324 if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
325 // XXX
326 }
327 }
328 }
329 */
330 broadcastDataConnectionFailed(reason);
331 }
332
333 public void notifyCellLocation(Bundle cellLocation) {
334 synchronized (mRecords) {
335 mCellLocation = cellLocation;
336 final int N = mRecords.size();
337 for (int i=N-1; i>=0; i--) {
338 Record r = mRecords.get(i);
339 if ((r.events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
340 sendCellLocation(r, cellLocation);
341 }
342 }
343 }
344 }
345
346 //
347 // the new callback broadcasting
348 //
349 // copy the service state object so they can't mess it up in the local calls
350 //
351 public void sendServiceState(Record r, ServiceState state) {
352 try {
353 r.callback.onServiceStateChanged(new ServiceState(state));
354 } catch (RemoteException ex) {
355 remove(r.binder);
356 }
357 }
358
359 public void sendCellLocation(Record r, Bundle cellLocation) {
360 try {
361 r.callback.onCellLocationChanged(new Bundle(cellLocation));
362 } catch (RemoteException ex) {
363 remove(r.binder);
364 }
365 }
366
367
368 @Override
369 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
370 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
371 != PackageManager.PERMISSION_GRANTED) {
372 pw.println("Permission Denial: can't dump telephony.registry from from pid="
373 + Binder.getCallingPid()
374 + ", uid=" + Binder.getCallingUid());
375 return;
376 }
377 synchronized (mRecords) {
378 final int N = mRecords.size();
379 pw.println("last known state:");
380 pw.println(" mCallState=" + mCallState);
381 pw.println(" mCallIncomingNumber=" + mCallIncomingNumber);
382 pw.println(" mServiceState=" + mServiceState);
383 pw.println(" mSignalStrength=" + mSignalStrength);
384 pw.println(" mMessageWaiting=" + mMessageWaiting);
385 pw.println(" mCallForwarding=" + mCallForwarding);
386 pw.println(" mDataActivity=" + mDataActivity);
387 pw.println(" mDataConnectionState=" + mDataConnectionState);
388 pw.println(" mDataConnectionPossible=" + mDataConnectionPossible);
389 pw.println(" mDataConnectionReason=" + mDataConnectionReason);
390 pw.println(" mDataConnectionApn=" + mDataConnectionApn);
391 pw.println(" mDataConnectionInterfaceName=" + mDataConnectionInterfaceName);
392 pw.println(" mCellLocation=" + mCellLocation);
393 pw.println("registrations: count=" + N);
394 for (int i=0; i<N; i++) {
395 Record r = mRecords.get(i);
396 pw.println(" " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
397 }
398 }
399 }
400
401
402 //
403 // the legacy intent broadcasting
404 //
405
406 private void broadcastServiceStateChanged(ServiceState state) {
407 Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
408 Bundle data = new Bundle();
409 state.fillInNotifierBundle(data);
410 intent.putExtras(data);
411 mContext.sendStickyBroadcast(intent);
412 }
413
414 private void broadcastSignalStrengthChanged(int asu) {
415 Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
416 intent.putExtra(PhoneStateIntentReceiver.INTENT_KEY_ASU, asu);
417 mContext.sendStickyBroadcast(intent);
418 }
419
420 private void broadcastCallStateChanged(int state, String incomingNumber) {
421 long ident = Binder.clearCallingIdentity();
422 try {
423 if (state == TelephonyManager.CALL_STATE_IDLE) {
424 mBatteryStats.notePhoneOff();
425 } else {
426 mBatteryStats.notePhoneOn();
427 }
428 } catch (RemoteException e) {
429 } finally {
430 Binder.restoreCallingIdentity(ident);
431 }
432
433 Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
434 intent.putExtra(Phone.STATE_KEY,
435 DefaultPhoneNotifier.convertCallState(state).toString());
436 if (!TextUtils.isEmpty(incomingNumber)) {
437 intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
438 }
439 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);
440 }
441
442 private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible,
443 String reason, String apn, String interfaceName) {
444 Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
445 intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
446 if (!isDataConnectivityPossible) {
447 intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true);
448 }
449 if (reason != null) {
450 intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason);
451 }
452 intent.putExtra(Phone.DATA_APN_KEY, apn);
453 intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName);
454 mContext.sendStickyBroadcast(intent);
455 }
456
457 private void broadcastDataConnectionFailed(String reason) {
458 Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
459 intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
460 mContext.sendStickyBroadcast(intent);
461 }
462}