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