1 /*
2  * Copyright (C) 2021 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.keyguard;
18 
19 import static com.android.systemui.DejankUtils.whitelistIpcs;
20 
21 import android.annotation.SuppressLint;
22 import android.app.ActivityOptions;
23 import android.app.ActivityTaskManager;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.content.res.Configuration;
27 import android.os.PowerManager;
28 import android.os.SystemClock;
29 import android.os.UserHandle;
30 import android.telecom.TelecomManager;
31 import android.telephony.TelephonyManager;
32 import android.util.Log;
33 
34 import androidx.annotation.Nullable;
35 import androidx.annotation.VisibleForTesting;
36 
37 import com.android.internal.logging.MetricsLogger;
38 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
39 import com.android.internal.widget.LockPatternUtils;
40 import com.android.keyguard.dagger.KeyguardBouncerScope;
41 import com.android.systemui.dagger.qualifiers.Background;
42 import com.android.systemui.dagger.qualifiers.Main;
43 import com.android.systemui.shade.ShadeController;
44 import com.android.systemui.statusbar.policy.ConfigurationController;
45 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
46 import com.android.systemui.util.EmergencyDialerConstants;
47 import com.android.systemui.util.ViewController;
48 
49 import java.util.concurrent.Executor;
50 
51 import javax.inject.Inject;
52 
53 /** View Controller for {@link com.android.keyguard.EmergencyButton}. */
54 @KeyguardBouncerScope
55 public class EmergencyButtonController extends ViewController<EmergencyButton> {
56     static final String LOG_TAG = "EmergencyButton";
57     private final ConfigurationController mConfigurationController;
58     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
59     private final TelephonyManager mTelephonyManager;
60     private final PowerManager mPowerManager;
61     private final ActivityTaskManager mActivityTaskManager;
62     private ShadeController mShadeController;
63     private final TelecomManager mTelecomManager;
64     private final MetricsLogger mMetricsLogger;
65 
66     private EmergencyButtonCallback mEmergencyButtonCallback;
67     private LockPatternUtils mLockPatternUtils;
68     private Executor mMainExecutor;
69     private Executor mBackgroundExecutor;
70 
71     private final KeyguardUpdateMonitorCallback mInfoCallback =
72             new KeyguardUpdateMonitorCallback() {
73         @Override
74         public void onSimStateChanged(int subId, int slotId, int simState) {
75             updateEmergencyCallButton();
76         }
77 
78         @Override
79         public void onPhoneStateChanged(int phoneState) {
80             updateEmergencyCallButton();
81         }
82     };
83 
84     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
85         @Override
86         public void onConfigChanged(Configuration newConfig) {
87             updateEmergencyCallButton();
88         }
89     };
90 
91     @VisibleForTesting
EmergencyButtonController(@ullable EmergencyButton view, ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, Executor mainExecutor, Executor backgroundExecutor)92     public EmergencyButtonController(@Nullable EmergencyButton view,
93             ConfigurationController configurationController,
94             KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
95             PowerManager powerManager, ActivityTaskManager activityTaskManager,
96             ShadeController shadeController,
97             @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
98             LockPatternUtils lockPatternUtils,
99             Executor mainExecutor, Executor backgroundExecutor) {
100         super(view);
101         mConfigurationController = configurationController;
102         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
103         mTelephonyManager = telephonyManager;
104         mPowerManager = powerManager;
105         mActivityTaskManager = activityTaskManager;
106         mShadeController = shadeController;
107         mTelecomManager = telecomManager;
108         mMetricsLogger = metricsLogger;
109         mLockPatternUtils = lockPatternUtils;
110         mMainExecutor = mainExecutor;
111         mBackgroundExecutor = backgroundExecutor;
112     }
113 
114     @Override
onInit()115     protected void onInit() {
116         whitelistIpcs(this::updateEmergencyCallButton);
117     }
118 
119     @Override
onViewAttached()120     protected void onViewAttached() {
121         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
122         mConfigurationController.addCallback(mConfigurationListener);
123         mView.setOnClickListener(v -> takeEmergencyCallAction());
124     }
125 
126     @Override
onViewDetached()127     protected void onViewDetached() {
128         mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
129         mConfigurationController.removeCallback(mConfigurationListener);
130     }
131 
132     /**
133      * Updates the visibility of the emergency button.
134      *
135      * This method runs binder calls in a background thread.
136      */
137     @VisibleForTesting
138     @SuppressLint("MissingPermission")
updateEmergencyCallButton()139     public void updateEmergencyCallButton() {
140         if (mView != null) {
141             // Run in bg thread to avoid throttling the main thread with binder call.
142             mBackgroundExecutor.execute(() -> {
143                 boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
144                 boolean isSecure = mLockPatternUtils
145                         .isSecure(KeyguardUpdateMonitor.getCurrentUser());
146                 mMainExecutor.execute(() -> mView.updateEmergencyCallButton(
147                         /* isInCall= */ isInCall,
148                         /* hasTelephonyRadio= */ getContext().getPackageManager()
149                                 .hasSystemFeature(PackageManager.FEATURE_TELEPHONY),
150                         /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(),
151                         /* isSecure= */ isSecure));
152             });
153         }
154     }
155 
setEmergencyButtonCallback(EmergencyButtonCallback callback)156     public void setEmergencyButtonCallback(EmergencyButtonCallback callback) {
157         mEmergencyButtonCallback = callback;
158     }
159     /**
160      * Shows the emergency dialer or returns the user to the existing call.
161      */
162     @SuppressLint("MissingPermission")
takeEmergencyCallAction()163     public void takeEmergencyCallAction() {
164         mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL);
165         if (mPowerManager != null) {
166             mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
167         }
168         mActivityTaskManager.stopSystemLockTaskMode();
169         mShadeController.collapseShade(false);
170         // Run in bg thread to avoid throttling the main thread with binder call.
171         mBackgroundExecutor.execute(() -> {
172             boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
173             mMainExecutor.execute(() -> {
174                 if (isInCall) {
175                     mTelecomManager.showInCallScreen(false);
176                     if (mEmergencyButtonCallback != null) {
177                         mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
178                     }
179                 } else {
180                     mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */);
181                     if (mTelecomManager == null) {
182                         Log.wtf(LOG_TAG, "TelecomManager was null, cannot launch emergency dialer");
183                         return;
184                     }
185                     Intent emergencyDialIntent =
186                             mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/)
187                                     .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
188                                             | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
189                                             | Intent.FLAG_ACTIVITY_CLEAR_TOP)
190                                     .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
191                                             EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
192 
193                     getContext().startActivityAsUser(emergencyDialIntent,
194                             ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
195                             new UserHandle(KeyguardUpdateMonitor.getCurrentUser()));
196                 }
197             });
198         });
199     }
200 
201     /** */
202     public interface EmergencyButtonCallback {
203         /** */
onEmergencyButtonClickedWhenInCall()204         void onEmergencyButtonClickedWhenInCall();
205     }
206 
207     /** Injectable Factory for creating {@link EmergencyButtonController}. */
208     public static class Factory {
209         private final ConfigurationController mConfigurationController;
210         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
211         private final TelephonyManager mTelephonyManager;
212         private final PowerManager mPowerManager;
213         private final ActivityTaskManager mActivityTaskManager;
214         private ShadeController mShadeController;
215         @Nullable
216         private final TelecomManager mTelecomManager;
217         private final MetricsLogger mMetricsLogger;
218         private final LockPatternUtils mLockPatternUtils;
219         private final Executor mMainExecutor;
220         private final Executor mBackgroundExecutor;
221 
222         @Inject
Factory(ConfigurationController configurationController, KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, @Main Executor mainExecutor, @Background Executor backgroundExecutor)223         public Factory(ConfigurationController configurationController,
224                 KeyguardUpdateMonitor keyguardUpdateMonitor, TelephonyManager telephonyManager,
225                 PowerManager powerManager, ActivityTaskManager activityTaskManager,
226                 ShadeController shadeController,
227                 @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
228                 LockPatternUtils lockPatternUtils,
229                 @Main Executor mainExecutor,
230                 @Background Executor backgroundExecutor) {
231 
232             mConfigurationController = configurationController;
233             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
234             mTelephonyManager = telephonyManager;
235             mPowerManager = powerManager;
236             mActivityTaskManager = activityTaskManager;
237             mShadeController = shadeController;
238             mTelecomManager = telecomManager;
239             mMetricsLogger = metricsLogger;
240             mLockPatternUtils = lockPatternUtils;
241             mMainExecutor = mainExecutor;
242             mBackgroundExecutor = backgroundExecutor;
243         }
244 
245         /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */
create(EmergencyButton view)246         public EmergencyButtonController create(EmergencyButton view) {
247             return new EmergencyButtonController(view, mConfigurationController,
248                     mKeyguardUpdateMonitor, mTelephonyManager, mPowerManager, mActivityTaskManager,
249                     mShadeController, mTelecomManager, mMetricsLogger, mLockPatternUtils,
250                     mMainExecutor, mBackgroundExecutor);
251         }
252     }
253 }
254