• 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 
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.util.Log;
32 
33 import androidx.annotation.Nullable;
34 import androidx.annotation.VisibleForTesting;
35 
36 import com.android.internal.logging.MetricsLogger;
37 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
38 import com.android.internal.widget.LockPatternUtils;
39 import com.android.keyguard.dagger.KeyguardBouncerScope;
40 import com.android.systemui.dagger.qualifiers.Background;
41 import com.android.systemui.dagger.qualifiers.Main;
42 import com.android.systemui.shade.ShadeController;
43 import com.android.systemui.statusbar.policy.ConfigurationController;
44 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
45 import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
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     private static final String TAG = "EmergencyButton";
57     private final ConfigurationController mConfigurationController;
58     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
59     private final PowerManager mPowerManager;
60     private final ActivityTaskManager mActivityTaskManager;
61     private final ShadeController mShadeController;
62     private final TelecomManager mTelecomManager;
63     private final MetricsLogger mMetricsLogger;
64 
65     private EmergencyButtonCallback mEmergencyButtonCallback;
66     private final LockPatternUtils mLockPatternUtils;
67     private final Executor mMainExecutor;
68     private final Executor mBackgroundExecutor;
69     private final SelectedUserInteractor mSelectedUserInteractor;
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, PowerManager powerManager, ActivityTaskManager activityTaskManager, ShadeController shadeController, @Nullable TelecomManager telecomManager, MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, Executor mainExecutor, Executor backgroundExecutor, SelectedUserInteractor selectedUserInteractor)92     public EmergencyButtonController(@Nullable EmergencyButton view,
93             ConfigurationController configurationController,
94             KeyguardUpdateMonitor keyguardUpdateMonitor,
95             PowerManager powerManager,
96             ActivityTaskManager activityTaskManager,
97             ShadeController shadeController,
98             @Nullable TelecomManager telecomManager,
99             MetricsLogger metricsLogger,
100             LockPatternUtils lockPatternUtils,
101             Executor mainExecutor, Executor backgroundExecutor,
102             SelectedUserInteractor selectedUserInteractor) {
103         super(view);
104         mConfigurationController = configurationController;
105         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
106         mPowerManager = powerManager;
107         mActivityTaskManager = activityTaskManager;
108         mShadeController = shadeController;
109         mTelecomManager = telecomManager;
110         mMetricsLogger = metricsLogger;
111         mLockPatternUtils = lockPatternUtils;
112         mMainExecutor = mainExecutor;
113         mBackgroundExecutor = backgroundExecutor;
114         mSelectedUserInteractor = selectedUserInteractor;
115     }
116 
117     @Override
onInit()118     protected void onInit() {
119         whitelistIpcs(this::updateEmergencyCallButton);
120     }
121 
122     @Override
onViewAttached()123     protected void onViewAttached() {
124         mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
125         mConfigurationController.addCallback(mConfigurationListener);
126         mView.setOnClickListener(v -> takeEmergencyCallAction());
127     }
128 
129     @Override
onViewDetached()130     protected void onViewDetached() {
131         mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
132         mConfigurationController.removeCallback(mConfigurationListener);
133     }
134 
135     /**
136      * Updates the visibility of the emergency button.
137      *
138      * This method runs binder calls in a background thread.
139      */
140     @VisibleForTesting
141     @SuppressLint("MissingPermission")
updateEmergencyCallButton()142     public void updateEmergencyCallButton() {
143         if (mView != null) {
144             // Run in bg thread to avoid throttling the main thread with binder call.
145             mBackgroundExecutor.execute(() -> {
146                 boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
147                 boolean isSecure = mLockPatternUtils
148                         .isSecure(mSelectedUserInteractor.getSelectedUserId());
149                 mMainExecutor.execute(() -> mView.updateEmergencyCallButton(
150                         /* isInCall= */ isInCall,
151                         /* hasTelephonyRadio= */ getContext().getPackageManager()
152                                 .hasSystemFeature(PackageManager.FEATURE_TELEPHONY),
153                         /* simLocked= */ mKeyguardUpdateMonitor.isSimPinVoiceSecure(),
154                         /* isSecure= */ isSecure));
155             });
156         }
157     }
158 
setEmergencyButtonCallback(EmergencyButtonCallback callback)159     public void setEmergencyButtonCallback(EmergencyButtonCallback callback) {
160         mEmergencyButtonCallback = callback;
161     }
162     /**
163      * Shows the emergency dialer or returns the user to the existing call.
164      */
165     @SuppressLint("MissingPermission")
takeEmergencyCallAction()166     public void takeEmergencyCallAction() {
167         mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_CALL);
168         if (mPowerManager != null) {
169             mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
170         }
171         mActivityTaskManager.stopSystemLockTaskMode();
172         mShadeController.collapseShade(false);
173         // Run in bg thread to avoid throttling the main thread with binder call.
174         mBackgroundExecutor.execute(() -> {
175             boolean isInCall = mTelecomManager != null && mTelecomManager.isInCall();
176             mMainExecutor.execute(() -> {
177                 if (isInCall) {
178                     mTelecomManager.showInCallScreen(false);
179                     if (mEmergencyButtonCallback != null) {
180                         mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall();
181                     }
182                 } else {
183                     mKeyguardUpdateMonitor.reportEmergencyCallAction(true /* bypassHandler */);
184                     if (mTelecomManager == null) {
185                         Log.wtf(TAG, "TelecomManager was null, cannot launch emergency dialer");
186                         return;
187                     }
188                     Intent emergencyDialIntent =
189                             mTelecomManager.createLaunchEmergencyDialerIntent(null /* number*/)
190                                     .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
191                                             | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
192                                             | Intent.FLAG_ACTIVITY_CLEAR_TOP)
193                                     .putExtra(EmergencyDialerConstants.EXTRA_ENTRY_TYPE,
194                                             EmergencyDialerConstants.ENTRY_TYPE_LOCKSCREEN_BUTTON);
195 
196                     getContext().startActivityAsUser(emergencyDialIntent,
197                             ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(),
198                             new UserHandle(mSelectedUserInteractor.getSelectedUserId()));
199                 }
200             });
201         });
202     }
203 
204     /** */
205     public interface EmergencyButtonCallback {
206         /** */
onEmergencyButtonClickedWhenInCall()207         void onEmergencyButtonClickedWhenInCall();
208     }
209 
210     /** Injectable Factory for creating {@link EmergencyButtonController}. */
211     public static class Factory {
212         private final ConfigurationController mConfigurationController;
213         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
214         private final PowerManager mPowerManager;
215         private final ActivityTaskManager mActivityTaskManager;
216         private final ShadeController mShadeController;
217         @Nullable
218         private final TelecomManager mTelecomManager;
219         private final MetricsLogger mMetricsLogger;
220         private final LockPatternUtils mLockPatternUtils;
221         private final Executor mMainExecutor;
222         private final Executor mBackgroundExecutor;
223         private final SelectedUserInteractor mSelectedUserInteractor;
224 
225         @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)226         public Factory(ConfigurationController configurationController,
227                 KeyguardUpdateMonitor keyguardUpdateMonitor,
228                 PowerManager powerManager,
229                 ActivityTaskManager activityTaskManager,
230                 ShadeController shadeController,
231                 @Nullable TelecomManager telecomManager,
232                 MetricsLogger metricsLogger,
233                 LockPatternUtils lockPatternUtils,
234                 @Main Executor mainExecutor,
235                 @Background Executor backgroundExecutor,
236                 SelectedUserInteractor selectedUserInteractor) {
237 
238             mConfigurationController = configurationController;
239             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
240             mPowerManager = powerManager;
241             mActivityTaskManager = activityTaskManager;
242             mShadeController = shadeController;
243             mTelecomManager = telecomManager;
244             mMetricsLogger = metricsLogger;
245             mLockPatternUtils = lockPatternUtils;
246             mMainExecutor = mainExecutor;
247             mBackgroundExecutor = backgroundExecutor;
248             mSelectedUserInteractor = selectedUserInteractor;
249         }
250 
251         /** Construct an {@link com.android.keyguard.EmergencyButtonController}. */
create(EmergencyButton view)252         public EmergencyButtonController create(EmergencyButton view) {
253             return new EmergencyButtonController(view, mConfigurationController,
254                     mKeyguardUpdateMonitor, mPowerManager, mActivityTaskManager, mShadeController,
255                     mTelecomManager, mMetricsLogger, mLockPatternUtils, mMainExecutor,
256                     mBackgroundExecutor, mSelectedUserInteractor);
257         }
258     }
259 }
260