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