TelephonyRegistry.java revision f013e1afd1e68af5e3b868c26a653bbfb39538f8
1/* 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.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 43 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); 407 mContext.sendStickyBroadcast(intent); 408 } 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); 413 mContext.sendStickyBroadcast(intent); 414 } 415 416 private void broadcastCallStateChanged(int state, String incomingNumber) { 417 Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED); 418 intent.putExtra(Phone.STATE_KEY, 419 DefaultPhoneNotifier.convertCallState(state).toString()); 420 if (!TextUtils.isEmpty(incomingNumber)) { 421 intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); 422 } 423 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); 424 } 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); 438 mContext.sendStickyBroadcast(intent); 439 } 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); 444 mContext.sendStickyBroadcast(intent); 445 } 446} 447