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