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