• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.internal.policy;
18 
19 import android.annotation.UnsupportedAppUsage;
20 import android.app.KeyguardManager;
21 import android.app.SearchManager;
22 import android.content.ActivityNotFoundException;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Configuration;
26 import android.media.AudioManager;
27 import android.media.session.MediaSessionManager;
28 import android.os.UserHandle;
29 import android.provider.Settings;
30 import android.telephony.TelephonyManager;
31 import android.util.Log;
32 import android.view.FallbackEventHandler;
33 import android.view.HapticFeedbackConstants;
34 import android.view.KeyEvent;
35 import android.view.View;
36 import com.android.internal.policy.PhoneWindow;
37 
38 /**
39  * @hide
40  */
41 public class PhoneFallbackEventHandler implements FallbackEventHandler {
42     private static String TAG = "PhoneFallbackEventHandler";
43     private static final boolean DEBUG = false;
44 
45     @UnsupportedAppUsage
46     Context mContext;
47     @UnsupportedAppUsage
48     View mView;
49 
50     AudioManager mAudioManager;
51     KeyguardManager mKeyguardManager;
52     SearchManager mSearchManager;
53     TelephonyManager mTelephonyManager;
54     MediaSessionManager mMediaSessionManager;
55 
56     @UnsupportedAppUsage
PhoneFallbackEventHandler(Context context)57     public PhoneFallbackEventHandler(Context context) {
58         mContext = context;
59     }
60 
setView(View v)61     public void setView(View v) {
62         mView = v;
63     }
64 
preDispatchKeyEvent(KeyEvent event)65     public void preDispatchKeyEvent(KeyEvent event) {
66         getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
67     }
68 
dispatchKeyEvent(KeyEvent event)69     public boolean dispatchKeyEvent(KeyEvent event) {
70 
71         final int action = event.getAction();
72         final int keyCode = event.getKeyCode();
73 
74         if (action == KeyEvent.ACTION_DOWN) {
75             return onKeyDown(keyCode, event);
76         } else {
77             return onKeyUp(keyCode, event);
78         }
79     }
80 
81     @UnsupportedAppUsage
onKeyDown(int keyCode, KeyEvent event)82     boolean onKeyDown(int keyCode, KeyEvent event) {
83         /* ****************************************************************************
84          * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
85          * See the comment in PhoneWindow.onKeyDown
86          * ****************************************************************************/
87         final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
88 
89         switch (keyCode) {
90             case KeyEvent.KEYCODE_VOLUME_UP:
91             case KeyEvent.KEYCODE_VOLUME_DOWN:
92             case KeyEvent.KEYCODE_VOLUME_MUTE: {
93                 handleVolumeKeyEvent(event);
94                 return true;
95             }
96 
97 
98             case KeyEvent.KEYCODE_MEDIA_PLAY:
99             case KeyEvent.KEYCODE_MEDIA_PAUSE:
100             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
101                 /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
102                  * to avoid music playback */
103                 if (getTelephonyManager().getCallState() != TelephonyManager.CALL_STATE_IDLE) {
104                     return true;  // suppress key event
105                 }
106             case KeyEvent.KEYCODE_MUTE:
107             case KeyEvent.KEYCODE_HEADSETHOOK:
108             case KeyEvent.KEYCODE_MEDIA_STOP:
109             case KeyEvent.KEYCODE_MEDIA_NEXT:
110             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
111             case KeyEvent.KEYCODE_MEDIA_REWIND:
112             case KeyEvent.KEYCODE_MEDIA_RECORD:
113             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
114             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
115                 handleMediaKeyEvent(event);
116                 return true;
117             }
118 
119             case KeyEvent.KEYCODE_CALL: {
120                 if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
121                     break;
122                 }
123                 if (event.getRepeatCount() == 0) {
124                     dispatcher.startTracking(event, this);
125                 } else if (event.isLongPress() && dispatcher.isTracking(event)) {
126                     dispatcher.performedLongPress(event);
127                     if (isUserSetupComplete()) {
128                         mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
129                         // launch the VoiceDialer
130                         Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
131                         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
132                         try {
133                             sendCloseSystemWindows();
134                             mContext.startActivity(intent);
135                         } catch (ActivityNotFoundException e) {
136                             startCallActivity();
137                         }
138                     } else {
139                         Log.i(TAG, "Not starting call activity because user "
140                                 + "setup is in progress.");
141                     }
142                 }
143                 return true;
144             }
145 
146             case KeyEvent.KEYCODE_CAMERA: {
147                 if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
148                     break;
149                 }
150                 if (event.getRepeatCount() == 0) {
151                     dispatcher.startTracking(event, this);
152                 } else if (event.isLongPress() && dispatcher.isTracking(event)) {
153                     dispatcher.performedLongPress(event);
154                     if (isUserSetupComplete()) {
155                         mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
156                         sendCloseSystemWindows();
157                         // Broadcast an intent that the Camera button was longpressed
158                         Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
159                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
160                         intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
161                         mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
162                                 null, null, null, 0, null, null);
163                     } else {
164                         Log.i(TAG, "Not dispatching CAMERA long press because user "
165                                 + "setup is in progress.");
166                     }
167                 }
168                 return true;
169             }
170 
171             case KeyEvent.KEYCODE_SEARCH: {
172                 if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
173                     break;
174                 }
175                 if (event.getRepeatCount() == 0) {
176                     dispatcher.startTracking(event, this);
177                 } else if (event.isLongPress() && dispatcher.isTracking(event)) {
178                     Configuration config = mContext.getResources().getConfiguration();
179                     if (config.keyboard == Configuration.KEYBOARD_NOKEYS
180                             || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
181                         if (isUserSetupComplete()) {
182                             // launch the search activity
183                             Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
184                             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
185                             try {
186                                 mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
187                                 sendCloseSystemWindows();
188                                 getSearchManager().stopSearch();
189                                 mContext.startActivity(intent);
190                                 // Only clear this if we successfully start the
191                                 // activity; otherwise we will allow the normal short
192                                 // press action to be performed.
193                                 dispatcher.performedLongPress(event);
194                                 return true;
195                             } catch (ActivityNotFoundException e) {
196                                 // Ignore
197                             }
198                         } else {
199                             Log.i(TAG, "Not dispatching SEARCH long press because user "
200                                     + "setup is in progress.");
201                         }
202                     }
203                 }
204                 break;
205             }
206         }
207         return false;
208     }
209 
isNotInstantAppAndKeyguardRestricted(KeyEvent.DispatcherState dispatcher)210     private boolean isNotInstantAppAndKeyguardRestricted(KeyEvent.DispatcherState dispatcher) {
211         return !mContext.getPackageManager().isInstantApp()
212                 && (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null);
213     }
214 
215     @UnsupportedAppUsage
onKeyUp(int keyCode, KeyEvent event)216     boolean onKeyUp(int keyCode, KeyEvent event) {
217         if (DEBUG) {
218             Log.d(TAG, "up " + keyCode);
219         }
220         final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
221         if (dispatcher != null) {
222             dispatcher.handleUpEvent(event);
223         }
224 
225         switch (keyCode) {
226             case KeyEvent.KEYCODE_VOLUME_UP:
227             case KeyEvent.KEYCODE_VOLUME_DOWN:
228             case KeyEvent.KEYCODE_VOLUME_MUTE: {
229                 if (!event.isCanceled()) {
230                     handleVolumeKeyEvent(event);
231                 }
232                 return true;
233             }
234 
235             case KeyEvent.KEYCODE_HEADSETHOOK:
236             case KeyEvent.KEYCODE_MUTE:
237             case KeyEvent.KEYCODE_MEDIA_PLAY:
238             case KeyEvent.KEYCODE_MEDIA_PAUSE:
239             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
240             case KeyEvent.KEYCODE_MEDIA_STOP:
241             case KeyEvent.KEYCODE_MEDIA_NEXT:
242             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
243             case KeyEvent.KEYCODE_MEDIA_REWIND:
244             case KeyEvent.KEYCODE_MEDIA_RECORD:
245             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
246             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
247                 handleMediaKeyEvent(event);
248                 return true;
249             }
250 
251             case KeyEvent.KEYCODE_CAMERA: {
252                 if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
253                     break;
254                 }
255                 if (event.isTracking() && !event.isCanceled()) {
256                     // Add short press behavior here if desired
257                 }
258                 return true;
259             }
260 
261             case KeyEvent.KEYCODE_CALL: {
262                 if (isNotInstantAppAndKeyguardRestricted(dispatcher)) {
263                     break;
264                 }
265                 if (event.isTracking() && !event.isCanceled()) {
266                     if (isUserSetupComplete()) {
267                         startCallActivity();
268                     } else {
269                         Log.i(TAG, "Not starting call activity because user "
270                                 + "setup is in progress.");
271                     }
272                 }
273                 return true;
274             }
275         }
276         return false;
277     }
278 
279     @UnsupportedAppUsage
startCallActivity()280     void startCallActivity() {
281         sendCloseSystemWindows();
282         Intent intent = new Intent(Intent.ACTION_CALL_BUTTON);
283         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
284         try {
285             mContext.startActivity(intent);
286         } catch (ActivityNotFoundException e) {
287             Log.w(TAG, "No activity found for android.intent.action.CALL_BUTTON.");
288         }
289     }
290 
getSearchManager()291     SearchManager getSearchManager() {
292         if (mSearchManager == null) {
293             mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
294         }
295         return mSearchManager;
296     }
297 
getTelephonyManager()298     TelephonyManager getTelephonyManager() {
299         if (mTelephonyManager == null) {
300             mTelephonyManager = (TelephonyManager)mContext.getSystemService(
301                     Context.TELEPHONY_SERVICE);
302         }
303         return mTelephonyManager;
304     }
305 
getKeyguardManager()306     KeyguardManager getKeyguardManager() {
307         if (mKeyguardManager == null) {
308             mKeyguardManager = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
309         }
310         return mKeyguardManager;
311     }
312 
getAudioManager()313     AudioManager getAudioManager() {
314         if (mAudioManager == null) {
315             mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
316         }
317         return mAudioManager;
318     }
319 
getMediaSessionManager()320     MediaSessionManager getMediaSessionManager() {
321         if (mMediaSessionManager == null) {
322             mMediaSessionManager =
323                     (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
324         }
325         return mMediaSessionManager;
326     }
327 
sendCloseSystemWindows()328     void sendCloseSystemWindows() {
329         PhoneWindow.sendCloseSystemWindows(mContext, null);
330     }
331 
handleVolumeKeyEvent(KeyEvent keyEvent)332     private void handleVolumeKeyEvent(KeyEvent keyEvent) {
333         getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
334                 AudioManager.USE_DEFAULT_STREAM_TYPE);
335     }
336 
handleMediaKeyEvent(KeyEvent keyEvent)337     private void handleMediaKeyEvent(KeyEvent keyEvent) {
338         getMediaSessionManager().dispatchMediaKeyEventAsSystemService(keyEvent);
339     }
340 
isUserSetupComplete()341     private boolean isUserSetupComplete() {
342         return Settings.Secure.getInt(mContext.getContentResolver(),
343                 Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
344     }
345 }
346 
347