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.app.ActivityManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.net.LinkCapabilities;
26import android.net.LinkProperties;
27import android.os.Binder;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.Message;
32import android.os.RemoteException;
33import android.os.UserHandle;
34import android.telephony.CellLocation;
35import android.telephony.PhoneStateListener;
36import android.telephony.ServiceState;
37import android.telephony.SignalStrength;
38import android.telephony.CellInfo;
39import android.telephony.TelephonyManager;
40import android.text.TextUtils;
41import android.util.Slog;
42
43import java.util.ArrayList;
44import java.util.List;
45import java.io.FileDescriptor;
46import java.io.PrintWriter;
47
48import com.android.internal.app.IBatteryStats;
49import com.android.internal.telephony.ITelephonyRegistry;
50import com.android.internal.telephony.IPhoneStateListener;
51import com.android.internal.telephony.DefaultPhoneNotifier;
52import com.android.internal.telephony.PhoneConstants;
53import com.android.internal.telephony.ServiceStateTracker;
54import com.android.internal.telephony.TelephonyIntents;
55import com.android.server.am.BatteryStatsService;
56
57/**
58 * Since phone process can be restarted, this class provides a centralized place
59 * that applications can register and be called back from.
60 */
61class TelephonyRegistry extends ITelephonyRegistry.Stub {
62    private static final String TAG = "TelephonyRegistry";
63    private static final boolean DBG = false;
64    private static final boolean DBG_LOC = false;
65
66    private static class Record {
67        String pkgForDebug;
68
69        IBinder binder;
70
71        IPhoneStateListener callback;
72
73        int callerUid;
74
75        int events;
76
77        @Override
78        public String toString() {
79            return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid +
80                    " events=" + Integer.toHexString(events) + "}";
81        }
82    }
83
84    private final Context mContext;
85
86    // access should be inside synchronized (mRecords) for these two fields
87    private final ArrayList<IBinder> mRemoveList = new ArrayList<IBinder>();
88    private final ArrayList<Record> mRecords = new ArrayList<Record>();
89
90    private final IBatteryStats mBatteryStats;
91
92    private int mCallState = TelephonyManager.CALL_STATE_IDLE;
93
94    private String mCallIncomingNumber = "";
95
96    private ServiceState mServiceState = new ServiceState();
97
98    private SignalStrength mSignalStrength = new SignalStrength();
99
100    private boolean mMessageWaiting = false;
101
102    private boolean mCallForwarding = false;
103
104    private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE;
105
106    private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN;
107
108    private boolean mDataConnectionPossible = false;
109
110    private String mDataConnectionReason = "";
111
112    private String mDataConnectionApn = "";
113
114    private ArrayList<String> mConnectedApns;
115
116    private LinkProperties mDataConnectionLinkProperties;
117
118    private LinkCapabilities mDataConnectionLinkCapabilities;
119
120    private Bundle mCellLocation = new Bundle();
121
122    private int mDataConnectionNetworkType;
123
124    private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
125
126    private List<CellInfo> mCellInfo = null;
127
128    static final int PHONE_STATE_PERMISSION_MASK =
129                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
130                PhoneStateListener.LISTEN_CALL_STATE |
131                PhoneStateListener.LISTEN_DATA_ACTIVITY |
132                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
133                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
134
135    private static final int MSG_USER_SWITCHED = 1;
136
137    private final Handler mHandler = new Handler() {
138        @Override
139        public void handleMessage(Message msg) {
140            switch (msg.what) {
141                case MSG_USER_SWITCHED: {
142                    if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1);
143                    TelephonyRegistry.this.notifyCellLocation(mCellLocation);
144                    break;
145                }
146            }
147        }
148    };
149
150    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
151        @Override
152        public void onReceive(Context context, Intent intent) {
153            String action = intent.getAction();
154            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
155                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
156                       intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
157            }
158        }
159    };
160
161    // we keep a copy of all of the state so we can send it out when folks
162    // register for it
163    //
164    // In these calls we call with the lock held. This is safe becasuse remote
165    // calls go through a oneway interface and local calls going through a
166    // handler before they get to app code.
167
168    TelephonyRegistry(Context context) {
169        CellLocation  location = CellLocation.getEmpty();
170
171        // Note that location can be null for non-phone builds like
172        // like the generic one.
173        if (location != null) {
174            location.fillInNotifierBundle(mCellLocation);
175        }
176        mContext = context;
177        mBatteryStats = BatteryStatsService.getService();
178        mConnectedApns = new ArrayList<String>();
179    }
180
181    public void systemReady() {
182        // Watch for interesting updates
183        final IntentFilter filter = new IntentFilter();
184        filter.addAction(Intent.ACTION_USER_SWITCHED);
185        filter.addAction(Intent.ACTION_USER_REMOVED);
186        mContext.registerReceiver(mBroadcastReceiver, filter);
187    }
188
189    @Override
190    public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
191            boolean notifyNow) {
192        int callerUid = UserHandle.getCallingUserId();
193        int myUid = UserHandle.myUserId();
194        if (DBG) {
195            Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
196                + " myUid=" + myUid
197                + " callerUid=" + callerUid);
198        }
199        if (events != 0) {
200            /* Checks permission and throws Security exception */
201            checkListenerPermission(events);
202
203            synchronized (mRecords) {
204                // register
205                Record r = null;
206                find_and_add: {
207                    IBinder b = callback.asBinder();
208                    final int N = mRecords.size();
209                    for (int i = 0; i < N; i++) {
210                        r = mRecords.get(i);
211                        if (b == r.binder) {
212                            break find_and_add;
213                        }
214                    }
215                    r = new Record();
216                    r.binder = b;
217                    r.callback = callback;
218                    r.pkgForDebug = pkgForDebug;
219                    r.callerUid = callerUid;
220                    mRecords.add(r);
221                    if (DBG) Slog.i(TAG, "listen: add new record=" + r);
222                }
223                int send = events & (events ^ r.events);
224                r.events = events;
225                if (notifyNow) {
226                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
227                        try {
228                            r.callback.onServiceStateChanged(new ServiceState(mServiceState));
229                        } catch (RemoteException ex) {
230                            remove(r.binder);
231                        }
232                    }
233                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
234                        try {
235                            int gsmSignalStrength = mSignalStrength.getGsmSignalStrength();
236                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
237                                    : gsmSignalStrength));
238                        } catch (RemoteException ex) {
239                            remove(r.binder);
240                        }
241                    }
242                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
243                        try {
244                            r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting);
245                        } catch (RemoteException ex) {
246                            remove(r.binder);
247                        }
248                    }
249                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
250                        try {
251                            r.callback.onCallForwardingIndicatorChanged(mCallForwarding);
252                        } catch (RemoteException ex) {
253                            remove(r.binder);
254                        }
255                    }
256                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
257                        try {
258                            if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation);
259                            r.callback.onCellLocationChanged(new Bundle(mCellLocation));
260                        } catch (RemoteException ex) {
261                            remove(r.binder);
262                        }
263                    }
264                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
265                        try {
266                            r.callback.onCallStateChanged(mCallState, mCallIncomingNumber);
267                        } catch (RemoteException ex) {
268                            remove(r.binder);
269                        }
270                    }
271                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
272                        try {
273                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
274                                mDataConnectionNetworkType);
275                        } catch (RemoteException ex) {
276                            remove(r.binder);
277                        }
278                    }
279                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
280                        try {
281                            r.callback.onDataActivity(mDataActivity);
282                        } catch (RemoteException ex) {
283                            remove(r.binder);
284                        }
285                    }
286                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
287                        try {
288                            r.callback.onSignalStrengthsChanged(mSignalStrength);
289                        } catch (RemoteException ex) {
290                            remove(r.binder);
291                        }
292                    }
293                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
294                        try {
295                            r.callback.onOtaspChanged(mOtaspMode);
296                        } catch (RemoteException ex) {
297                            remove(r.binder);
298                        }
299                    }
300                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
301                        try {
302                            if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo);
303                            r.callback.onCellInfoChanged(mCellInfo);
304                        } catch (RemoteException ex) {
305                            remove(r.binder);
306                        }
307                    }
308                }
309            }
310        } else {
311            remove(callback.asBinder());
312        }
313    }
314
315    private void remove(IBinder binder) {
316        synchronized (mRecords) {
317            final int recordCount = mRecords.size();
318            for (int i = 0; i < recordCount; i++) {
319                if (mRecords.get(i).binder == binder) {
320                    mRecords.remove(i);
321                    return;
322                }
323            }
324        }
325    }
326
327    public void notifyCallState(int state, String incomingNumber) {
328        if (!checkNotifyPermission("notifyCallState()")) {
329            return;
330        }
331        synchronized (mRecords) {
332            mCallState = state;
333            mCallIncomingNumber = incomingNumber;
334            for (Record r : mRecords) {
335                if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
336                    try {
337                        r.callback.onCallStateChanged(state, incomingNumber);
338                    } catch (RemoteException ex) {
339                        mRemoveList.add(r.binder);
340                    }
341                }
342            }
343            handleRemoveListLocked();
344        }
345        broadcastCallStateChanged(state, incomingNumber);
346    }
347
348    public void notifyServiceState(ServiceState state) {
349        if (!checkNotifyPermission("notifyServiceState()")){
350            return;
351        }
352        synchronized (mRecords) {
353            mServiceState = state;
354            for (Record r : mRecords) {
355                if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
356                    try {
357                        r.callback.onServiceStateChanged(new ServiceState(state));
358                    } catch (RemoteException ex) {
359                        mRemoveList.add(r.binder);
360                    }
361                }
362            }
363            handleRemoveListLocked();
364        }
365        broadcastServiceStateChanged(state);
366    }
367
368    public void notifySignalStrength(SignalStrength signalStrength) {
369        if (!checkNotifyPermission("notifySignalStrength()")) {
370            return;
371        }
372        synchronized (mRecords) {
373            mSignalStrength = signalStrength;
374            for (Record r : mRecords) {
375                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
376                    try {
377                        r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
378                    } catch (RemoteException ex) {
379                        mRemoveList.add(r.binder);
380                    }
381                }
382                if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
383                    try {
384                        int gsmSignalStrength = signalStrength.getGsmSignalStrength();
385                        r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
386                                : gsmSignalStrength));
387                    } catch (RemoteException ex) {
388                        mRemoveList.add(r.binder);
389                    }
390                }
391            }
392            handleRemoveListLocked();
393        }
394        broadcastSignalStrengthChanged(signalStrength);
395    }
396
397    public void notifyCellInfo(List<CellInfo> cellInfo) {
398        if (!checkNotifyPermission("notifyCellInfo()")) {
399            return;
400        }
401
402        synchronized (mRecords) {
403            mCellInfo = cellInfo;
404            for (Record r : mRecords) {
405                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
406                    try {
407                        if (DBG_LOC) {
408                            Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r);
409                        }
410                        r.callback.onCellInfoChanged(cellInfo);
411                    } catch (RemoteException ex) {
412                        mRemoveList.add(r.binder);
413                    }
414                }
415            }
416            handleRemoveListLocked();
417        }
418    }
419
420    public void notifyMessageWaitingChanged(boolean mwi) {
421        if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
422            return;
423        }
424        synchronized (mRecords) {
425            mMessageWaiting = mwi;
426            for (Record r : mRecords) {
427                if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
428                    try {
429                        r.callback.onMessageWaitingIndicatorChanged(mwi);
430                    } catch (RemoteException ex) {
431                        mRemoveList.add(r.binder);
432                    }
433                }
434            }
435            handleRemoveListLocked();
436        }
437    }
438
439    public void notifyCallForwardingChanged(boolean cfi) {
440        if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
441            return;
442        }
443        synchronized (mRecords) {
444            mCallForwarding = cfi;
445            for (Record r : mRecords) {
446                if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
447                    try {
448                        r.callback.onCallForwardingIndicatorChanged(cfi);
449                    } catch (RemoteException ex) {
450                        mRemoveList.add(r.binder);
451                    }
452                }
453            }
454            handleRemoveListLocked();
455        }
456    }
457
458    public void notifyDataActivity(int state) {
459        if (!checkNotifyPermission("notifyDataActivity()" )) {
460            return;
461        }
462        synchronized (mRecords) {
463            mDataActivity = state;
464            for (Record r : mRecords) {
465                if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
466                    try {
467                        r.callback.onDataActivity(state);
468                    } catch (RemoteException ex) {
469                        mRemoveList.add(r.binder);
470                    }
471                }
472            }
473            handleRemoveListLocked();
474        }
475    }
476
477    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
478            String reason, String apn, String apnType, LinkProperties linkProperties,
479            LinkCapabilities linkCapabilities, int networkType, boolean roaming) {
480        if (!checkNotifyPermission("notifyDataConnection()" )) {
481            return;
482        }
483        if (DBG) {
484            Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible="
485                + isDataConnectivityPossible + " reason='" + reason
486                + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
487                + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
488        }
489        synchronized (mRecords) {
490            boolean modified = false;
491            if (state == TelephonyManager.DATA_CONNECTED) {
492                if (!mConnectedApns.contains(apnType)) {
493                    mConnectedApns.add(apnType);
494                    if (mDataConnectionState != state) {
495                        mDataConnectionState = state;
496                        modified = true;
497                    }
498                }
499            } else {
500                if (mConnectedApns.remove(apnType)) {
501                    if (mConnectedApns.isEmpty()) {
502                        mDataConnectionState = state;
503                        modified = true;
504                    } else {
505                        // leave mDataConnectionState as is and
506                        // send out the new status for the APN in question.
507                    }
508                }
509            }
510            mDataConnectionPossible = isDataConnectivityPossible;
511            mDataConnectionReason = reason;
512            mDataConnectionLinkProperties = linkProperties;
513            mDataConnectionLinkCapabilities = linkCapabilities;
514            if (mDataConnectionNetworkType != networkType) {
515                mDataConnectionNetworkType = networkType;
516                // need to tell registered listeners about the new network type
517                modified = true;
518            }
519            if (modified) {
520                if (DBG) {
521                    Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState
522                        + ", " + mDataConnectionNetworkType + ")");
523                }
524                for (Record r : mRecords) {
525                    if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
526                        try {
527                            r.callback.onDataConnectionStateChanged(mDataConnectionState,
528                                    mDataConnectionNetworkType);
529                        } catch (RemoteException ex) {
530                            mRemoveList.add(r.binder);
531                        }
532                    }
533                }
534                handleRemoveListLocked();
535            }
536        }
537        broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
538                apnType, linkProperties, linkCapabilities, roaming);
539    }
540
541    public void notifyDataConnectionFailed(String reason, String apnType) {
542        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
543            return;
544        }
545        /*
546         * This is commented out because there is no onDataConnectionFailed callback
547         * in PhoneStateListener. There should be.
548        synchronized (mRecords) {
549            mDataConnectionFailedReason = reason;
550            final int N = mRecords.size();
551            for (int i=N-1; i>=0; i--) {
552                Record r = mRecords.get(i);
553                if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
554                    // XXX
555                }
556            }
557        }
558        */
559        broadcastDataConnectionFailed(reason, apnType);
560    }
561
562    public void notifyCellLocation(Bundle cellLocation) {
563        if (!checkNotifyPermission("notifyCellLocation()")) {
564            return;
565        }
566        synchronized (mRecords) {
567            mCellLocation = cellLocation;
568            for (Record r : mRecords) {
569                if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
570                    try {
571                        if (DBG_LOC) {
572                            Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation
573                                    + " r=" + r);
574                        }
575                        r.callback.onCellLocationChanged(new Bundle(cellLocation));
576                    } catch (RemoteException ex) {
577                        mRemoveList.add(r.binder);
578                    }
579
580                }
581            }
582            handleRemoveListLocked();
583        }
584    }
585
586    public void notifyOtaspChanged(int otaspMode) {
587        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
588            return;
589        }
590        synchronized (mRecords) {
591            mOtaspMode = otaspMode;
592            for (Record r : mRecords) {
593                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
594                    try {
595                        r.callback.onOtaspChanged(otaspMode);
596                    } catch (RemoteException ex) {
597                        mRemoveList.add(r.binder);
598                    }
599                }
600            }
601            handleRemoveListLocked();
602        }
603    }
604
605    @Override
606    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
607        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
608                != PackageManager.PERMISSION_GRANTED) {
609            pw.println("Permission Denial: can't dump telephony.registry from from pid="
610                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
611            return;
612        }
613        synchronized (mRecords) {
614            final int recordCount = mRecords.size();
615            pw.println("last known state:");
616            pw.println("  mCallState=" + mCallState);
617            pw.println("  mCallIncomingNumber=" + mCallIncomingNumber);
618            pw.println("  mServiceState=" + mServiceState);
619            pw.println("  mSignalStrength=" + mSignalStrength);
620            pw.println("  mMessageWaiting=" + mMessageWaiting);
621            pw.println("  mCallForwarding=" + mCallForwarding);
622            pw.println("  mDataActivity=" + mDataActivity);
623            pw.println("  mDataConnectionState=" + mDataConnectionState);
624            pw.println("  mDataConnectionPossible=" + mDataConnectionPossible);
625            pw.println("  mDataConnectionReason=" + mDataConnectionReason);
626            pw.println("  mDataConnectionApn=" + mDataConnectionApn);
627            pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties);
628            pw.println("  mDataConnectionLinkCapabilities=" + mDataConnectionLinkCapabilities);
629            pw.println("  mCellLocation=" + mCellLocation);
630            pw.println("  mCellInfo=" + mCellInfo);
631            pw.println("registrations: count=" + recordCount);
632            for (Record r : mRecords) {
633                pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
634            }
635        }
636    }
637
638    //
639    // the legacy intent broadcasting
640    //
641
642    private void broadcastServiceStateChanged(ServiceState state) {
643        long ident = Binder.clearCallingIdentity();
644        try {
645            mBatteryStats.notePhoneState(state.getState());
646        } catch (RemoteException re) {
647            // Can't do much
648        } finally {
649            Binder.restoreCallingIdentity(ident);
650        }
651
652        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
653        Bundle data = new Bundle();
654        state.fillInNotifierBundle(data);
655        intent.putExtras(data);
656        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
657    }
658
659    private void broadcastSignalStrengthChanged(SignalStrength signalStrength) {
660        long ident = Binder.clearCallingIdentity();
661        try {
662            mBatteryStats.notePhoneSignalStrength(signalStrength);
663        } catch (RemoteException e) {
664            /* The remote entity disappeared, we can safely ignore the exception. */
665        } finally {
666            Binder.restoreCallingIdentity(ident);
667        }
668
669        Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
670        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
671        Bundle data = new Bundle();
672        signalStrength.fillInNotifierBundle(data);
673        intent.putExtras(data);
674        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
675    }
676
677    private void broadcastCallStateChanged(int state, String incomingNumber) {
678        long ident = Binder.clearCallingIdentity();
679        try {
680            if (state == TelephonyManager.CALL_STATE_IDLE) {
681                mBatteryStats.notePhoneOff();
682            } else {
683                mBatteryStats.notePhoneOn();
684            }
685        } catch (RemoteException e) {
686            /* The remote entity disappeared, we can safely ignore the exception. */
687        } finally {
688            Binder.restoreCallingIdentity(ident);
689        }
690
691        Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
692        intent.putExtra(PhoneConstants.STATE_KEY,
693                DefaultPhoneNotifier.convertCallState(state).toString());
694        if (!TextUtils.isEmpty(incomingNumber)) {
695            intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
696        }
697        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
698                android.Manifest.permission.READ_PHONE_STATE);
699    }
700
701    private void broadcastDataConnectionStateChanged(int state,
702            boolean isDataConnectivityPossible,
703            String reason, String apn, String apnType, LinkProperties linkProperties,
704            LinkCapabilities linkCapabilities, boolean roaming) {
705        // Note: not reporting to the battery stats service here, because the
706        // status bar takes care of that after taking into account all of the
707        // required info.
708        Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
709        intent.putExtra(PhoneConstants.STATE_KEY,
710                DefaultPhoneNotifier.convertDataState(state).toString());
711        if (!isDataConnectivityPossible) {
712            intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
713        }
714        if (reason != null) {
715            intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
716        }
717        if (linkProperties != null) {
718            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
719            String iface = linkProperties.getInterfaceName();
720            if (iface != null) {
721                intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
722            }
723        }
724        if (linkCapabilities != null) {
725            intent.putExtra(PhoneConstants.DATA_LINK_CAPABILITIES_KEY, linkCapabilities);
726        }
727        if (roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);
728
729        intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
730        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
731        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
732    }
733
734    private void broadcastDataConnectionFailed(String reason, String apnType) {
735        Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
736        intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
737        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
738        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
739    }
740
741    private boolean checkNotifyPermission(String method) {
742        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
743                == PackageManager.PERMISSION_GRANTED) {
744            return true;
745        }
746        String msg = "Modify Phone State Permission Denial: " + method + " from pid="
747                + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
748        if (DBG) Slog.w(TAG, msg);
749        return false;
750    }
751
752    private void checkListenerPermission(int events) {
753        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
754            mContext.enforceCallingOrSelfPermission(
755                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
756
757        }
758
759        if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
760            mContext.enforceCallingOrSelfPermission(
761                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
762
763        }
764
765        if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
766            mContext.enforceCallingOrSelfPermission(
767                    android.Manifest.permission.READ_PHONE_STATE, null);
768        }
769    }
770
771    private void handleRemoveListLocked() {
772        if (mRemoveList.size() > 0) {
773            for (IBinder b: mRemoveList) {
774                remove(b);
775            }
776            mRemoveList.clear();
777        }
778    }
779
780    private boolean validateEventsAndUserLocked(Record r, int events) {
781        int foregroundUser;
782        long callingIdentity = Binder.clearCallingIdentity();
783        boolean valid = false;
784        try {
785            foregroundUser = ActivityManager.getCurrentUser();
786            valid = r.callerUid ==  foregroundUser && (r.events & events) != 0;
787            if (DBG | DBG_LOC) {
788                Slog.d(TAG, "validateEventsAndUserLocked: valid=" + valid
789                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
790                        + " r.events=" + r.events + " events=" + events);
791            }
792        } finally {
793            Binder.restoreCallingIdentity(callingIdentity);
794        }
795        return valid;
796    }
797}
798