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