1 /* 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 17 package com.android.keyguard; 18 19 import android.app.ActivityOptions; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.res.Configuration; 23 import android.os.PowerManager; 24 import android.os.SystemClock; 25 import android.os.UserHandle; 26 import android.telecom.TelecomManager; 27 import android.util.AttributeSet; 28 import android.view.View; 29 import android.widget.Button; 30 31 import com.android.internal.logging.MetricsLogger; 32 import com.android.internal.telephony.IccCardConstants.State; 33 import com.android.internal.widget.LockPatternUtils; 34 35 /** 36 * This class implements a smart emergency button that updates itself based 37 * on telephony state. When the phone is idle, it is an emergency call button. 38 * When there's a call in progress, it presents an appropriate message and 39 * allows the user to return to the call. 40 */ 41 public class EmergencyButton extends Button { 42 private static final Intent INTENT_EMERGENCY_DIAL = new Intent() 43 .setAction("com.android.phone.EmergencyDialer.DIAL") 44 .setPackage("com.android.phone") 45 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 46 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 47 | Intent.FLAG_ACTIVITY_CLEAR_TOP); 48 49 KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { 50 51 @Override 52 public void onSimStateChanged(int subId, int slotId, State simState) { 53 updateEmergencyCallButton(); 54 } 55 56 @Override 57 public void onPhoneStateChanged(int phoneState) { 58 updateEmergencyCallButton(); 59 } 60 }; 61 62 public interface EmergencyButtonCallback { onEmergencyButtonClickedWhenInCall()63 public void onEmergencyButtonClickedWhenInCall(); 64 } 65 66 private LockPatternUtils mLockPatternUtils; 67 private PowerManager mPowerManager; 68 private EmergencyButtonCallback mEmergencyButtonCallback; 69 70 private final boolean mIsVoiceCapable; 71 private final boolean mEnableEmergencyCallWhileSimLocked; 72 EmergencyButton(Context context)73 public EmergencyButton(Context context) { 74 this(context, null); 75 } 76 EmergencyButton(Context context, AttributeSet attrs)77 public EmergencyButton(Context context, AttributeSet attrs) { 78 super(context, attrs); 79 mIsVoiceCapable = context.getResources().getBoolean( 80 com.android.internal.R.bool.config_voice_capable); 81 mEnableEmergencyCallWhileSimLocked = mContext.getResources().getBoolean( 82 com.android.internal.R.bool.config_enable_emergency_call_while_sim_locked); 83 } 84 85 @Override onAttachedToWindow()86 protected void onAttachedToWindow() { 87 super.onAttachedToWindow(); 88 KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mInfoCallback); 89 } 90 91 @Override onDetachedFromWindow()92 protected void onDetachedFromWindow() { 93 super.onDetachedFromWindow(); 94 KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mInfoCallback); 95 } 96 97 @Override onFinishInflate()98 protected void onFinishInflate() { 99 super.onFinishInflate(); 100 mLockPatternUtils = new LockPatternUtils(mContext); 101 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 102 setOnClickListener(new OnClickListener() { 103 public void onClick(View v) { 104 takeEmergencyCallAction(); 105 } 106 }); 107 updateEmergencyCallButton(); 108 } 109 110 @Override onConfigurationChanged(Configuration newConfig)111 protected void onConfigurationChanged(Configuration newConfig) { 112 super.onConfigurationChanged(newConfig); 113 updateEmergencyCallButton(); 114 } 115 116 /** 117 * Shows the emergency dialer or returns the user to the existing call. 118 */ takeEmergencyCallAction()119 public void takeEmergencyCallAction() { 120 MetricsLogger.action(mContext, MetricsLogger.ACTION_EMERGENCY_CALL); 121 // TODO: implement a shorter timeout once new PowerManager API is ready. 122 // should be the equivalent to the old userActivity(EMERGENCY_CALL_TIMEOUT) 123 mPowerManager.userActivity(SystemClock.uptimeMillis(), true); 124 if (isInCall()) { 125 resumeCall(); 126 if (mEmergencyButtonCallback != null) { 127 mEmergencyButtonCallback.onEmergencyButtonClickedWhenInCall(); 128 } 129 } else { 130 KeyguardUpdateMonitor.getInstance(mContext).reportEmergencyCallAction( 131 true /* bypassHandler */); 132 getContext().startActivityAsUser(INTENT_EMERGENCY_DIAL, 133 ActivityOptions.makeCustomAnimation(getContext(), 0, 0).toBundle(), 134 new UserHandle(KeyguardUpdateMonitor.getCurrentUser())); 135 } 136 } 137 updateEmergencyCallButton()138 private void updateEmergencyCallButton() { 139 boolean visible = false; 140 if (mIsVoiceCapable) { 141 // Emergency calling requires voice capability. 142 if (isInCall()) { 143 visible = true; // always show "return to call" if phone is off-hook 144 } else { 145 final boolean simLocked = KeyguardUpdateMonitor.getInstance(mContext) 146 .isSimPinVoiceSecure(); 147 if (simLocked) { 148 // Some countries can't handle emergency calls while SIM is locked. 149 visible = mEnableEmergencyCallWhileSimLocked; 150 } else { 151 // Only show if there is a secure screen (pin/pattern/SIM pin/SIM puk); 152 visible = mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser()); 153 } 154 } 155 } 156 if (visible) { 157 setVisibility(View.VISIBLE); 158 159 int textId; 160 if (isInCall()) { 161 textId = com.android.internal.R.string.lockscreen_return_to_call; 162 } else { 163 textId = com.android.internal.R.string.lockscreen_emergency_call; 164 } 165 setText(textId); 166 } else { 167 setVisibility(View.GONE); 168 } 169 } 170 setCallback(EmergencyButtonCallback callback)171 public void setCallback(EmergencyButtonCallback callback) { 172 mEmergencyButtonCallback = callback; 173 } 174 175 /** 176 * Resumes a call in progress. 177 */ resumeCall()178 private void resumeCall() { 179 getTelecommManager().showInCallScreen(false); 180 } 181 182 /** 183 * @return {@code true} if there is a call currently in progress. 184 */ isInCall()185 private boolean isInCall() { 186 return getTelecommManager().isInCall(); 187 } 188 getTelecommManager()189 private TelecomManager getTelecommManager() { 190 return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 191 } 192 } 193