blob: ecd8c8d34aa2c2c523c1fa0c0bad472830d5d83e [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 {
Jim Miller109f1fd2012-09-19 20:44:16 -070053
Hall Liu7dac3662016-05-27 13:30:09 -070054 private static final String LOG_TAG = "EmergencyButton";
Selim Cinek705442f2016-09-13 16:02:33 -070055 private final EmergencyAffordanceManager mEmergencyAffordanceManager;
Hall Liu7dac3662016-05-27 13:30:09 -070056
Selim Cinek705442f2016-09-13 16:02:33 -070057 private int mDownX;
58 private int mDownY;
Jim Miller109f1fd2012-09-19 20:44:16 -070059 KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
60
61 @Override
Jim Miller52a61332014-11-12 19:29:51 -080062 public void onSimStateChanged(int subId, int slotId, State simState) {
63 updateEmergencyCallButton();
Jim Miller109f1fd2012-09-19 20:44:16 -070064 }
65
Jorim Jaggi5cf17872014-03-26 18:31:48 +010066 @Override
67 public void onPhoneStateChanged(int phoneState) {
Jim Miller52a61332014-11-12 19:29:51 -080068 updateEmergencyCallButton();
Jorim Jaggi5cf17872014-03-26 18:31:48 +010069 }
Jim Miller109f1fd2012-09-19 20:44:16 -070070 };
Selim Cinek705442f2016-09-13 16:02:33 -070071 private boolean mLongPressWasDragged;
Andrew Lee72b46d42015-01-30 13:23:21 -080072
73 public interface EmergencyButtonCallback {
74 public void onEmergencyButtonClickedWhenInCall();
75 }
76
Jim Miller109f1fd2012-09-19 20:44:16 -070077 private LockPatternUtils mLockPatternUtils;
78 private PowerManager mPowerManager;
Andrew Lee72b46d42015-01-30 13:23:21 -080079 private EmergencyButtonCallback mEmergencyButtonCallback;
Jim Miller109f1fd2012-09-19 20:44:16 -070080
Adrian Roosc2e01682015-01-15 23:20:20 +010081 private final boolean mIsVoiceCapable;
82 private final boolean mEnableEmergencyCallWhileSimLocked;
83
Jim Miller109f1fd2012-09-19 20:44:16 -070084 public EmergencyButton(Context context) {
85 this(context, null);
86 }
87
88 public EmergencyButton(Context context, AttributeSet attrs) {
89 super(context, attrs);
Adrian Roosc2e01682015-01-15 23:20:20 +010090 mIsVoiceCapable = context.getResources().getBoolean(
91 com.android.internal.R.bool.config_voice_capable);
92 mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean(
93 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked);
Selim Cinek705442f2016-09-13 16:02:33 -070094 mEmergencyAffordanceManager = new EmergencyAffordanceManager(context);
Jim Miller109f1fd2012-09-19 20:44:16 -070095 }
96
97 @Override
Jim Miller0928e012012-11-06 18:43:22 -080098 protected void onAttachedToWindow() {
99 super.onAttachedToWindow();
Dave Mankoffe2294692019-08-14 11:53:13 -0400100 Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback);
Jim Miller0928e012012-11-06 18:43:22 -0800101 }
102
103 @Override
104 protected void onDetachedFromWindow() {
105 super.onDetachedFromWindow();
Dave Mankoffe2294692019-08-14 11:53:13 -0400106 Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback);
Jim Miller0928e012012-11-06 18:43:22 -0800107 }
108
109 @Override
Jim Miller109f1fd2012-09-19 20:44:16 -0700110 protected void onFinishInflate() {
111 super.onFinishInflate();
112 mLockPatternUtils = new LockPatternUtils(mContext);
113 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
114 setOnClickListener(new OnClickListener() {
115 public void onClick(View v) {
116 takeEmergencyCallAction();
117 }
118 });
Selim Cinek705442f2016-09-13 16:02:33 -0700119 setOnLongClickListener(new OnLongClickListener() {
120 @Override
121 public boolean onLongClick(View v) {
122 if (!mLongPressWasDragged
123 && mEmergencyAffordanceManager.needsEmergencyAffordance()) {
124 mEmergencyAffordanceManager.performEmergencyCall();
125 return true;
126 }
127 return false;
128 }
129 });
Lucas Dupin8968f6a2019-08-09 17:41:15 -0700130 whitelistIpcs(this::updateEmergencyCallButton);
Jim Miller109f1fd2012-09-19 20:44:16 -0700131 }
132
Jorim Jaggi76511c72015-05-04 15:34:22 -0700133 @Override
Selim Cinek705442f2016-09-13 16:02:33 -0700134 public boolean onTouchEvent(MotionEvent event) {
135 final int x = (int) event.getX();
136 final int y = (int) event.getY();
137 if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
138 mDownX = x;
139 mDownY = y;
140 mLongPressWasDragged = false;
141 } else {
142 final int xDiff = Math.abs(x - mDownX);
143 final int yDiff = Math.abs(y - mDownY);
144 int touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
145 if (Math.abs(yDiff) > touchSlop || Math.abs(xDiff) > touchSlop) {
146 mLongPressWasDragged = true;
147 }
148 }
149 return super.onTouchEvent(event);
150 }
151
152 @Override
153 public boolean performLongClick() {
154 return super.performLongClick();
155 }
156
157 @Override
Jorim Jaggi76511c72015-05-04 15:34:22 -0700158 protected void onConfigurationChanged(Configuration newConfig) {
159 super.onConfigurationChanged(newConfig);
160 updateEmergencyCallButton();
161 }
162
Jim Miller109f1fd2012-09-19 20:44:16 -0700163 /**
164 * Shows the emergency dialer or returns the user to the existing call.
165 */
166 public void takeEmergencyCallAction() {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500167 MetricsLogger.action(mContext, MetricsEvent.ACTION_EMERGENCY_CALL);
Jim Miller109f1fd2012-09-19 20:44:16 -0700168 // TODO: implement a shorter timeout once new PowerManager API is ready.
169 // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT)
170 mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
Hall Liu7dac3662016-05-27 13:30:09 -0700171 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700172 ActivityTaskManager.getService().stopSystemLockTaskMode();
Hall Liu7dac3662016-05-27 13:30:09 -0700173 } catch (RemoteException e) {
174 Slog.w(LOG_TAG, "Failed to stop app pinning");
175 }
Adrian Roosc2e01682015-01-15 23:20:20 +0100176 if (isInCall()) {
177 resumeCall();
Andrew Lee72b46d42015-01-30 13:23:21 -0800178 if (mEmergencyButtonCallback != null) {
179 mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
180 }
Jim Miller109f1fd2012-09-19 20:44:16 -0700181 } else {
Dave Mankoffe2294692019-08-14 11:53:13 -0400182 Dependency.get(KeyguardUpdateMonitor.class).reportEmergencyCallAction(
Adrian Roos8d75c142015-03-24 12:57:20 -0700183 true /* bypassHandler */);
Fan Zhangf9914762019-11-01 15:58:38 -0700184 Intent emergencyDialIntent =
185 getTelecommManager().createLaunchEmergencyDialerIntent(null /* number*/)
186 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
187 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
188 | Intent.FLAG_ACTIVITY_CLEAR_TOP)
189 .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
190 EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
191
192 getContext().startActivityAsUser(emergencyDialIntent,
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}