• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.internal.location;
18 
19 import android.Manifest;
20 import android.annotation.RequiresPermission;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.location.LocationManager;
24 import android.os.SystemClock;
25 import android.telephony.TelephonyCallback;
26 import android.telephony.TelephonyManager;
27 import android.telephony.emergency.EmergencyNumber;
28 import android.util.Log;
29 
30 import java.util.concurrent.TimeUnit;
31 
32 /**
33  * A GPS Network-initiated Handler class used by LocationManager.
34  *
35  * {@hide}
36  */
37 public class GpsNetInitiatedHandler {
38 
39     private static final String TAG = "GpsNetInitiatedHandler";
40 
41     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
42 
43     private final Context mContext;
44     private final TelephonyManager mTelephonyManager;
45 
46     // parent gps location provider
47     private final LocationManager mLocationManager;
48 
49     // Set to true if the phone is having emergency call.
50     private volatile boolean mIsInEmergencyCall;
51 
52 
53     // End time of emergency call, and extension, if set
54     private volatile long mCallEndElapsedRealtimeMillis = 0;
55     private volatile long mEmergencyExtensionMillis = 0;
56 
57     /** Callbacks for Emergency call events. */
58     public interface EmergencyCallCallback {
59         /** Callback invoked when an emergency call starts */
onEmergencyCallStart(int subId)60         void onEmergencyCallStart(int subId);
61         /** Callback invoked when an emergency call ends */
onEmergencyCallEnd()62         void onEmergencyCallEnd();
63     }
64 
65     private class EmergencyCallListener extends TelephonyCallback implements
66             TelephonyCallback.OutgoingEmergencyCallListener,
67             TelephonyCallback.CallStateListener {
68 
69         @Override
70         @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber, int subscriptionId)71         public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber,
72                 int subscriptionId) {
73             mIsInEmergencyCall = true;
74             if (DEBUG) Log.d(TAG, "onOutgoingEmergencyCall(): inEmergency = " + getInEmergency());
75             mEmergencyCallCallback.onEmergencyCallStart(subscriptionId);
76         }
77 
78         @Override
79         @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
onCallStateChanged(int state)80         public void onCallStateChanged(int state) {
81             if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is " + state);
82             // listening for emergency call ends
83             if (state == TelephonyManager.CALL_STATE_IDLE) {
84                 if (mIsInEmergencyCall) {
85                     mCallEndElapsedRealtimeMillis = SystemClock.elapsedRealtime();
86                     mIsInEmergencyCall = false;
87                     mEmergencyCallCallback.onEmergencyCallEnd();
88                 }
89             }
90         }
91     }
92 
93     // The internal implementation of TelephonyManager uses WeakReference so we have to keep a
94     // reference here.
95     private final EmergencyCallListener mEmergencyCallListener = new EmergencyCallListener();
96 
97     private final EmergencyCallCallback mEmergencyCallCallback;
98 
GpsNetInitiatedHandler(Context context, EmergencyCallCallback emergencyCallCallback, boolean isSuplEsEnabled)99     public GpsNetInitiatedHandler(Context context,
100                                   EmergencyCallCallback emergencyCallCallback,
101                                   boolean isSuplEsEnabled) {
102         mContext = context;
103         mEmergencyCallCallback = emergencyCallCallback;
104 
105         mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
106         mTelephonyManager =
107             (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
108         mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
109                 mEmergencyCallListener);
110 
111     }
112 
113     /**
114      * Determines whether device is in user-initiated emergency session based on the following
115      * 1. If the user is making an emergency call, this is provided by actively
116      *    monitoring the outgoing phone number;
117      * 2. If the user has recently ended an emergency call, and the device is in a configured time
118      *    window after the end of that call.
119      * 3. If the device is in a emergency callback state, this is provided by querying
120      *    TelephonyManager.
121      * 4. If the user has recently sent an Emergency SMS and telephony reports that it is in
122      *    emergency SMS mode, this is provided by querying TelephonyManager.
123      * @return true if is considered in user initiated emergency mode for NI purposes
124      */
getInEmergency()125     public boolean getInEmergency() {
126         return getInEmergency(mEmergencyExtensionMillis);
127     }
128 
129     /**
130      * Determines whether device is in user-initiated emergency session with the given extension
131      * time.
132      *
133      * @return true if is considered in user initiated emergency mode for NI purposes within the
134      * given extension time.
135      *
136      * @see {@link #getInEmergency()}
137      */
getInEmergency(long emergencyExtensionMillis)138     public boolean getInEmergency(long emergencyExtensionMillis) {
139         boolean isInEmergencyExtension =
140                 (mCallEndElapsedRealtimeMillis > 0)
141                         && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis)
142                         < emergencyExtensionMillis);
143         boolean isInEmergencyCallback = false;
144         boolean isInEmergencySmsMode = false;
145         PackageManager pm = mContext.getPackageManager();
146         if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) {
147             isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
148         }
149         if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)) {
150             isInEmergencySmsMode = mTelephonyManager.isInEmergencySmsMode();
151         }
152         return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension
153                 || isInEmergencySmsMode;
154     }
155 
setEmergencyExtensionSeconds(int emergencyExtensionSeconds)156     public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
157         mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
158     }
159 }
160