PhoneFallbackEventHandler.java revision 86f6786032b1a0380cf089aeeceef7e9d8982ef8
1a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o/*
2a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Copyright (C) 2008 The Android Open Source Project
3a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o *
4a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Licensed under the Apache License, Version 2.0 (the "License");
5a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * you may not use this file except in compliance with the License.
6a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * You may obtain a copy of the License at
7a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o *
8a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o *      http://www.apache.org/licenses/LICENSE-2.0
9a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o *
10a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Unless required by applicable law or agreed to in writing, software
11a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * distributed under the License is distributed on an "AS IS" BASIS,
12a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o * See the License for the specific language governing permissions and
14a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * limitations under the License.
154cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o */
16a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
17a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'opackage com.android.internal.policy.impl;
18a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
19a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.app.KeyguardManager;
20a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.app.SearchManager;
21a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.ActivityNotFoundException;
22a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.Context;
23a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.Intent;
24a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.content.res.Configuration;
25a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.media.AudioManager;
26a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.telephony.TelephonyManager;
27a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.util.EventLog;
28a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.util.Slog;
29a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.View;
30a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.HapticFeedbackConstants;
31a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.FallbackEventHandler;
32a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oimport android.view.KeyEvent;
33a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
34a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'opublic class PhoneFallbackEventHandler implements FallbackEventHandler {
35a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    static String TAG = "PhoneFallbackEventHandler";
36a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
37a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    Context mContext;
38a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    View mView;
39a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
40a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    AudioManager mAudioManager;
41a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    KeyguardManager mKeyguardManager;
42a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    SearchManager mSearchManager;
43a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    TelephonyManager mTelephonyManager;
44a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
45a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    public PhoneFallbackEventHandler(Context context) {
46a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        mContext = context;
47a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    }
48a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
49a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    public void setView(View v) {
50a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        mView = v;
51a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    }
52a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
53a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    public void preDispatchKeyEvent(KeyEvent event) {
54a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
55a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                AudioManager.USE_DEFAULT_STREAM_TYPE);
56a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    }
57a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
58a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    public boolean dispatchKeyEvent(KeyEvent event) {
59a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
60a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        final int action = event.getAction();
61a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        final int keyCode = event.getKeyCode();
62a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
63a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        if (action == KeyEvent.ACTION_DOWN) {
64a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            return onKeyDown(keyCode, event);
65a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        } else {
66a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            return onKeyUp(keyCode, event);
67a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        }
68a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    }
69a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
70a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o    boolean onKeyDown(int keyCode, KeyEvent event) {
71a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        /* ****************************************************************************
72a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o         * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
73a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o         * See the comment in PhoneWindow.onKeyDown
74a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o         * ****************************************************************************/
75a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
76a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
77a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o        switch (keyCode) {
78a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_VOLUME_UP:
79a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_VOLUME_DOWN:
80a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_VOLUME_MUTE: {
81a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
82a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                return true;
83a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            }
84a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
85a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
86a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_MEDIA_PLAY:
87a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_MEDIA_PAUSE:
88a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
89a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
90a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                 * to avoid music playback */
91a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) {
92a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                    return true;  // suppress key event
93a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o                }
94a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_MUTE:
95a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o            case KeyEvent.KEYCODE_HEADSETHOOK:
96            case KeyEvent.KEYCODE_MEDIA_STOP:
97            case KeyEvent.KEYCODE_MEDIA_NEXT:
98            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
99            case KeyEvent.KEYCODE_MEDIA_REWIND:
100            case KeyEvent.KEYCODE_MEDIA_RECORD:
101            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
102                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
103                intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
104                mContext.sendOrderedBroadcast(intent, null);
105                return true;
106            }
107
108            case KeyEvent.KEYCODE_CALL: {
109                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
110                    break;
111                }
112                if (event.getRepeatCount() == 0) {
113                    dispatcher.startTracking(event, this);
114                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
115                    dispatcher.performedLongPress(event);
116                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
117                    // launch the VoiceDialer
118                    Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
119                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
120                    try {
121                        sendCloseSystemWindows();
122                        mContext.startActivity(intent);
123                    } catch (ActivityNotFoundException e) {
124                        startCallActivity();
125                    }
126                }
127                return true;
128            }
129
130            case KeyEvent.KEYCODE_CAMERA: {
131                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
132                    break;
133                }
134                if (event.getRepeatCount() == 0) {
135                    dispatcher.startTracking(event, this);
136                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
137                    dispatcher.performedLongPress(event);
138                    mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
139                    sendCloseSystemWindows();
140                    // Broadcast an intent that the Camera button was longpressed
141                    Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
142                    intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
143                    mContext.sendOrderedBroadcast(intent, null);
144                }
145                return true;
146            }
147
148            case KeyEvent.KEYCODE_SEARCH: {
149                if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null) {
150                    break;
151                }
152                if (event.getRepeatCount() == 0) {
153                    dispatcher.startTracking(event, this);
154                } else if (event.isLongPress() && dispatcher.isTracking(event)) {
155                    Configuration config = mContext.getResources().getConfiguration();
156                    if (config.keyboard == Configuration.KEYBOARD_NOKEYS
157                            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
158                        // launch the search activity
159                        Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
160                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
161                        try {
162                            mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
163                            sendCloseSystemWindows();
164                            getSearchManager().stopSearch();
165                            mContext.startActivity(intent);
166                            // Only clear this if we successfully start the
167                            // activity; otherwise we will allow the normal short
168                            // press action to be performed.
169                            dispatcher.performedLongPress(event);
170                            return true;
171                        } catch (ActivityNotFoundException e) {
172                            // Ignore
173                        }
174                    }
175                }
176                break;
177            }
178        }
179        return false;
180    }
181
182    boolean onKeyUp(int keyCode, KeyEvent event) {
183        Slog.d(TAG, "up " + keyCode);
184        final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
185        if (dispatcher != null) {
186            dispatcher.handleUpEvent(event);
187        }
188
189        switch (keyCode) {
190            case KeyEvent.KEYCODE_VOLUME_UP:
191            case KeyEvent.KEYCODE_VOLUME_DOWN:
192            case KeyEvent.KEYCODE_VOLUME_MUTE: {
193                if (!event.isCanceled()) {
194                    AudioManager audioManager = (AudioManager)mContext.getSystemService(
195                            Context.AUDIO_SERVICE);
196                    if (audioManager != null) {
197                        getAudioManager().handleKeyUp(keyCode,
198                                AudioManager.USE_DEFAULT_STREAM_TYPE);
199                    }
200                }
201                return true;
202            }
203
204            case KeyEvent.KEYCODE_HEADSETHOOK:
205            case KeyEvent.KEYCODE_MUTE:
206            case KeyEvent.KEYCODE_MEDIA_PLAY:
207            case KeyEvent.KEYCODE_MEDIA_PAUSE:
208            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
209            case KeyEvent.KEYCODE_MEDIA_STOP:
210            case KeyEvent.KEYCODE_MEDIA_NEXT:
211            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
212            case KeyEvent.KEYCODE_MEDIA_REWIND:
213            case KeyEvent.KEYCODE_MEDIA_RECORD:
214            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
215                Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
216                intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
217                mContext.sendOrderedBroadcast(intent, null);
218                return true;
219            }
220
221            case KeyEvent.KEYCODE_CAMERA: {
222                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
223                    break;
224                }
225                if (event.isTracking() && !event.isCanceled()) {
226                    // Add short press behavior here if desired
227                }
228                return true;
229            }
230
231            case KeyEvent.KEYCODE_CALL: {
232                if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
233                    break;
234                }
235                if (event.isTracking() && !event.isCanceled()) {
236                    startCallActivity();
237                }
238                return true;
239            }
240        }
241        return false;
242    }
243
244    void startCallActivity() {
245        sendCloseSystemWindows();
246        Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
247        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
248        try {
249            mContext.startActivity(intent);
250        } catch (ActivityNotFoundException e) {
251            Slog.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
252        }
253    }
254
255    SearchManager getSearchManager() {
256        if (mSearchManager == null) {
257            mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
258        }
259        return mSearchManager;
260    }
261
262    TelephonyManager getTelephonyManager() {
263        if (mTelephonyManager == null) {
264            mTelephonyManager = (TelephonyManager)mContext.getSystemService(
265                    Context.TELEPHONY_SERVICE);
266        }
267        return mTelephonyManager;
268    }
269
270    KeyguardManager getKeyguardManager() {
271        if (mKeyguardManager == null) {
272            mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
273        }
274        return mKeyguardManager;
275    }
276
277    AudioManager getAudioManager() {
278        if (mAudioManager == null) {
279            mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
280        }
281        return mAudioManager;
282    }
283
284    void sendCloseSystemWindows() {
285        PhoneWindowManager.sendCloseSystemWindows(mContext, null);
286    }
287}
288
289