TelephonyRegistry.java revision 2f32ac25e94b9451f9004c8a5679762d3fdd9acd
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.LinkProperties;
26import android.net.NetworkCapabilities;
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.DataConnectionRealTimeInfo;
36import android.telephony.Rlog;
37import android.telephony.TelephonyManager;
38import android.telephony.SubscriptionManager;
39import android.telephony.PhoneStateListener;
40import android.telephony.ServiceState;
41import android.telephony.SignalStrength;
42import android.telephony.CellInfo;
43import android.telephony.VoLteServiceState;
44import android.telephony.TelephonyManager;
45import android.telephony.DisconnectCause;
46import android.telephony.PreciseCallState;
47import android.telephony.PreciseDataConnectionState;
48import android.telephony.PreciseDisconnectCause;
49import android.text.TextUtils;
50import android.text.format.Time;
51
52import java.util.ArrayList;
53import java.util.Calendar;
54import java.util.List;
55import java.io.FileDescriptor;
56import java.io.PrintWriter;
57
58import com.android.internal.app.IBatteryStats;
59import com.android.internal.telephony.ITelephonyRegistry;
60import com.android.internal.telephony.IPhoneStateListener;
61import com.android.internal.telephony.DefaultPhoneNotifier;
62import com.android.internal.telephony.PhoneConstants;
63import com.android.internal.telephony.ServiceStateTracker;
64import com.android.internal.telephony.TelephonyIntents;
65import com.android.server.am.BatteryStatsService;
66
67/**
68 * Since phone process can be restarted, this class provides a centralized place
69 * that applications can register and be called back from.
70 */
71class TelephonyRegistry extends ITelephonyRegistry.Stub {
72    private static final String TAG = "TelephonyRegistry";
73    private static final boolean DBG = false; // STOPSHIP if true
74    private static final boolean DBG_LOC = false; // STOPSHIP if true
75    private static final boolean VDBG = false; // STOPSHIP if true
76
77    private static class Record {
78        String pkgForDebug;
79
80        IBinder binder;
81
82        IPhoneStateListener callback;
83
84        int callerUid;
85
86        int events;
87
88        long subId;
89
90        boolean isLegacyApp;
91
92        @Override
93        public String toString() {
94            return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid + " subId=" + subId +
95                    " events=" + Integer.toHexString(events) + "}";
96        }
97    }
98
99    private final Context mContext;
100
101    // access should be inside synchronized (mRecords) for these two fields
102    private final ArrayList<IBinder> mRemoveList = new ArrayList<IBinder>();
103    private final ArrayList<Record> mRecords = new ArrayList<Record>();
104
105    private final IBatteryStats mBatteryStats;
106
107    private int mNumPhones;
108
109    private int[] mCallState;
110
111    private String[] mCallIncomingNumber;
112
113    private ServiceState[] mServiceState;
114
115    private SignalStrength[] mSignalStrength;
116
117    private boolean[] mMessageWaiting;
118
119    private boolean[] mCallForwarding;
120
121    private int[] mDataActivity;
122
123    private int[] mDataConnectionState;
124
125    private boolean[] mDataConnectionPossible;
126
127    private String[] mDataConnectionReason;
128
129    private String[] mDataConnectionApn;
130
131    private ArrayList<String> mConnectedApns;
132
133    private LinkProperties[] mDataConnectionLinkProperties;
134
135    private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
136
137    private Bundle[] mCellLocation;
138
139    private int[] mDataConnectionNetworkType;
140
141    private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN;
142
143    private ArrayList<List<CellInfo>> mCellInfo = null;
144
145    private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
146
147    private long mDefaultSubId;
148
149    private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
150
151    private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
152
153    private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
154
155    private int mBackgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
156
157    private PreciseCallState mPreciseCallState = new PreciseCallState();
158
159    private PreciseDataConnectionState mPreciseDataConnectionState =
160                new PreciseDataConnectionState();
161
162    static final int PHONE_STATE_PERMISSION_MASK =
163                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
164                PhoneStateListener.LISTEN_CALL_STATE |
165                PhoneStateListener.LISTEN_DATA_ACTIVITY |
166                PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
167                PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
168                PhoneStateListener.LISTEN_VOLTE_STATE;;
169
170    static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
171                PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
172                PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
173
174    private static final int MSG_USER_SWITCHED = 1;
175    private static final int MSG_UPDATE_DEFAULT_SUB = 2;
176
177    private final Handler mHandler = new Handler() {
178        @Override
179        public void handleMessage(Message msg) {
180            switch (msg.what) {
181                case MSG_USER_SWITCHED: {
182                    log("MSG_USER_SWITCHED userId=" + msg.arg1);
183                    int numPhones = TelephonyManager.getDefault().getPhoneCount();
184                    for (int sub = 0; sub < numPhones; sub++) {
185                        TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]);
186                    }
187                    break;
188                }
189                case MSG_UPDATE_DEFAULT_SUB: {
190                    log("MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId);
191                    // Default subscription id changed, update the changed default subscription
192                    // id in  all the legacy application listener records.
193                    synchronized (mRecords) {
194                        for (Record r : mRecords) {
195                            // FIXME: Be sure we're using isLegacyApp correctly!
196                            if (r.isLegacyApp == true) {
197                                r.subId = mDefaultSubId;
198                            }
199                        }
200                    }
201                    break;
202                }
203            }
204        }
205    };
206
207    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
208        @Override
209        public void onReceive(Context context, Intent intent) {
210            String action = intent.getAction();
211            log("mBroadcastReceiver: action=" + action);
212            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
213                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
214                if (DBG) log("onReceive: userHandle=" + userHandle);
215                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
216            } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
217                mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
218                        SubscriptionManager.getDefaultSubId());
219                if (DBG) log("onReceive: mDefaultSubId=" + mDefaultSubId);
220                mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0));
221            }
222        }
223    };
224
225    // we keep a copy of all of the state so we can send it out when folks
226    // register for it
227    //
228    // In these calls we call with the lock held. This is safe becasuse remote
229    // calls go through a oneway interface and local calls going through a
230    // handler before they get to app code.
231
232    TelephonyRegistry(Context context) {
233        CellLocation  location = CellLocation.getEmpty();
234
235        mContext = context;
236        mBatteryStats = BatteryStatsService.getService();
237        mConnectedApns = new ArrayList<String>();
238
239        // Initialize default subscription to be used for single standby.
240        mDefaultSubId = SubscriptionManager.getDefaultSubId();
241
242        int numPhones = TelephonyManager.getDefault().getPhoneCount();
243        if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones);
244        mNumPhones = numPhones;
245        mCallState = new int[numPhones];
246        mDataActivity = new int[numPhones];
247        mDataConnectionState = new int[numPhones];
248        mDataConnectionNetworkType = new int[numPhones];
249        mCallIncomingNumber = new String[numPhones];
250        mServiceState = new ServiceState[numPhones];
251        mSignalStrength = new SignalStrength[numPhones];
252        mMessageWaiting = new boolean[numPhones];
253        mDataConnectionPossible = new boolean[numPhones];
254        mDataConnectionReason = new String[numPhones];
255        mDataConnectionApn = new String[numPhones];
256        mCallForwarding = new boolean[numPhones];
257        mCellLocation = new Bundle[numPhones];
258        mDataConnectionLinkProperties = new LinkProperties[numPhones];
259        mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
260        mCellInfo = new ArrayList<List<CellInfo>>();
261        for (int i = 0; i < numPhones; i++) {
262            mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
263            mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
264            mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
265            mCallIncomingNumber[i] =  "";
266            mServiceState[i] =  new ServiceState();
267            mSignalStrength[i] =  new SignalStrength();
268            mMessageWaiting[i] =  false;
269            mCallForwarding[i] =  false;
270            mDataConnectionPossible[i] = false;
271            mDataConnectionReason[i] =  "";
272            mDataConnectionApn[i] =  "";
273            mCellLocation[i] = new Bundle();
274            mCellInfo.add(i, null);
275        }
276
277        // Note that location can be null for non-phone builds like
278        // like the generic one.
279        if (location != null) {
280            for (int i = 0; i < numPhones; i++) {
281                location.fillInNotifierBundle(mCellLocation[i]);
282            }
283        }
284        mConnectedApns = new ArrayList<String>();
285    }
286
287    public void systemRunning() {
288        // Watch for interesting updates
289        final IntentFilter filter = new IntentFilter();
290        filter.addAction(Intent.ACTION_USER_SWITCHED);
291        filter.addAction(Intent.ACTION_USER_REMOVED);
292        filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
293        log("systemRunning register for intents");
294        mContext.registerReceiver(mBroadcastReceiver, filter);
295    }
296
297    @Override
298    public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
299            boolean notifyNow) {
300        listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true);
301    }
302
303    @Override
304    public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback,
305            int events, boolean notifyNow) {
306        listen(pkgForDebug, callback, events, notifyNow, subId, false);
307    }
308
309    private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
310            boolean notifyNow, long subId, boolean isLegacyApp) {
311        int callerUid = UserHandle.getCallingUserId();
312        int myUid = UserHandle.myUserId();
313        if (true /*VDBG*/) {
314            log("listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events)
315                + " notifyNow=" + notifyNow + " subId=" + subId
316                + " isLegacyApp=" + isLegacyApp
317                + " myUid=" + myUid
318                + " callerUid=" + callerUid);
319        }
320        if (events != 0) {
321            /* Checks permission and throws Security exception */
322            checkListenerPermission(events);
323
324            synchronized (mRecords) {
325                // register
326                Record r = null;
327                find_and_add: {
328                    IBinder b = callback.asBinder();
329                    final int N = mRecords.size();
330                    for (int i = 0; i < N; i++) {
331                        r = mRecords.get(i);
332                        if (b == r.binder) {
333                            break find_and_add;
334                        }
335                    }
336                    r = new Record();
337                    r.binder = b;
338                    r.callback = callback;
339                    r.pkgForDebug = pkgForDebug;
340                    r.callerUid = callerUid;
341                    r.subId = subId;
342                    r.isLegacyApp = isLegacyApp;
343                    // Legacy applications pass invalid subId(-1), based on
344                    // the received subId value update the isLegacyApp field
345                    if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) {
346                        r.subId = mDefaultSubId;
347                        r.isLegacyApp = true; // r.subId is to be update when default changes.
348                    }
349                    if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
350                        r.subId = mDefaultSubId;
351                        r.isLegacyApp = true; // r.subId is to be update when default changes.
352                        if (true/*DBG*/) log("listen: DEFAULT_SUB_ID");
353                    }
354                    mRecords.add(r);
355                    if (true/*DBG*/) log("listen: add new record");
356                }
357                int phoneId = SubscriptionManager.getPhoneId(subId);
358                r.events = events;
359                if (true/*DBG*/) log("listen: set events record=" + r + " subId=" + subId + " phoneId=" + phoneId);
360                toStringLogSSC("listen");
361                if (notifyNow && validatePhoneId(phoneId)) {
362                    if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
363                        try {
364                            log("listen: call onSSC state=" + mServiceState[phoneId]);
365                            r.callback.onServiceStateChanged(
366                                    new ServiceState(mServiceState[phoneId]));
367                        } catch (RemoteException ex) {
368                            remove(r.binder);
369                        }
370                    }
371                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
372                        try {
373                            int gsmSignalStrength = mSignalStrength[phoneId]
374                                    .getGsmSignalStrength();
375                            r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
376                                    : gsmSignalStrength));
377                        } catch (RemoteException ex) {
378                            remove(r.binder);
379                        }
380                    }
381                    if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
382                        try {
383                            r.callback.onMessageWaitingIndicatorChanged(
384                                    mMessageWaiting[phoneId]);
385                        } catch (RemoteException ex) {
386                            remove(r.binder);
387                        }
388                    }
389                    if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
390                        try {
391                            r.callback.onCallForwardingIndicatorChanged(
392                                    mCallForwarding[phoneId]);
393                        } catch (RemoteException ex) {
394                            remove(r.binder);
395                        }
396                    }
397                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
398                        try {
399                            if (DBG_LOC) log("listen: mCellLocation = "
400                                    + mCellLocation[phoneId]);
401                            r.callback.onCellLocationChanged(
402                                    new Bundle(mCellLocation[phoneId]));
403                        } catch (RemoteException ex) {
404                            remove(r.binder);
405                        }
406                    }
407                    if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
408                        try {
409                            r.callback.onCallStateChanged(mCallState[phoneId],
410                                     mCallIncomingNumber[phoneId]);
411                        } catch (RemoteException ex) {
412                            remove(r.binder);
413                        }
414                    }
415                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
416                        try {
417                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
418                                mDataConnectionNetworkType[phoneId]);
419                        } catch (RemoteException ex) {
420                            remove(r.binder);
421                        }
422                    }
423                    if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
424                        try {
425                            r.callback.onDataActivity(mDataActivity[phoneId]);
426                        } catch (RemoteException ex) {
427                            remove(r.binder);
428                        }
429                    }
430                    if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
431                        try {
432                            r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
433                        } catch (RemoteException ex) {
434                            remove(r.binder);
435                        }
436                    }
437                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
438                        try {
439                            r.callback.onOtaspChanged(mOtaspMode);
440                        } catch (RemoteException ex) {
441                            remove(r.binder);
442                        }
443                    }
444                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
445                        try {
446                            if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
447                                    + mCellInfo.get(phoneId));
448                            r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
449                        } catch (RemoteException ex) {
450                            remove(r.binder);
451                        }
452                    }
453                    if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
454                        try {
455                            r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
456                        } catch (RemoteException ex) {
457                            remove(r.binder);
458                        }
459                    }
460                    if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
461                        try {
462                            r.callback.onPreciseCallStateChanged(mPreciseCallState);
463                        } catch (RemoteException ex) {
464                            remove(r.binder);
465                        }
466                    }
467                    if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
468                        try {
469                            r.callback.onPreciseDataConnectionStateChanged(
470                                    mPreciseDataConnectionState);
471                        } catch (RemoteException ex) {
472                            remove(r.binder);
473                        }
474                    }
475                }
476            }
477        } else {
478            remove(callback.asBinder());
479        }
480    }
481
482    private void remove(IBinder binder) {
483        synchronized (mRecords) {
484            final int recordCount = mRecords.size();
485            for (int i = 0; i < recordCount; i++) {
486                if (mRecords.get(i).binder == binder) {
487                    mRecords.remove(i);
488                    return;
489                }
490            }
491        }
492    }
493
494    public void notifyCallState(int state, String incomingNumber) {
495        if (!checkNotifyPermission("notifyCallState()")) {
496            return;
497        }
498        synchronized (mRecords) {
499            for (Record r : mRecords) {
500                if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
501                    (r.isLegacyApp == true)) {
502                    // FIXME: why does isLegacyApp need to be true?
503                    try {
504                        r.callback.onCallStateChanged(state, incomingNumber);
505                    } catch (RemoteException ex) {
506                        mRemoveList.add(r.binder);
507                    }
508                }
509            }
510            handleRemoveListLocked();
511        }
512        broadcastCallStateChanged(state, incomingNumber, mDefaultSubId);
513    }
514
515    public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) {
516        if (!checkNotifyPermission("notifyCallState()")) {
517            return;
518        }
519        if (true /*VDBG*/) {
520            log("notifyCallStateUsingSubId: subId=" + subId
521                + " state=" + state + " incomingNumber=" + incomingNumber);
522        }
523        synchronized (mRecords) {
524            int phoneId = SubscriptionManager.getPhoneId(subId);
525            if (validatePhoneId(phoneId)) {
526                mCallState[phoneId] = state;
527                mCallIncomingNumber[phoneId] = incomingNumber;
528                for (Record r : mRecords) {
529                    if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) &&
530                        (r.subId == subId) && (r.isLegacyApp == false)) {
531                        // FIXME: why isLegacyApp false?
532                        try {
533                            r.callback.onCallStateChanged(state, incomingNumber);
534                        } catch (RemoteException ex) {
535                            mRemoveList.add(r.binder);
536                        }
537                    }
538                }
539            }
540            handleRemoveListLocked();
541        }
542        broadcastCallStateChanged(state, incomingNumber, subId);
543    }
544
545     public void notifyServiceState(ServiceState state) {
546         notifyServiceStateUsingSubId(mDefaultSubId, state);
547     }
548
549    public void notifyServiceStateUsingSubId(long subId, ServiceState state) {
550        if (!checkNotifyPermission("notifyServiceState()")){
551            return;
552        }
553        if (subId == SubscriptionManager.DEFAULT_SUB_ID) {
554            subId = mDefaultSubId;
555            log("notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId);
556        }
557        synchronized (mRecords) {
558            int phoneId = SubscriptionManager.getPhoneId(subId);
559            if (true/*VDBG*/) {
560                log("notifyServiceStateUsingSubId: subId=" + subId + " phoneId=" + phoneId
561                    + " state=" + state);
562            }
563            if (validatePhoneId(phoneId)) {
564                mServiceState[phoneId] = state;
565                logServiceStateChanged("notifyServiceStateUsingSubId", subId, phoneId, state);
566                toStringLogSSC("notifyServiceStateUsingSubId");
567
568                for (Record r : mRecords) {
569                    log("notifyServiceStateUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId + " state=" + state);
570                    // FIXME: use DEFAULT_SUB_ID instead??
571                    if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) &&
572                            (r.subId == subId)) {
573                        try {
574                            log("notifyServiceStateUsingSubId: call onSSC subId=" + subId
575                                    + " state=" + state);
576                            r.callback.onServiceStateChanged(new ServiceState(state));
577                        } catch (RemoteException ex) {
578                            mRemoveList.add(r.binder);
579                        }
580                    }
581                }
582            } else {
583                log("notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId);
584            }
585            handleRemoveListLocked();
586        }
587        broadcastServiceStateChanged(state, subId);
588    }
589
590    public void notifySignalStrength(SignalStrength signalStrength) {
591        notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength);
592    }
593
594    public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) {
595        if (!checkNotifyPermission("notifySignalStrength()")) {
596            return;
597        }
598        if (true/*VDBG*/) {
599            log("notifySignalStrengthUsingSubId: subId=" + subId
600                + " signalStrength=" + signalStrength);
601            toStringLogSSC("notifySignalStrengthUsingSubId");
602        }
603        synchronized (mRecords) {
604            int phoneId = SubscriptionManager.getPhoneId(subId);
605            if (validatePhoneId(phoneId)) {
606                log("notifySignalStrengthUsingSubId: valid phoneId=" + phoneId);
607                mSignalStrength[phoneId] = signalStrength;
608                for (Record r : mRecords) {
609                    log("notifySignalStrengthUsingSubId: r.events=0x" + Integer.toHexString(r.events) + " r.subId=" + r.subId + " subId=" + subId);
610                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) &&
611                        (r.subId == subId)){
612                        try {
613                            log("notifySignalStrengthUsingSubId: callback.onSsS ss=" + signalStrength);
614                            r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
615                        } catch (RemoteException ex) {
616                            mRemoveList.add(r.binder);
617                        }
618                    }
619                    if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) &&
620                        (r.subId == subId)) {
621                        try {
622                            int gsmSignalStrength = signalStrength.getGsmSignalStrength();
623                            int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
624                            log("notifySignalStrengthUsingSubId: callback.onSS gsmSS=" + gsmSignalStrength + " ss=" + ss);
625                            r.callback.onSignalStrengthChanged(ss);
626                        } catch (RemoteException ex) {
627                            mRemoveList.add(r.binder);
628                        }
629                    }
630                }
631            } else {
632                log("notifySignalStrengthUsingSubId: invalid phoneId=" + phoneId);
633            }
634            handleRemoveListLocked();
635        }
636        broadcastSignalStrengthChanged(signalStrength, subId);
637    }
638
639    public void notifyCellInfo(List<CellInfo> cellInfo) {
640         notifyCellInfoUsingSubId(mDefaultSubId, cellInfo);
641    }
642
643    public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) {
644        if (!checkNotifyPermission("notifyCellInfo()")) {
645            return;
646        }
647        if (VDBG) {
648            log("notifyCellInfoUsingSubId: subId=" + subId
649                + " cellInfo=" + cellInfo);
650        }
651
652        synchronized (mRecords) {
653            int phoneId = SubscriptionManager.getPhoneId(subId);
654            if (validatePhoneId(phoneId)) {
655                mCellInfo.set(phoneId, cellInfo);
656                for (Record r : mRecords) {
657                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)
658                            && r.subId == subId) {
659                        try {
660                            if (DBG_LOC) {
661                                log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r);
662                            }
663                            r.callback.onCellInfoChanged(cellInfo);
664                        } catch (RemoteException ex) {
665                            mRemoveList.add(r.binder);
666                        }
667                    }
668                }
669            }
670            handleRemoveListLocked();
671        }
672    }
673
674    public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
675        if (!checkNotifyPermission("notifyDataConnectionRealTimeInfo()")) {
676            return;
677        }
678
679        synchronized (mRecords) {
680            mDcRtInfo = dcRtInfo;
681            for (Record r : mRecords) {
682                if (validateEventsAndUserLocked(r,
683                        PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO)) {
684                    try {
685                        if (DBG_LOC) {
686                            log("notifyDataConnectionRealTimeInfo: mDcRtInfo="
687                                    + mDcRtInfo + " r=" + r);
688                        }
689                        r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
690                    } catch (RemoteException ex) {
691                        mRemoveList.add(r.binder);
692                    }
693                }
694            }
695            handleRemoveListLocked();
696        }
697    }
698
699    public void notifyMessageWaitingChanged(boolean mwi) {
700        notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi);
701    }
702
703    public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) {
704        if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
705            return;
706        }
707        if (VDBG) {
708            log("notifyMessageWaitingChangedUsingSubId: subId=" + subId
709                + " mwi=" + mwi);
710        }
711        synchronized (mRecords) {
712            int phoneId = SubscriptionManager.getPhoneId(subId);
713            if (validatePhoneId(phoneId)) {
714                mMessageWaiting[phoneId] = mwi;
715                for (Record r : mRecords) {
716                    if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) &&
717                        (r.subId == subId)) {
718                        try {
719                            r.callback.onMessageWaitingIndicatorChanged(mwi);
720                        } catch (RemoteException ex) {
721                            mRemoveList.add(r.binder);
722                        }
723                    }
724                }
725            }
726            handleRemoveListLocked();
727        }
728    }
729
730    public void notifyCallForwardingChanged(boolean cfi) {
731        notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi);
732    }
733
734    public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) {
735        if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
736            return;
737        }
738        if (VDBG) {
739            log("notifyCallForwardingChangedUsingSubId: subId=" + subId
740                + " cfi=" + cfi);
741        }
742        synchronized (mRecords) {
743            int phoneId = SubscriptionManager.getPhoneId(subId);
744            if (validatePhoneId(phoneId)) {
745                mCallForwarding[phoneId] = cfi;
746                for (Record r : mRecords) {
747                    if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) &&
748                        (r.subId == subId)) {
749                        try {
750                            r.callback.onCallForwardingIndicatorChanged(cfi);
751                        } catch (RemoteException ex) {
752                            mRemoveList.add(r.binder);
753                        }
754                    }
755                }
756            }
757            handleRemoveListLocked();
758        }
759    }
760
761    public void notifyDataActivity(int state) {
762        notifyDataActivityUsingSubId(mDefaultSubId, state);
763    }
764
765    public void notifyDataActivityUsingSubId(long subId, int state) {
766        if (!checkNotifyPermission("notifyDataActivity()" )) {
767            return;
768        }
769        synchronized (mRecords) {
770            int phoneId = SubscriptionManager.getPhoneId(subId);
771            mDataActivity[phoneId] = state;
772            for (Record r : mRecords) {
773                if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
774                    try {
775                        r.callback.onDataActivity(state);
776                    } catch (RemoteException ex) {
777                        mRemoveList.add(r.binder);
778                    }
779                }
780            }
781            handleRemoveListLocked();
782        }
783    }
784
785    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
786            String reason, String apn, String apnType, LinkProperties linkProperties,
787            NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
788        notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible,
789            reason, apn, apnType, linkProperties,
790            networkCapabilities, networkType, roaming);
791    }
792
793    public void notifyDataConnectionUsingSubId(long subId, int state,
794            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
795            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
796            int networkType, boolean roaming) {
797        if (!checkNotifyPermission("notifyDataConnection()" )) {
798            return;
799        }
800        if (VDBG) {
801            log("notifyDataConnectionUsingSubId: subId=" + subId
802                + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
803                + " reason='" + reason
804                + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
805                + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords);
806        }
807        synchronized (mRecords) {
808            int phoneId = SubscriptionManager.getPhoneId(subId);
809            boolean modified = false;
810            if (state == TelephonyManager.DATA_CONNECTED) {
811                if (!mConnectedApns.contains(apnType)) {
812                    mConnectedApns.add(apnType);
813                    if (mDataConnectionState[phoneId] != state) {
814                        mDataConnectionState[phoneId] = state;
815                        modified = true;
816                    }
817                }
818            } else {
819                if (mConnectedApns.remove(apnType)) {
820                    if (mConnectedApns.isEmpty()) {
821                        mDataConnectionState[phoneId] = state;
822                        modified = true;
823                    } else {
824                        // leave mDataConnectionState as is and
825                        // send out the new status for the APN in question.
826                    }
827                }
828            }
829            mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
830            mDataConnectionReason[phoneId] = reason;
831            mDataConnectionLinkProperties[phoneId] = linkProperties;
832            mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
833            if (mDataConnectionNetworkType[phoneId] != networkType) {
834                mDataConnectionNetworkType[phoneId] = networkType;
835                // need to tell registered listeners about the new network type
836                modified = true;
837            }
838            if (modified) {
839                if (DBG) {
840                    log("onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
841                        + ", " + mDataConnectionNetworkType[phoneId] + ")");
842                }
843                for (Record r : mRecords) {
844                    if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) &&
845                            (r.subId == subId)) {
846                        try {
847                            log("Notify data connection state changed on sub: " +
848                                    subId);
849                            r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
850                                    mDataConnectionNetworkType[phoneId]);
851                        } catch (RemoteException ex) {
852                            mRemoveList.add(r.binder);
853                        }
854                    }
855                }
856                handleRemoveListLocked();
857            }
858            mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
859                    apnType, apn, reason, linkProperties, "");
860            for (Record r : mRecords) {
861                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
862                    try {
863                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
864                    } catch (RemoteException ex) {
865                        mRemoveList.add(r.binder);
866                    }
867                }
868            }
869            handleRemoveListLocked();
870        }
871        broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
872                apnType, linkProperties, networkCapabilities, roaming, subId);
873        broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
874                linkProperties, "");
875    }
876
877    public void notifyDataConnectionFailed(String reason, String apnType) {
878         notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType);
879    }
880
881    public void notifyDataConnectionFailedUsingSubId(long subId,
882            String reason, String apnType) {
883        if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
884            return;
885        }
886        if (VDBG) {
887            log("notifyDataConnectionFailedUsingSubId: subId=" + subId
888                + " reason=" + reason + " apnType=" + apnType);
889        }
890        synchronized (mRecords) {
891            mPreciseDataConnectionState = new PreciseDataConnectionState(
892                    TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
893                    apnType, "", reason, null, "");
894            for (Record r : mRecords) {
895                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
896                    try {
897                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
898                    } catch (RemoteException ex) {
899                        mRemoveList.add(r.binder);
900                    }
901                }
902            }
903            handleRemoveListLocked();
904        }
905        broadcastDataConnectionFailed(reason, apnType, subId);
906        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
907                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
908    }
909
910    public void notifyCellLocation(Bundle cellLocation) {
911         notifyCellLocationUsingSubId(mDefaultSubId, cellLocation);
912    }
913
914    public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) {
915        log("notifyCellLocationUsingSubId: subId=" + subId
916                + " cellLocation=" + cellLocation);
917        if (!checkNotifyPermission("notifyCellLocation()")) {
918            return;
919        }
920        if (VDBG) {
921            log("notifyCellLocationUsingSubId: subId=" + subId
922                + " cellLocation=" + cellLocation);
923        }
924        synchronized (mRecords) {
925            int phoneId = SubscriptionManager.getPhoneId(subId);
926            if (validatePhoneId(phoneId)) {
927                mCellLocation[phoneId] = cellLocation;
928                for (Record r : mRecords) {
929                    if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)
930                            && r.subId == subId) {
931                        try {
932                            if (DBG_LOC) {
933                                log("notifyCellLocation: cellLocation=" + cellLocation
934                                        + " r=" + r);
935                            }
936                            r.callback.onCellLocationChanged(new Bundle(cellLocation));
937                        } catch (RemoteException ex) {
938                            mRemoveList.add(r.binder);
939                        }
940                    }
941                }
942            }
943            handleRemoveListLocked();
944        }
945    }
946
947    public void notifyOtaspChanged(int otaspMode) {
948        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
949            return;
950        }
951        synchronized (mRecords) {
952            mOtaspMode = otaspMode;
953            for (Record r : mRecords) {
954                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
955                    try {
956                        r.callback.onOtaspChanged(otaspMode);
957                    } catch (RemoteException ex) {
958                        mRemoveList.add(r.binder);
959                    }
960                }
961            }
962            handleRemoveListLocked();
963        }
964    }
965
966    public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
967            int backgroundCallState) {
968        if (!checkNotifyPermission("notifyPreciseCallState()")) {
969            return;
970        }
971        synchronized (mRecords) {
972            mRingingCallState = ringingCallState;
973            mForegroundCallState = foregroundCallState;
974            mBackgroundCallState = backgroundCallState;
975            mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
976                    backgroundCallState,
977                    DisconnectCause.NOT_VALID,
978                    PreciseDisconnectCause.NOT_VALID);
979            for (Record r : mRecords) {
980                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
981                    try {
982                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
983                    } catch (RemoteException ex) {
984                        mRemoveList.add(r.binder);
985                    }
986                }
987            }
988            handleRemoveListLocked();
989        }
990        broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
991                DisconnectCause.NOT_VALID,
992                PreciseDisconnectCause.NOT_VALID);
993    }
994
995    public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
996        if (!checkNotifyPermission("notifyDisconnectCause()")) {
997            return;
998        }
999        synchronized (mRecords) {
1000            mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
1001                    mBackgroundCallState, disconnectCause, preciseDisconnectCause);
1002            for (Record r : mRecords) {
1003                if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
1004                    try {
1005                        r.callback.onPreciseCallStateChanged(mPreciseCallState);
1006                    } catch (RemoteException ex) {
1007                        mRemoveList.add(r.binder);
1008                    }
1009                }
1010            }
1011            handleRemoveListLocked();
1012        }
1013        broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
1014                mBackgroundCallState, disconnectCause, preciseDisconnectCause);
1015    }
1016
1017    public void notifyPreciseDataConnectionFailed(String reason, String apnType,
1018            String apn, String failCause) {
1019        if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
1020            return;
1021        }
1022        synchronized (mRecords) {
1023            mPreciseDataConnectionState = new PreciseDataConnectionState(
1024                    TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
1025                    apnType, apn, reason, null, failCause);
1026            for (Record r : mRecords) {
1027                if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
1028                    try {
1029                        r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
1030                    } catch (RemoteException ex) {
1031                        mRemoveList.add(r.binder);
1032                    }
1033                }
1034            }
1035            handleRemoveListLocked();
1036        }
1037        broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
1038                TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
1039    }
1040
1041    public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) {
1042        if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) {
1043            return;
1044        }
1045        synchronized (mRecords) {
1046            mVoLteServiceState = lteState;
1047            for (Record r : mRecords) {
1048                if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) {
1049                    try {
1050                        r.callback.onVoLteServiceStateChanged(
1051                                new VoLteServiceState(mVoLteServiceState));
1052                    } catch (RemoteException ex) {
1053                        mRemoveList.add(r.binder);
1054                    }
1055                }
1056            }
1057            handleRemoveListLocked();
1058        }
1059    }
1060
1061    @Override
1062    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1063        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1064                != PackageManager.PERMISSION_GRANTED) {
1065            pw.println("Permission Denial: can't dump telephony.registry from from pid="
1066                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1067            return;
1068        }
1069        synchronized (mRecords) {
1070            final int recordCount = mRecords.size();
1071            pw.println("last known state:");
1072            for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
1073                pw.println("  Phone Id=" + i);
1074                pw.println("  mCallState=" + mCallState[i]);
1075                pw.println("  mCallIncomingNumber=" + mCallIncomingNumber[i]);
1076                pw.println("  mServiceState=" + mServiceState[i]);
1077                pw.println("  mSignalStrength=" + mSignalStrength[i]);
1078                pw.println("  mMessageWaiting=" + mMessageWaiting[i]);
1079                pw.println("  mCallForwarding=" + mCallForwarding[i]);
1080                pw.println("  mDataActivity=" + mDataActivity[i]);
1081                pw.println("  mDataConnectionState=" + mDataConnectionState[i]);
1082                pw.println("  mDataConnectionPossible=" + mDataConnectionPossible[i]);
1083                pw.println("  mDataConnectionReason=" + mDataConnectionReason[i]);
1084                pw.println("  mDataConnectionApn=" + mDataConnectionApn[i]);
1085                pw.println("  mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
1086                pw.println("  mDataConnectionNetworkCapabilities=" +
1087                        mDataConnectionNetworkCapabilities[i]);
1088                pw.println("  mCellLocation=" + mCellLocation[i]);
1089                pw.println("  mCellInfo=" + mCellInfo.get(i));
1090            }
1091            pw.println("  mDefaultSubId=" + mDefaultSubId);
1092            pw.println("  mDcRtInfo=" + mDcRtInfo);
1093            pw.println("registrations: count=" + recordCount);
1094            for (Record r : mRecords) {
1095                pw.println("  " + r.pkgForDebug + " 0x" + Integer.toHexString(r.events));
1096                pw.println("is Legacy = " + r.isLegacyApp + " subId = " + r.subId);
1097            }
1098        }
1099    }
1100
1101    //
1102    // the legacy intent broadcasting
1103    //
1104
1105    private void broadcastServiceStateChanged(ServiceState state, long subId) {
1106        long ident = Binder.clearCallingIdentity();
1107        try {
1108            mBatteryStats.notePhoneState(state.getState());
1109        } catch (RemoteException re) {
1110            // Can't do much
1111        } finally {
1112            Binder.restoreCallingIdentity(ident);
1113        }
1114
1115        Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
1116        Bundle data = new Bundle();
1117        state.fillInNotifierBundle(data);
1118        intent.putExtras(data);
1119        // Pass the subscription along with the intent.
1120        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1121        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1122    }
1123
1124    private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
1125        long ident = Binder.clearCallingIdentity();
1126        try {
1127            mBatteryStats.notePhoneSignalStrength(signalStrength);
1128        } catch (RemoteException e) {
1129            /* The remote entity disappeared, we can safely ignore the exception. */
1130        } finally {
1131            Binder.restoreCallingIdentity(ident);
1132        }
1133
1134        Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
1135        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1136        Bundle data = new Bundle();
1137        signalStrength.fillInNotifierBundle(data);
1138        intent.putExtras(data);
1139        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1140        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1141    }
1142
1143    private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
1144        long ident = Binder.clearCallingIdentity();
1145        try {
1146            if (state == TelephonyManager.CALL_STATE_IDLE) {
1147                mBatteryStats.notePhoneOff();
1148            } else {
1149                mBatteryStats.notePhoneOn();
1150            }
1151        } catch (RemoteException e) {
1152            /* The remote entity disappeared, we can safely ignore the exception. */
1153        } finally {
1154            Binder.restoreCallingIdentity(ident);
1155        }
1156
1157        Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1158        intent.putExtra(PhoneConstants.STATE_KEY,
1159                DefaultPhoneNotifier.convertCallState(state).toString());
1160        if (!TextUtils.isEmpty(incomingNumber)) {
1161            intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
1162        }
1163        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1164        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1165                android.Manifest.permission.READ_PHONE_STATE);
1166    }
1167
1168    private void broadcastDataConnectionStateChanged(int state,
1169            boolean isDataConnectivityPossible,
1170            String reason, String apn, String apnType, LinkProperties linkProperties,
1171            NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
1172        // Note: not reporting to the battery stats service here, because the
1173        // status bar takes care of that after taking into account all of the
1174        // required info.
1175        Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
1176        intent.putExtra(PhoneConstants.STATE_KEY,
1177                DefaultPhoneNotifier.convertDataState(state).toString());
1178        if (!isDataConnectivityPossible) {
1179            intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
1180        }
1181        if (reason != null) {
1182            intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
1183        }
1184        if (linkProperties != null) {
1185            intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
1186            String iface = linkProperties.getInterfaceName();
1187            if (iface != null) {
1188                intent.putExtra(PhoneConstants.DATA_IFACE_NAME_KEY, iface);
1189            }
1190        }
1191        if (networkCapabilities != null) {
1192            intent.putExtra(PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY, networkCapabilities);
1193        }
1194        if (roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);
1195
1196        intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
1197        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
1198        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1199        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1200    }
1201
1202    private void broadcastDataConnectionFailed(String reason, String apnType,
1203            long subId) {
1204        Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
1205        intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
1206        intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
1207        intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
1208        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1209    }
1210
1211    private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
1212            int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
1213        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
1214        intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
1215        intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
1216        intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
1217        intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
1218        intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
1219        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1220                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
1221    }
1222
1223    private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
1224            String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
1225        Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
1226        intent.putExtra(PhoneConstants.STATE_KEY, state);
1227        intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
1228        if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
1229        if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
1230        if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
1231        if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
1232        if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
1233
1234        mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1235                android.Manifest.permission.READ_PRECISE_PHONE_STATE);
1236    }
1237
1238    private boolean checkNotifyPermission(String method) {
1239        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
1240                == PackageManager.PERMISSION_GRANTED) {
1241            return true;
1242        }
1243        String msg = "Modify Phone State Permission Denial: " + method + " from pid="
1244                + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
1245        if (DBG) log(msg);
1246        return false;
1247    }
1248
1249    private void checkListenerPermission(int events) {
1250        if ((events & PhoneStateListener.LISTEN_CELL_LOCATION) != 0) {
1251            mContext.enforceCallingOrSelfPermission(
1252                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1253
1254        }
1255
1256        if ((events & PhoneStateListener.LISTEN_CELL_INFO) != 0) {
1257            mContext.enforceCallingOrSelfPermission(
1258                    android.Manifest.permission.ACCESS_COARSE_LOCATION, null);
1259
1260        }
1261
1262        if ((events & PHONE_STATE_PERMISSION_MASK) != 0) {
1263            mContext.enforceCallingOrSelfPermission(
1264                    android.Manifest.permission.READ_PHONE_STATE, null);
1265        }
1266
1267        if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
1268            mContext.enforceCallingOrSelfPermission(
1269                    android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
1270
1271        }
1272    }
1273
1274    private void handleRemoveListLocked() {
1275        if (mRemoveList.size() > 0) {
1276            for (IBinder b: mRemoveList) {
1277                remove(b);
1278            }
1279            mRemoveList.clear();
1280        }
1281    }
1282
1283    private boolean validateEventsAndUserLocked(Record r, int events) {
1284        int foregroundUser;
1285        long callingIdentity = Binder.clearCallingIdentity();
1286        boolean valid = false;
1287        try {
1288            foregroundUser = ActivityManager.getCurrentUser();
1289            valid = r.callerUid ==  foregroundUser && (r.events & events) != 0;
1290            if (DBG | DBG_LOC) {
1291                log("validateEventsAndUserLocked: valid=" + valid
1292                        + " r.callerUid=" + r.callerUid + " foregroundUser=" + foregroundUser
1293                        + " r.events=" + r.events + " events=" + events);
1294            }
1295        } finally {
1296            Binder.restoreCallingIdentity(callingIdentity);
1297        }
1298        return valid;
1299    }
1300
1301    private boolean validatePhoneId(int phoneId) {
1302        boolean valid = (phoneId >= 0) && (phoneId < mNumPhones);
1303        if (VDBG) log("validatePhoneId: " + valid);
1304        return valid;
1305    }
1306
1307    private static void log(String s) {
1308        Rlog.d(TAG, s);
1309    }
1310
1311    private static class LogSSC {
1312        private Time mTime;
1313        private String mS;
1314        private long mSubId;
1315        private int mPhoneId;
1316        private ServiceState mState;
1317
1318        public void set(Time t, String s, long subId, int phoneId, ServiceState state) {
1319            mTime = t; mS = s; mSubId = subId; mPhoneId = phoneId; mState = state;
1320        }
1321
1322        @Override
1323        public String toString() {
1324            return mS + " " + mTime.toString() + " " + mSubId + " " + mPhoneId + " " + mState;
1325        }
1326    }
1327
1328    private LogSSC logSSC [] = new LogSSC[10];
1329    private int next = 0;
1330
1331    private void logServiceStateChanged(String s, long subId, int phoneId, ServiceState state) {
1332        if (logSSC == null || logSSC.length == 0) {
1333            return;
1334        }
1335        if (logSSC[next] == null) {
1336            logSSC[next] = new LogSSC();
1337        }
1338        Time t = new Time();
1339        t.setToNow();
1340        logSSC[next].set(t, s, subId, phoneId, state);
1341        if (++next >= logSSC.length) {
1342            next = 0;
1343        }
1344    }
1345
1346    private void toStringLogSSC(String prompt) {
1347        if (logSSC == null || logSSC.length == 0 || (next == 0 && logSSC[next] == null)) {
1348            log(prompt + ": logSSC is empty");
1349        } else {
1350            // There is at least one element
1351            log(prompt + ": logSSC.length=" + logSSC.length + " next=" + next);
1352            int i = next;
1353            if (logSSC[i] == null) {
1354                // logSSC is not full so back to the beginning
1355                i = 0;
1356            }
1357            do {
1358                log(logSSC[i].toString());
1359                if (++i >= logSSC.length) {
1360                    i = 0;
1361                }
1362            } while (i != next);
1363        }
1364    }
1365}
1366