blob: 1c307628f86d01b4b81ce4a5f6f4290c50f194bd [file] [log] [blame]
Jim Miller109f1fd2012-09-19 20:44:16 -07001/*
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
Jim Miller5ecd8112013-01-09 18:50:26 -080017package com.android.keyguard;
Jim Miller109f1fd2012-09-19 20:44:16 -070018
Lucas Dupin8968f6a2019-08-09 17:41:15 -070019import static com.android.systemui.DejankUtils.whitelistIpcs;
20
Adrian Roosb5947e02015-05-14 16:14:29 -070021import android.app.ActivityOptions;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070022import android.app.ActivityTaskManager;
Jim Miller109f1fd2012-09-19 20:44:16 -070023import android.content.Context;
24import android.content.Intent;
Jorim Jaggi76511c72015-05-04 15:34:22 -070025import android.content.res.Configuration;
Jim Miller109f1fd2012-09-19 20:44:16 -070026import android.os.PowerManager;
Hall Liu7dac3662016-05-27 13:30:09 -070027import android.os.RemoteException;
Jim Miller109f1fd2012-09-19 20:44:16 -070028import android.os.SystemClock;
Jim Miller450a3a12013-03-12 18:54:44 -070029import android.os.UserHandle;
Adrian Roosc2e01682015-01-15 23:20:20 +010030import android.telecom.TelecomManager;
Jim Miller109f1fd2012-09-19 20:44:16 -070031import android.util.AttributeSet;
Hall Liu7dac3662016-05-27 13:30:09 -070032import android.util.Slog;
Selim Cinek705442f2016-09-13 16:02:33 -070033import android.view.MotionEvent;
Jim Miller109f1fd2012-09-19 20:44:16 -070034import android.view.View;
Selim Cinek705442f2016-09-13 16:02:33 -070035import android.view.ViewConfiguration;
Jim Miller109f1fd2012-09-19 20:44:16 -070036import android.widget.Button;
37
Chris Wrende0a21f2015-06-05 17:17:55 -040038import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010039import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jim Miller109f1fd2012-09-19 20:44:16 -070040import com.android.internal.telephony.IccCardConstants.State;
Jason Monk361915c2017-03-21 20:33:59 -040041import com.android.internal.util.EmergencyAffordanceManager;
Gus Prevasab336792018-11-14 13:52:20 -050042import com.android.internal.widget.LockPatternUtils;
Dave Mankoffe2294692019-08-14 11:53:13 -040043import com.android.systemui.Dependency;
Shaotang Li5c422632018-07-04 14:18:40 +080044import com.android.systemui.util.EmergencyDialerConstants;
Jim Miller109f1fd2012-09-19 20:44:16 -070045
46/**
47 * This class implements a smart emergency button that updates itself based
48 * on telephony state. When the phone is idle, it is an emergency call button.
49 * When there's a call in progress, it presents an appropriate message and
50 * allows the user to return to the call.
51 */
52public class EmergencyButton extends Button {
Adrian Roos8d75c142015-03-24 12:57:20 -070053 private static final Intent INTENT_EMERGENCY_DIAL = new Intent()
Shaotang Li5c422632018-07-04 14:18:40 +080054 .setAction(EmergencyDialerConstants.ACTION_DIAL)
Adrian Roos8d75c142015-03-24 12:57:20 -070055 .setPackage("com.android.phone")
Adrian Roos0ab57422015-04-20 13:57:06 -070056 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
57 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
Shaotang Li5c422632018-07-04 14:18:40 +080058 | Intent.FLAG_ACTIVITY_CLEAR_TOP)
59 .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
60 EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
Jim Miller109f1fd2012-09-19 20:44:16 -070061
Hall Liu7dac3662016-05-27 13:30:09 -070062 private static final String LOG_TAG = "EmergencyButton";
Selim Cinek705442f2016-09-13 16:02:33 -070063 private final EmergencyAffordanceManager mEmergencyAffordanceManager;
Hall Liu7dac3662016-05-27 13:30:09 -070064
Selim Cinek705442f2016-09-13 16:02:33 -070065 private int mDownX;
66 private int mDownY;
Jim Miller109f1fd2012-09-19 20:44:16 -070067 KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
68
69 @Override
Jim Miller52a61332014-11-12 19:29:51 -080070 public void onSimStateChanged(int subId, int slotId, State simState) {
71 updateEmergencyCallButton();
Jim Miller109f1fd2012-09-19 20:44:16 -070072 }
73
Jorim Jaggi5cf17872014-03-26 18:31:48 +010074 @Override
75 public void onPhoneStateChanged(int phoneState) {
Jim Miller52a61332014-11-12 19:29:51 -080076 updateEmergencyCallButton();
Jorim Jaggi5cf17872014-03-26 18:31:48 +010077 }
Jim Miller109f1fd2012-09-19 20:44:16 -070078 };
Selim Cinek705442f2016-09-13 16:02:33 -070079 private boolean mLongPressWasDragged;
Andrew Lee72b46d42015-01-30 13:23:21 -080080
81 public interface EmergencyButtonCallback {
82 public void onEmergencyButtonClickedWhenInCall();
83 }
84
Jim Miller109f1fd2012-09-19 20:44:16 -070085 private LockPatternUtils mLockPatternUtils;
86 private PowerManager mPowerManager;
Andrew Lee72b46d42015-01-30 13:23:21 -080087 private EmergencyButtonCallback mEmergencyButtonCallback;
Jim Miller109f1fd2012-09-19 20:44:16 -070088
Adrian Roosc2e01682015-01-15 23:20:20 +010089 private final boolean mIsVoiceCapable;
90 private final boolean mEnableEmergencyCallWhileSimLocked;
91
Jim Miller109f1fd2012-09-19 20:44:16 -070092 public EmergencyButton(Context context) {
93 this(context, null);
94 }
95
96 public EmergencyButton(Context context, AttributeSet attrs) {
97 super(context, attrs);
Adrian Roosc2e01682015-01-15 23:20:20 +010098 mIsVoiceCapable = context.getResources().getBoolean(
99 com.android.internal.R.bool.config_voice_capable);
100 mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
101 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
Selim Cinek705442f2016-09-13 16:02:33 -0700102 mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
Jim Miller109f1fd2012-09-19 20:44:16 -0700103 }
104
105 @Override
Jim Miller0928e012012-11-06 18:43:22 -0800106 protected void onAttachedToWindow() {
107 super.onAttachedToWindow();
Dave Mankoffe2294692019-08-14 11:53:13 -0400108 Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback);
Jim Miller0928e012012-11-06 18:43:22 -0800109 }
110
111 @Override
112 protected void onDetachedFromWindow() {
113 super.onDetachedFromWindow();
Dave Mankoffe2294692019-08-14 11:53:13 -0400114 Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback);
Jim Miller0928e012012-11-06 18:43:22 -0800115 }
116
117 @Override
Jim Miller109f1fd2012-09-19 20:44:16 -0700118 protected void onFinishInflate() {
119 super.onFinishInflate();
120 mLockPatternUtils = new LockPatternUtils(mContext);
121 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
122 setOnClickListener(new OnClickListener() {
123 public void onClick(View v) {
124 takeEmergencyCallAction();
125 }
126 });
Selim Cinek705442f2016-09-13 16:02:33 -0700127 setOnLongClickListener(new OnLongClickListener() {
128 @Override
129 public boolean onLongClick(View v) {
130 if (!mLongPressWasDragged
131 && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
132 mEmergencyAffordanceManager.performEmergencyCall();
133 return true;
134 }
135 return false;
136 }
137 });
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700138 whitelistIpcs(this::updateEmergencyCallButton);
Jim Miller109f1fd2012-09-19 20:44:16 -0700139 }
140
Jorim Jaggi76511c72015-05-04 15:34:22 -0700141 @Override
Selim Cinek705442f2016-09-13 16:02:33 -0700142 public boolean onTouchEvent(MotionEvent event) {
143 final int x = (int) event.getX();
144 final int y = (int) event.getY();
145 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
146 mDownX = x;
147 mDownY = y;
148 mLongPressWasDragged = false;
149 } else {
150 final int xDiff = Math.abs(x - mDownX);
151 final int yDiff = Math.abs(y - mDownY);
152 int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
153 if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
154 mLongPressWasDragged = true;
155 }
156 }
157 return super.onTouchEvent(event);
158 }
159
160 @Override
161 public boolean performLongClick() {
162 return super.performLongClick();
163 }
164
165 @Override
Jorim Jaggi76511c72015-05-04 15:34:22 -0700166 protected void onConfigurationChanged(Configuration newConfig) {
167 super.onConfigurationChanged(newConfig);
168 updateEmergencyCallButton();
169 }
170
Jim Miller109f1fd2012-09-19 20:44:16 -0700171 /**
172 * Shows the emergency dialer or returns the user to the existing call.
173 */
174 public void takeEmergencyCallAction() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500175 MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL);
Jim Miller109f1fd2012-09-19 20:44:16 -0700176 // TODO: implement a shorter timeout once new PowerManager API is ready.
177 // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
178 mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
Hall Liu7dac3662016-05-27 13:30:09 -0700179 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700180 ActivityTaskManager.getService().stopSystemLockTaskMode();
Hall Liu7dac3662016-05-27 13:30:09 -0700181 } catch (RemoteException e) {
182 Slog.w(LOG_TAG, "Failed to stop app pinning");
183 }
Adrian Roosc2e01682015-01-15 23:20:20 +0100184 if (isInCall()) {
185 resumeCall();
Andrew Lee72b46d42015-01-30 13:23:21 -0800186 if (mEmergencyButtonCallback != null) {
187 mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
188 }
Jim Miller109f1fd2012-09-19 20:44:16 -0700189 } else {
Dave Mankoffe2294692019-08-14 11:53:13 -0400190 Dependency.get(KeyguardUpdateMonitor.class).reportEmergencyCallAction(
Adrian Roos8d75c142015-03-24 12:57:20 -0700191 true /* bypassHandler */);
192 getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL,
Adrian Roosb5947e02015-05-14 16:14:29 -0700193 ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
Adrian Roosd6aa6cb2015-04-16 19:31:29 -0700194 new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
Jim Miller109f1fd2012-09-19 20:44:16 -0700195 }
196 }
197
Jim Miller52a61332014-11-12 19:29:51 -0800198 private void updateEmergencyCallButton() {
Adrian Roosc2e01682015-01-15 23:20:20 +0100199 boolean visible = false;
200 if (mIsVoiceCapable) {
201 // Emergency calling requires voice capability.
202 if (isInCall()) {
203 visible = true; // always show "return to call" if phone is off-hook
Jim Miller3efe1062012-09-28 16:59:31 -0700204 } else {
Dave Mankoffe2294692019-08-14 11:53:13 -0400205 final boolean simLocked = Dependency.get(KeyguardUpdateMonitor.class)
Adrian Roosc2e01682015-01-15 23:20:20 +0100206 .isSimPinVoiceSecure();
207 if (simLocked) {
208 // Some countries can't handle emergency calls while SIM is locked.
209 visible = mEnableEmergencyCallWhileSimLocked;
210 } else {
211 // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk);
Adrian Roosd6aa6cb2015-04-16 19:31:29 -0700212 visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser());
Adrian Roosc2e01682015-01-15 23:20:20 +0100213 }
Jim Miller3efe1062012-09-28 16:59:31 -0700214 }
Jim Miller109f1fd2012-09-19 20:44:16 -0700215 }
Adrian Roosc2e01682015-01-15 23:20:20 +0100216 if (visible) {
217 setVisibility(View.VISIBLE);
218
219 int textId;
220 if (isInCall()) {
221 textId = com.android.internal.R.string.lockscreen_return_to_call;
222 } else {
223 textId = com.android.internal.R.string.lockscreen_emergency_call;
224 }
225 setText(textId);
226 } else {
227 setVisibility(View.GONE);
228 }
Jim Miller109f1fd2012-09-19 20:44:16 -0700229 }
230
Andrew Lee72b46d42015-01-30 13:23:21 -0800231 public void setCallback(EmergencyButtonCallback callback) {
232 mEmergencyButtonCallback = callback;
233 }
Adrian Roosc2e01682015-01-15 23:20:20 +0100234
235 /**
236 * Resumes a call in progress.
237 */
238 private void resumeCall() {
239 getTelecommManager().showInCallScreen(false);
240 }
241
242 /**
243 * @return {@code true} if there is a call currently in progress.
244 */
245 private boolean isInCall() {
246 return getTelecommManager().isInCall();
247 }
248
249 private TelecomManager getTelecommManager() {
250 return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
251 }
Jim Miller109f1fd2012-09-19 20:44:16 -0700252}