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