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