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