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