blob: 5b4c2fd5316d2536ed21db1547a520dedf09df8f [file] [log] [blame]
mike dooley21fb1af2016-12-05 14:25:53 -08001/*
2 * Copyright 2016, 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.telecom;
18
19import android.Manifest;
20import android.content.Context;
21import android.content.pm.PackageManager;
22import android.os.UserHandle;
23import android.telecom.Log;
24import com.android.internal.annotations.VisibleForTesting;
25
26/**
mike dooley66f26d12016-12-19 13:25:47 -080027 * Helps with emergency calls by:
28 * 1. granting temporary location permission to the default dialer service during emergency calls
29 * 2. keeping track of the time of the last emergency call
mike dooley21fb1af2016-12-05 14:25:53 -080030 */
31@VisibleForTesting
mike dooley66f26d12016-12-19 13:25:47 -080032public class EmergencyCallHelper {
mike dooley21fb1af2016-12-05 14:25:53 -080033 private final Context mContext;
34 private final String mDefaultDialerPackage;
35 private final Timeouts.Adapter mTimeoutsAdapter;
36 private UserHandle mLocationPermissionGrantedToUser;
mike dooley66f26d12016-12-19 13:25:47 -080037 private long mLastEmergencyCallTimestampMillis;
mike dooley21fb1af2016-12-05 14:25:53 -080038
39 @VisibleForTesting
mike dooley66f26d12016-12-19 13:25:47 -080040 public EmergencyCallHelper(
mike dooley21fb1af2016-12-05 14:25:53 -080041 Context context,
42 String defaultDialerPackage,
43 Timeouts.Adapter timeoutsAdapter) {
44 mContext = context;
45 mDefaultDialerPackage = defaultDialerPackage;
46 mTimeoutsAdapter = timeoutsAdapter;
47 }
48
49 void maybeGrantTemporaryLocationPermission(Call call, UserHandle userHandle) {
50 if (shouldGrantTemporaryLocationPermission(call)) {
51 grantLocationPermission(userHandle, call);
52 }
mike dooley66f26d12016-12-19 13:25:47 -080053 if (call != null && call.isEmergencyCall()) {
54 recordEmergencyCallTime();
55 }
mike dooley21fb1af2016-12-05 14:25:53 -080056 }
57
58 void maybeRevokeTemporaryLocationPermission() {
59 if (wasGrantedTemporaryLocationPermission()) {
60 revokeLocationPermission();
61 }
62 }
63
mike dooley66f26d12016-12-19 13:25:47 -080064 long getLastEmergencyCallTimeMillis() {
65 return mLastEmergencyCallTimestampMillis;
66 }
67
68 private void recordEmergencyCallTime() {
69 mLastEmergencyCallTimestampMillis = System.currentTimeMillis();
70 }
71
72 private boolean isInEmergencyCallbackWindow() {
73 return System.currentTimeMillis() - getLastEmergencyCallTimeMillis()
74 < mTimeoutsAdapter.getEmergencyCallbackWindowMillis(mContext.getContentResolver());
75 }
76
mike dooley21fb1af2016-12-05 14:25:53 -080077 private boolean shouldGrantTemporaryLocationPermission(Call call) {
mike dooleyce641902017-05-09 15:44:40 -070078 if (!mContext.getResources().getBoolean(R.bool.grant_location_permission_enabled)) {
79 Log.i(this, "ShouldGrantTemporaryLocationPermission, disabled by config");
80 return false;
81 }
mike dooley21fb1af2016-12-05 14:25:53 -080082 if (call == null) {
83 Log.i(this, "ShouldGrantTemporaryLocationPermission, no call");
84 return false;
85 }
86 if (!call.isEmergencyCall() && !isInEmergencyCallbackWindow()) {
87 Log.i(this, "ShouldGrantTemporaryLocationPermission, not emergency");
88 return false;
89 }
90 if (hasLocationPermission()) {
91 Log.i(this, "ShouldGrantTemporaryLocationPermission, already has location permission");
92 return false;
93 }
94 Log.i(this, "ShouldGrantTemporaryLocationPermission, returning true");
95 return true;
96 }
97
98 private void grantLocationPermission(UserHandle userHandle, Call call) {
99 Log.i(this, "Granting temporary location permission to " + mDefaultDialerPackage
100 + ", user: " + userHandle);
101 try {
102 mContext.getPackageManager().grantRuntimePermission(mDefaultDialerPackage,
103 Manifest.permission.ACCESS_FINE_LOCATION, userHandle);
mike dooley66f26d12016-12-19 13:25:47 -0800104 recordPermissionGrant(userHandle);
mike dooley21fb1af2016-12-05 14:25:53 -0800105 } catch (Exception e) {
106 Log.e(this, e, "Failed to grant location permission to " + mDefaultDialerPackage
107 + ", user: " + userHandle);
108 }
109 }
110
111 private void revokeLocationPermission() {
112 Log.i(this, "Revoking temporary location permission from " + mDefaultDialerPackage
113 + ", user: " + mLocationPermissionGrantedToUser);
114 UserHandle userHandle = mLocationPermissionGrantedToUser;
115 clearPermissionGrant();
116 try {
117 mContext.getPackageManager().revokeRuntimePermission(mDefaultDialerPackage,
118 Manifest.permission.ACCESS_FINE_LOCATION, userHandle);
119 } catch (Exception e) {
120 Log.e(this, e, "Failed to revoke location permission from " + mDefaultDialerPackage
121 + ", user: " + userHandle);
122 }
123 }
124
125 private boolean hasLocationPermission() {
126 return mContext.getPackageManager().checkPermission(
127 Manifest.permission.ACCESS_FINE_LOCATION, mDefaultDialerPackage)
128 == PackageManager.PERMISSION_GRANTED;
129 }
130
mike dooley66f26d12016-12-19 13:25:47 -0800131 private void recordPermissionGrant(UserHandle userHandle) {
mike dooley21fb1af2016-12-05 14:25:53 -0800132 mLocationPermissionGrantedToUser = userHandle;
mike dooley21fb1af2016-12-05 14:25:53 -0800133 }
134
135 private boolean wasGrantedTemporaryLocationPermission() {
136 return mLocationPermissionGrantedToUser != null;
137 }
138
139 private void clearPermissionGrant() {
140 mLocationPermissionGrantedToUser = null;
141 }
mike dooley21fb1af2016-12-05 14:25:53 -0800142}