blob: cfe25e277a81763923d9a9423ce700ecde167b23 [file] [log] [blame]
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001/*
2 * Copyright (C) 2006 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.internal.policy.impl;
18
19import android.app.Activity;
20import android.app.ActivityManagerNative;
21import android.app.IActivityManager;
22import android.app.IStatusBar;
23import android.content.BroadcastReceiver;
24import android.content.ContentQueryMap;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.pm.ActivityInfo;
29import android.content.pm.PackageManager;
30import android.content.res.Configuration;
31import android.content.res.Resources;
32import android.database.ContentObserver;
33import android.graphics.Rect;
34import android.os.Handler;
35import android.os.IBinder;
36import android.os.LocalPowerManager;
37import android.os.PowerManager;
38import android.os.RemoteException;
39import android.os.ServiceManager;
40import android.os.SystemClock;
41import android.os.SystemProperties;
42import android.os.Vibrator;
43import android.provider.Settings;
44
45import com.android.internal.policy.PolicyManager;
46import com.android.internal.telephony.ITelephony;
47import android.util.Config;
48import android.util.EventLog;
49import android.util.Log;
Mitsuru Oshima831d0d92009-06-16 18:27:18 -070050import android.view.Display;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080051import android.view.Gravity;
52import android.view.HapticFeedbackConstants;
53import android.view.IWindowManager;
54import android.view.KeyEvent;
55import android.view.MotionEvent;
56import android.view.WindowOrientationListener;
57import android.view.RawInputEvent;
58import android.view.Surface;
59import android.view.View;
60import android.view.ViewConfiguration;
61import android.view.Window;
62import android.view.WindowManager;
63import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
64import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
65import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
66import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
67import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
68import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
Suchi Amalapurapu9cdc9032009-05-14 18:01:07 -070069import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080070import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
71import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
72import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
73import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
Dianne Hackborn5cb8d792009-05-21 17:34:15 -070074import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080075import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
76import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
77import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
78import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
79import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
80import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
81import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
82import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
83import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
84import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
85import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
86import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
87import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
88import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
89import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
90import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
91import android.view.WindowManagerImpl;
92import android.view.WindowManagerPolicy;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080093import android.media.IAudioService;
94import android.media.AudioManager;
95
96/**
The Android Open Source Project0727d222009-03-11 12:11:58 -070097 * WindowManagerPolicy implementation for the Android phone UI. This
98 * introduces a new method suffix, Lp, for an internal lock of the
99 * PhoneWindowManager. This is used to protect some internal state, and
100 * can be acquired with either thw Lw and Li lock held, so has the restrictions
101 * of both of those when held.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800102 */
103public class PhoneWindowManager implements WindowManagerPolicy {
104 static final String TAG = "WindowManager";
105 static final boolean DEBUG = false;
106 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
The Android Open Source Project11267662009-03-18 17:39:47 -0700107 static final boolean DEBUG_LAYOUT = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800108 static final boolean SHOW_STARTING_ANIMATIONS = true;
109 static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
110
111 static final int APPLICATION_LAYER = 1;
112 static final int PHONE_LAYER = 2;
113 static final int SEARCH_BAR_LAYER = 3;
114 static final int STATUS_BAR_PANEL_LAYER = 4;
115 // toasts and the plugged-in battery thing
116 static final int TOAST_LAYER = 5;
117 static final int STATUS_BAR_LAYER = 6;
118 // SIM errors and unlock. Not sure if this really should be in a high layer.
119 static final int PRIORITY_PHONE_LAYER = 7;
120 // like the ANR / app crashed dialogs
121 static final int SYSTEM_ALERT_LAYER = 8;
122 // system-level error dialogs
123 static final int SYSTEM_ERROR_LAYER = 9;
124 // on-screen keyboards and other such input method user interfaces go here.
125 static final int INPUT_METHOD_LAYER = 10;
126 // on-screen keyboards and other such input method user interfaces go here.
127 static final int INPUT_METHOD_DIALOG_LAYER = 11;
128 // the keyguard; nothing on top of these can take focus, since they are
129 // responsible for power management when displayed.
130 static final int KEYGUARD_LAYER = 12;
131 static final int KEYGUARD_DIALOG_LAYER = 13;
132 // things in here CAN NOT take focus, but are shown on top of everything else.
133 static final int SYSTEM_OVERLAY_LAYER = 14;
134
Dianne Hackborn5cb8d792009-05-21 17:34:15 -0700135 static final int APPLICATION_MEDIA_SUBLAYER = -2;
136 static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800137 static final int APPLICATION_PANEL_SUBLAYER = 1;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800138 static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
139
140 static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
141
142 // Debugging: set this to have the system act like there is no hard keyboard.
143 static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
144
145 static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
146 static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
147 static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
148
149 // Vibrator pattern for haptic feedback of a long press.
150 private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800151
Dianne Hackborn0041e972009-07-24 17:14:43 -0700152 // Vibrator pattern for haptic feedback of virtual key press.
153 private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 1, 20, 21};
154
The Android Open Source Project0727d222009-03-11 12:11:58 -0700155 final Object mLock = new Object();
156
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800157 Context mContext;
158 IWindowManager mWindowManager;
159 LocalPowerManager mPowerManager;
160 Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
161
162 /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
163 boolean mEnableShiftMenuBugReports = false;
164
165 boolean mSafeMode;
166 WindowState mStatusBar = null;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800167 WindowState mKeyguard = null;
168 KeyguardViewMediator mKeyguardMediator;
169 GlobalActions mGlobalActions;
170 boolean mShouldTurnOffOnKeyUp;
171 RecentApplicationsDialog mRecentAppsDialog;
172 Handler mHandler;
173
174 boolean mLidOpen;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800175 boolean mScreenOn = false;
176 boolean mOrientationSensorEnabled = false;
177 int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
178 static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
179 int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
180 boolean mHasSoftInput = false;
181
182 // The current size of the screen.
183 int mW, mH;
184 // During layout, the current screen borders with all outer decoration
185 // (status bar, input method dock) accounted for.
186 int mCurLeft, mCurTop, mCurRight, mCurBottom;
187 // During layout, the frame in which content should be displayed
188 // to the user, accounting for all screen decoration except for any
189 // space they deem as available for other content. This is usually
190 // the same as mCur*, but may be larger if the screen decor has supplied
191 // content insets.
192 int mContentLeft, mContentTop, mContentRight, mContentBottom;
193 // During layout, the current screen borders along with input method
194 // windows are placed.
195 int mDockLeft, mDockTop, mDockRight, mDockBottom;
196 // During layout, the layer at which the doc window is placed.
197 int mDockLayer;
198
199 static final Rect mTmpParentFrame = new Rect();
200 static final Rect mTmpDisplayFrame = new Rect();
201 static final Rect mTmpContentFrame = new Rect();
202 static final Rect mTmpVisibleFrame = new Rect();
203
204 WindowState mTopFullscreenOpaqueWindowState;
205 boolean mForceStatusBar;
Suchi Amalapurapu9cdc9032009-05-14 18:01:07 -0700206 boolean mHideKeyguard;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800207 boolean mHomePressed;
208 Intent mHomeIntent;
209 boolean mSearchKeyPressed;
210 boolean mConsumeSearchKeyUp;
211
212 static final int ENDCALL_HOME = 0x1;
213 static final int ENDCALL_SLEEPS = 0x2;
214 static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS;
215 int mEndcallBehavior;
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700216
Mitsuru Oshima831d0d92009-06-16 18:27:18 -0700217 int mLandscapeRotation = -1;
218 int mPortraitRotation = -1;
219
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700220 // Nothing to see here, move along...
221 int mFancyRotationAnimation;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800222
223 ShortcutManager mShortcutManager;
224 PowerManager.WakeLock mBroadcastWakeLock;
225
226 class SettingsObserver extends ContentObserver {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800227 SettingsObserver(Handler handler) {
228 super(handler);
229 }
230
231 void observe() {
232 ContentResolver resolver = mContext.getContentResolver();
233 resolver.registerContentObserver(Settings.System.getUriFor(
234 Settings.System.END_BUTTON_BEHAVIOR), false, this);
235 resolver.registerContentObserver(Settings.System.getUriFor(
236 Settings.System.ACCELEROMETER_ROTATION), false, this);
237 resolver.registerContentObserver(Settings.Secure.getUriFor(
238 Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700239 resolver.registerContentObserver(Settings.System.getUriFor(
240 "fancy_rotation_anim"), false, this);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800241 update();
242 }
243
244 @Override public void onChange(boolean selfChange) {
245 update();
246 try {
Dianne Hackborn32bc91d2009-03-27 16:16:03 -0700247 mWindowManager.setRotation(USE_LAST_ROTATION, false,
248 mFancyRotationAnimation);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800249 } catch (RemoteException e) {
250 // Ignore
251 }
252 }
253
254 public void update() {
255 ContentResolver resolver = mContext.getContentResolver();
Dianne Hackbornae585e82009-03-27 20:56:50 -0700256 boolean updateRotation = false;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700257 synchronized (mLock) {
258 mEndcallBehavior = Settings.System.getInt(resolver,
259 Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR);
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700260 mFancyRotationAnimation = Settings.System.getInt(resolver,
Dianne Hackborn32bc91d2009-03-27 16:16:03 -0700261 "fancy_rotation_anim", 0) != 0 ? 0x80 : 0;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700262 int accelerometerDefault = Settings.System.getInt(resolver,
263 Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
264 if (mAccelerometerDefault != accelerometerDefault) {
265 mAccelerometerDefault = accelerometerDefault;
266 updateOrientationListenerLp();
267 }
268 String imId = Settings.Secure.getString(resolver,
269 Settings.Secure.DEFAULT_INPUT_METHOD);
270 boolean hasSoftInput = imId != null && imId.length() > 0;
271 if (mHasSoftInput != hasSoftInput) {
272 mHasSoftInput = hasSoftInput;
Dianne Hackbornae585e82009-03-27 20:56:50 -0700273 updateRotation = true;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700274 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800275 }
Dianne Hackbornae585e82009-03-27 20:56:50 -0700276 if (updateRotation) {
277 updateRotation(0);
278 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800279 }
280 }
281
282 class MyOrientationListener extends WindowOrientationListener {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800283 MyOrientationListener(Context context) {
284 super(context);
285 }
286
287 @Override
The Android Open Source Projectd06b0972009-03-13 13:04:23 -0700288 public void onOrientationChanged(int rotation) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800289 // Send updates based on orientation value
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700290 if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation);
291 try {
Dianne Hackborn32bc91d2009-03-27 16:16:03 -0700292 mWindowManager.setRotation(rotation, false,
293 mFancyRotationAnimation);
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700294 } catch (RemoteException e) {
295 // Ignore
Wink Saville37c124c2009-04-02 01:37:02 -0700296
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800297 }
298 }
299 }
300 MyOrientationListener mOrientationListener;
301
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700302 boolean useSensorForOrientationLp(int appOrientation) {
303 if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800304 return true;
305 }
306 if (mAccelerometerDefault != 0 && (
Dianne Hackborn03759ed2009-03-27 16:04:08 -0700307 appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
308 appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800309 return true;
310 }
311 return false;
312 }
313
Suchi Amalapurapua9e1b162009-03-24 22:24:47 -0700314 /*
315 * We always let the sensor be switched on by default except when
316 * the user has explicitly disabled sensor based rotation or when the
317 * screen is switched off.
318 */
The Android Open Source Project0727d222009-03-11 12:11:58 -0700319 boolean needSensorRunningLp() {
320 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800321 // If the application has explicitly requested to follow the
322 // orientation, then we need to turn the sensor or.
323 return true;
324 }
Suchi Amalapurapua9e1b162009-03-24 22:24:47 -0700325 if (mAccelerometerDefault == 0) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800326 // If the setting for using the sensor by default is enabled, then
327 // we will always leave it on. Note that the user could go to
328 // a window that forces an orientation that does not use the
329 // sensor and in theory we could turn it off... however, when next
330 // turning it on we won't have a good value for the current
331 // orientation for a little bit, which can cause orientation
332 // changes to lag, so we'd like to keep it always on. (It will
333 // still be turned off when the screen is off.)
Suchi Amalapurapua9e1b162009-03-24 22:24:47 -0700334 return false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800335 }
Suchi Amalapurapua9e1b162009-03-24 22:24:47 -0700336 return true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800337 }
338
339 /*
340 * Various use cases for invoking this function
341 * screen turning off, should always disable listeners if already enabled
342 * screen turned on and current app has sensor based orientation, enable listeners
343 * if not already enabled
344 * screen turned on and current app does not have sensor orientation, disable listeners if
345 * already enabled
346 * screen turning on and current app has sensor based orientation, enable listeners if needed
347 * screen turning on and current app has nosensor based orientation, do nothing
348 */
The Android Open Source Project0727d222009-03-11 12:11:58 -0700349 void updateOrientationListenerLp() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800350 if (!mOrientationListener.canDetectOrientation()) {
351 // If sensor is turned off or nonexistent for some reason
352 return;
353 }
354 //Could have been invoked due to screen turning on or off or
355 //change of the currently visible window's orientation
The Android Open Source Project0727d222009-03-11 12:11:58 -0700356 if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800357 ", current orientation="+mCurrentAppOrientation+
358 ", SensorEnabled="+mOrientationSensorEnabled);
359 boolean disable = true;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700360 if (mScreenOn) {
361 if (needSensorRunningLp()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800362 disable = false;
363 //enable listener if not already enabled
The Android Open Source Project0727d222009-03-11 12:11:58 -0700364 if (!mOrientationSensorEnabled) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800365 mOrientationListener.enable();
366 if(localLOGV) Log.i(TAG, "Enabling listeners");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800367 mOrientationSensorEnabled = true;
368 }
369 }
370 }
371 //check if sensors need to be disabled
The Android Open Source Project0727d222009-03-11 12:11:58 -0700372 if (disable && mOrientationSensorEnabled) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800373 mOrientationListener.disable();
374 if(localLOGV) Log.i(TAG, "Disabling listeners");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800375 mOrientationSensorEnabled = false;
376 }
377 }
378
Dianne Hackborn0041e972009-07-24 17:14:43 -0700379 Runnable mPowerLongPress = new Runnable() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800380 public void run() {
381 mShouldTurnOffOnKeyUp = false;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700382 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800383 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
384 showGlobalActionsDialog();
385 }
386 };
387
388 void showGlobalActionsDialog() {
389 if (mGlobalActions == null) {
390 mGlobalActions = new GlobalActions(mContext);
391 }
392 final boolean keyguardShowing = mKeyguardMediator.isShowing();
393 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
394 if (keyguardShowing) {
395 // since it took two seconds of long press to bring this up,
396 // poke the wake lock so they have some time to see the dialog.
397 mKeyguardMediator.pokeWakelock();
398 }
399 }
400
401 boolean isDeviceProvisioned() {
402 return Settings.Secure.getInt(
403 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
404 }
405
406 /**
407 * When a home-key longpress expires, close other system windows and launch the recent apps
408 */
409 Runnable mHomeLongPress = new Runnable() {
410 public void run() {
411 /*
412 * Eat the longpress so it won't dismiss the recent apps dialog when
413 * the user lets go of the home key
414 */
415 mHomePressed = false;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700416 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800417 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
418 showRecentAppsDialog();
419 }
420 };
421
422 /**
423 * Create (if necessary) and launch the recent apps dialog
424 */
425 void showRecentAppsDialog() {
426 if (mRecentAppsDialog == null) {
427 mRecentAppsDialog = new RecentApplicationsDialog(mContext);
428 }
429 mRecentAppsDialog.show();
430 }
431
432 /** {@inheritDoc} */
433 public void init(Context context, IWindowManager windowManager,
434 LocalPowerManager powerManager) {
435 mContext = context;
436 mWindowManager = windowManager;
437 mPowerManager = powerManager;
438 mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
439 mHandler = new Handler();
440 mOrientationListener = new MyOrientationListener(mContext);
441 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
442 settingsObserver.observe();
443 mShortcutManager = new ShortcutManager(context, mHandler);
444 mShortcutManager.observe();
445 mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
446 mHomeIntent.addCategory(Intent.CATEGORY_HOME);
447 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
448 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
449 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
450 mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
451 "PhoneWindowManager.mBroadcastWakeLock");
452 mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
453 }
454
455 /** {@inheritDoc} */
456 public int checkAddPermission(WindowManager.LayoutParams attrs) {
457 int type = attrs.type;
Mitsuru Oshima831d0d92009-06-16 18:27:18 -0700458
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800459 if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
460 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
461 return WindowManagerImpl.ADD_OKAY;
462 }
463 String permission = null;
464 switch (type) {
465 case TYPE_TOAST:
466 // XXX right now the app process has complete control over
467 // this... should introduce a token to let the system
468 // monitor/control what they are doing.
469 break;
470 case TYPE_INPUT_METHOD:
471 // The window manager will check this.
472 break;
473 case TYPE_PHONE:
474 case TYPE_PRIORITY_PHONE:
475 case TYPE_SYSTEM_ALERT:
476 case TYPE_SYSTEM_ERROR:
477 case TYPE_SYSTEM_OVERLAY:
478 permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
479 break;
480 default:
481 permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
482 }
483 if (permission != null) {
484 if (mContext.checkCallingOrSelfPermission(permission)
485 != PackageManager.PERMISSION_GRANTED) {
486 return WindowManagerImpl.ADD_PERMISSION_DENIED;
487 }
488 }
489 return WindowManagerImpl.ADD_OKAY;
490 }
491
492 public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
493 switch (attrs.type) {
494 case TYPE_SYSTEM_OVERLAY:
495 case TYPE_TOAST:
496 // These types of windows can't receive input events.
497 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
498 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
499 break;
500 }
501 }
502
503 void readLidState() {
504 try {
505 int sw = mWindowManager.getSwitchState(0);
506 if (sw >= 0) {
507 mLidOpen = sw == 0;
508 }
509 } catch (RemoteException e) {
510 // Ignore
511 }
512 }
513
514 /** {@inheritDoc} */
515 public void adjustConfigurationLw(Configuration config) {
516 readLidState();
517 final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
518 mPowerManager.setKeyboardVisibility(lidOpen);
519 config.keyboardHidden = (lidOpen || mHasSoftInput)
520 ? Configuration.KEYBOARDHIDDEN_NO
521 : Configuration.KEYBOARDHIDDEN_YES;
522 config.hardKeyboardHidden = lidOpen
523 ? Configuration.KEYBOARDHIDDEN_NO
524 : Configuration.KEYBOARDHIDDEN_YES;
525 }
526
527 public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
528 if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
529 return true;
530 }
531 int size = ev.getHistorySize();
532 for(int i = 0; i < size; i++) {
533 if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
534 return true;
535 }
536 }
537 return false;
538 }
539
540 /** {@inheritDoc} */
541 public int windowTypeToLayerLw(int type) {
542 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
543 return APPLICATION_LAYER;
544 }
545 switch (type) {
546 case TYPE_STATUS_BAR:
547 return STATUS_BAR_LAYER;
548 case TYPE_STATUS_BAR_PANEL:
549 return STATUS_BAR_PANEL_LAYER;
550 case TYPE_SEARCH_BAR:
551 return SEARCH_BAR_LAYER;
552 case TYPE_PHONE:
553 return PHONE_LAYER;
554 case TYPE_KEYGUARD:
555 return KEYGUARD_LAYER;
556 case TYPE_KEYGUARD_DIALOG:
557 return KEYGUARD_DIALOG_LAYER;
558 case TYPE_SYSTEM_ALERT:
559 return SYSTEM_ALERT_LAYER;
560 case TYPE_SYSTEM_ERROR:
561 return SYSTEM_ERROR_LAYER;
562 case TYPE_INPUT_METHOD:
563 return INPUT_METHOD_LAYER;
564 case TYPE_INPUT_METHOD_DIALOG:
565 return INPUT_METHOD_DIALOG_LAYER;
566 case TYPE_SYSTEM_OVERLAY:
567 return SYSTEM_OVERLAY_LAYER;
568 case TYPE_PRIORITY_PHONE:
569 return PRIORITY_PHONE_LAYER;
570 case TYPE_TOAST:
571 return TOAST_LAYER;
572 }
573 Log.e(TAG, "Unknown window type: " + type);
574 return APPLICATION_LAYER;
575 }
576
577 /** {@inheritDoc} */
578 public int subWindowTypeToLayerLw(int type) {
579 switch (type) {
580 case TYPE_APPLICATION_PANEL:
581 case TYPE_APPLICATION_ATTACHED_DIALOG:
582 return APPLICATION_PANEL_SUBLAYER;
583 case TYPE_APPLICATION_MEDIA:
584 return APPLICATION_MEDIA_SUBLAYER;
Dianne Hackborn5cb8d792009-05-21 17:34:15 -0700585 case TYPE_APPLICATION_MEDIA_OVERLAY:
586 return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800587 case TYPE_APPLICATION_SUB_PANEL:
588 return APPLICATION_SUB_PANEL_SUBLAYER;
589 }
590 Log.e(TAG, "Unknown sub-window type: " + type);
591 return 0;
592 }
593
594 /** {@inheritDoc} */
595 public View addStartingWindow(IBinder appToken, String packageName,
596 int theme, CharSequence nonLocalizedLabel,
597 int labelRes, int icon) {
598 if (!SHOW_STARTING_ANIMATIONS) {
599 return null;
600 }
601 if (packageName == null) {
602 return null;
603 }
604
605 Context context = mContext;
606 boolean setTheme = false;
607 //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
608 // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
609 if (theme != 0 || labelRes != 0) {
610 try {
611 context = context.createPackageContext(packageName, 0);
612 if (theme != 0) {
613 context.setTheme(theme);
614 setTheme = true;
615 }
616 } catch (PackageManager.NameNotFoundException e) {
617 // Ignore
618 }
619 }
620 if (!setTheme) {
621 context.setTheme(com.android.internal.R.style.Theme);
622 }
623
624 Window win = PolicyManager.makeNewWindow(context);
625 if (win.getWindowStyle().getBoolean(
626 com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
627 return null;
628 }
629
630 Resources r = context.getResources();
631 win.setTitle(r.getText(labelRes, nonLocalizedLabel));
632
633 win.setType(
634 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
635 // Force the window flags: this is a fake window, so it is not really
636 // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM
637 // flag because we do know that the next window will take input
638 // focus, so we want to get the IME window up on top of us right away.
639 win.setFlags(
640 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
641 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
642 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
643 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
644 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
645 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
646
647 win.setLayout(WindowManager.LayoutParams.FILL_PARENT,
648 WindowManager.LayoutParams.FILL_PARENT);
649
650 final WindowManager.LayoutParams params = win.getAttributes();
651 params.token = appToken;
652 params.packageName = packageName;
653 params.windowAnimations = win.getWindowStyle().getResourceId(
654 com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
655 params.setTitle("Starting " + packageName);
656
657 try {
658 WindowManagerImpl wm = (WindowManagerImpl)
659 context.getSystemService(Context.WINDOW_SERVICE);
660 View view = win.getDecorView();
661
662 if (win.isFloating()) {
663 // Whoops, there is no way to display an animation/preview
664 // of such a thing! After all that work... let's skip it.
665 // (Note that we must do this here because it is in
666 // getDecorView() where the theme is evaluated... maybe
667 // we should peek the floating attribute from the theme
668 // earlier.)
669 return null;
670 }
671
672 if (localLOGV) Log.v(
673 TAG, "Adding starting window for " + packageName
674 + " / " + appToken + ": "
675 + (view.getParent() != null ? view : null));
676
677 wm.addView(view, params);
678
679 // Only return the view if it was successfully added to the
680 // window manager... which we can tell by it having a parent.
681 return view.getParent() != null ? view : null;
682 } catch (WindowManagerImpl.BadTokenException e) {
683 // ignore
684 Log.w(TAG, appToken + " already running, starting window not displayed");
685 }
686
687 return null;
688 }
689
690 /** {@inheritDoc} */
691 public void removeStartingWindow(IBinder appToken, View window) {
692 // RuntimeException e = new RuntimeException();
693 // Log.i(TAG, "remove " + appToken + " " + window, e);
694
695 if (localLOGV) Log.v(
696 TAG, "Removing starting window for " + appToken + ": " + window);
697
698 if (window != null) {
699 WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE);
700 wm.removeView(window);
701 }
702 }
703
704 /**
705 * Preflight adding a window to the system.
706 *
707 * Currently enforces that three window types are singletons:
708 * <ul>
709 * <li>STATUS_BAR_TYPE</li>
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800710 * <li>KEYGUARD_TYPE</li>
711 * </ul>
712 *
713 * @param win The window to be added
714 * @param attrs Information about the window to be added
715 *
716 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
717 */
718 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
719 switch (attrs.type) {
720 case TYPE_STATUS_BAR:
721 if (mStatusBar != null) {
722 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
723 }
724 mStatusBar = win;
725 break;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800726 case TYPE_KEYGUARD:
727 if (mKeyguard != null) {
728 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
729 }
730 mKeyguard = win;
731 break;
732 }
733 return WindowManagerImpl.ADD_OKAY;
734 }
735
736 /** {@inheritDoc} */
737 public void removeWindowLw(WindowState win) {
738 if (mStatusBar == win) {
739 mStatusBar = null;
740 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800741 else if (mKeyguard == win) {
742 mKeyguard = null;
743 }
744 }
745
746 static final boolean PRINT_ANIM = false;
747
748 /** {@inheritDoc} */
749 public int selectAnimationLw(WindowState win, int transit) {
750 if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
751 + ": transit=" + transit);
752 if (transit == TRANSIT_PREVIEW_DONE) {
753 if (win.hasAppShownWindows()) {
754 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
755 return com.android.internal.R.anim.app_starting_exit;
756 }
757 }
758
759 return 0;
760 }
761
762 static ITelephony getPhoneInterface() {
763 return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
764 }
765
766 static IAudioService getAudioInterface() {
767 return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
768 }
769
770 boolean keyguardOn() {
771 return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
772 }
773
774 private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
775 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
776 WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
777 };
778
779 /** {@inheritDoc} */
780 public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
Dianne Hackborn0041e972009-07-24 17:14:43 -0700781 int repeatCount, int flags) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800782 boolean keyguardOn = keyguardOn();
783
784 if (false) {
785 Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
786 + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
787 }
788
789 // Clear a pending HOME longpress if the user releases Home
790 // TODO: This could probably be inside the next bit of logic, but that code
791 // turned out to be a bit fragile so I'm doing it here explicitly, for now.
792 if ((code == KeyEvent.KEYCODE_HOME) && !down) {
793 mHandler.removeCallbacks(mHomeLongPress);
794 }
795
796 // If the HOME button is currently being held, then we do special
797 // chording with it.
798 if (mHomePressed) {
799
800 // If we have released the home key, and didn't do anything else
801 // while it was pressed, then it is time to go home!
802 if (code == KeyEvent.KEYCODE_HOME) {
803 if (!down) {
804 mHomePressed = false;
805
Dianne Hackborn0041e972009-07-24 17:14:43 -0700806 if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
807 // If an incoming call is ringing, HOME is totally disabled.
808 // (The user is already on the InCallScreen at this point,
809 // and his ONLY options are to answer or reject the call.)
810 boolean incomingRinging = false;
811 try {
812 ITelephony phoneServ = getPhoneInterface();
813 if (phoneServ != null) {
814 incomingRinging = phoneServ.isRinging();
815 } else {
816 Log.w(TAG, "Unable to find ITelephony interface");
817 }
818 } catch (RemoteException ex) {
819 Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800820 }
Dianne Hackborn0041e972009-07-24 17:14:43 -0700821
822 if (incomingRinging) {
823 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
824 } else {
825 launchHomeFromHotKey();
826 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800827 } else {
Dianne Hackborn0041e972009-07-24 17:14:43 -0700828 Log.i(TAG, "Ignoring HOME; event canceled.");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800829 }
830 }
831 }
832
833 return true;
834 }
Dianne Hackborn0041e972009-07-24 17:14:43 -0700835
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800836 // First we always handle the home key here, so applications
837 // can never break it, although if keyguard is on, we do let
838 // it handle it, because that gives us the correct 5 second
839 // timeout.
840 if (code == KeyEvent.KEYCODE_HOME) {
841
842 // If a system window has focus, then it doesn't make sense
843 // right now to interact with applications.
844 WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
845 if (attrs != null) {
846 final int type = attrs.type;
847 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
848 || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
849 // the "app" is keyguard, so give it the key
850 return false;
851 }
852 final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
853 for (int i=0; i<typeCount; i++) {
854 if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
855 // don't do anything, but also don't pass it to the app
856 return true;
857 }
858 }
859 }
860
861 if (down && repeatCount == 0) {
862 if (!keyguardOn) {
863 mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
864 }
865 mHomePressed = true;
866 }
867 return true;
868 } else if (code == KeyEvent.KEYCODE_MENU) {
869 // Hijack modified menu keys for debugging features
870 final int chordBug = KeyEvent.META_SHIFT_ON;
871
872 if (down && repeatCount == 0) {
873 if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
874 Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
875 mContext.sendOrderedBroadcast(intent, null);
876 return true;
877 } else if (SHOW_PROCESSES_ON_ALT_MENU &&
878 (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
879 Intent service = new Intent();
880 service.setClassName(mContext, "com.android.server.LoadAverageService");
881 ContentResolver res = mContext.getContentResolver();
882 boolean shown = Settings.System.getInt(
883 res, Settings.System.SHOW_PROCESSES, 0) != 0;
884 if (!shown) {
885 mContext.startService(service);
886 } else {
887 mContext.stopService(service);
888 }
889 Settings.System.putInt(
890 res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
891 return true;
892 }
893 }
894 } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
895 if (down) {
896 // this key doesn't exist on current hardware, but if a device
897 // didn't have a touchscreen, it would want one of these to open
898 // the status bar.
899 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
900 if (sbs != null) {
901 try {
902 sbs.toggle();
903 } catch (RemoteException e) {
904 // we're screwed anyway, since it's in this process
905 throw new RuntimeException(e);
906 }
907 }
908 }
909 return true;
910 } else if (code == KeyEvent.KEYCODE_SEARCH) {
911 if (down) {
912 if (repeatCount == 0) {
913 mSearchKeyPressed = true;
914 }
915 } else {
916 mSearchKeyPressed = false;
917
918 if (mConsumeSearchKeyUp) {
919 // Consume the up-event
920 mConsumeSearchKeyUp = false;
921 return true;
922 }
923 }
924 }
925
926 // Shortcuts are invoked through Search+key, so intercept those here
927 if (mSearchKeyPressed) {
928 if (down && repeatCount == 0 && !keyguardOn) {
929 Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
930 if (shortcutIntent != null) {
931 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
932 mContext.startActivity(shortcutIntent);
933
934 /*
935 * We launched an app, so the up-event of the search key
936 * should be consumed
937 */
938 mConsumeSearchKeyUp = true;
939 return true;
940 }
941 }
942 }
943
944 return false;
945 }
946
947 /**
948 * A home key -> launch home action was detected. Take the appropriate action
949 * given the situation with the keyguard.
950 */
951 void launchHomeFromHotKey() {
952 if (mKeyguardMediator.isShowing()) {
953 // don't launch home if keyguard showing
954 } else if (mKeyguardMediator.isInputRestricted()) {
955 // when in keyguard restricted mode, must first verify unlock
956 // before launching home
957 mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
958 public void onKeyguardExitResult(boolean success) {
959 if (success) {
Dianne Hackborn256dd3b2009-05-19 18:51:21 -0700960 try {
961 ActivityManagerNative.getDefault().stopAppSwitches();
962 } catch (RemoteException e) {
963 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800964 mContext.startActivity(mHomeIntent);
965 sendCloseSystemWindows();
966 }
967 }
968 });
969 } else {
970 // no keyguard stuff to worry about, just launch home!
Dianne Hackborn256dd3b2009-05-19 18:51:21 -0700971 try {
972 ActivityManagerNative.getDefault().stopAppSwitches();
973 } catch (RemoteException e) {
974 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800975 mContext.startActivity(mHomeIntent);
976 sendCloseSystemWindows();
977 }
978 }
979
980 public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
981 final int fl = attrs.flags;
982
983 if ((fl &
984 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
985 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
986 contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom);
987 } else {
988 contentInset.setEmpty();
989 }
990 }
991
992 /** {@inheritDoc} */
993 public void beginLayoutLw(int displayWidth, int displayHeight) {
994 mW = displayWidth;
995 mH = displayHeight;
996 mDockLeft = mContentLeft = mCurLeft = 0;
997 mDockTop = mContentTop = mCurTop = 0;
998 mDockRight = mContentRight = mCurRight = displayWidth;
999 mDockBottom = mContentBottom = mCurBottom = displayHeight;
1000 mDockLayer = 0x10000000;
1001
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001002 mTopFullscreenOpaqueWindowState = null;
1003 mForceStatusBar = false;
Suchi Amalapurapu9cdc9032009-05-14 18:01:07 -07001004 mHideKeyguard = false;
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001005
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001006 // decide where the status bar goes ahead of time
1007 if (mStatusBar != null) {
1008 final Rect pf = mTmpParentFrame;
1009 final Rect df = mTmpDisplayFrame;
1010 final Rect vf = mTmpVisibleFrame;
1011 pf.left = df.left = vf.left = 0;
1012 pf.top = df.top = vf.top = 0;
1013 pf.right = df.right = vf.right = displayWidth;
1014 pf.bottom = df.bottom = vf.bottom = displayHeight;
1015
1016 mStatusBar.computeFrameLw(pf, df, vf, vf);
1017 if (mStatusBar.isVisibleLw()) {
1018 // If the status bar is hidden, we don't want to cause
1019 // windows behind it to scroll.
1020 mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom;
The Android Open Source Project11267662009-03-18 17:39:47 -07001021 if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockBottom="
1022 + mDockBottom + " mContentBottom="
1023 + mContentBottom + " mCurBottom=" + mCurBottom);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001024 }
1025 }
1026 }
1027
1028 void setAttachedWindowFrames(WindowState win, int fl, int sim,
1029 WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
1030 if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
1031 // Here's a special case: if this attached window is a panel that is
1032 // above the dock window, and the window it is attached to is below
1033 // the dock window, then the frames we computed for the window it is
1034 // attached to can not be used because the dock is effectively part
1035 // of the underlying window and the attached window is floating on top
1036 // of the whole thing. So, we ignore the attached window and explicitly
1037 // compute the frames that would be appropriate without the dock.
1038 df.left = cf.left = vf.left = mDockLeft;
1039 df.top = cf.top = vf.top = mDockTop;
1040 df.right = cf.right = vf.right = mDockRight;
1041 df.bottom = cf.bottom = vf.bottom = mDockBottom;
1042 } else {
1043 // The effective display frame of the attached window depends on
1044 // whether it is taking care of insetting its content. If not,
1045 // we need to use the parent's content frame so that the entire
1046 // window is positioned within that content. Otherwise we can use
1047 // the display frame and let the attached window take care of
1048 // positioning its content appropriately.
1049 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1050 cf.set(attached.getDisplayFrameLw());
1051 } else {
1052 // If the window is resizing, then we want to base the content
1053 // frame on our attached content frame to resize... however,
1054 // things can be tricky if the attached window is NOT in resize
1055 // mode, in which case its content frame will be larger.
1056 // Ungh. So to deal with that, make sure the content frame
1057 // we end up using is not covering the IM dock.
1058 cf.set(attached.getContentFrameLw());
1059 if (attached.getSurfaceLayer() < mDockLayer) {
1060 if (cf.left < mContentLeft) cf.left = mContentLeft;
1061 if (cf.top < mContentTop) cf.top = mContentTop;
1062 if (cf.right > mContentRight) cf.right = mContentRight;
1063 if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
1064 }
1065 }
1066 df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1067 vf.set(attached.getVisibleFrameLw());
1068 }
1069 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
1070 // window should be positioned relative to its parent or the entire
1071 // screen.
1072 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
1073 ? attached.getFrameLw() : df);
1074 }
1075
1076 /** {@inheritDoc} */
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001077 public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
1078 WindowState attached) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001079 // we've already done the status bar
1080 if (win == mStatusBar) {
1081 return;
1082 }
1083
1084 if (false) {
1085 if ("com.google.android.youtube".equals(attrs.packageName)
1086 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1087 Log.i(TAG, "GOTCHA!");
1088 }
1089 }
1090
1091 final int fl = attrs.flags;
1092 final int sim = attrs.softInputMode;
1093
1094 final Rect pf = mTmpParentFrame;
1095 final Rect df = mTmpDisplayFrame;
1096 final Rect cf = mTmpContentFrame;
1097 final Rect vf = mTmpVisibleFrame;
1098
1099 if (attrs.type == TYPE_INPUT_METHOD) {
1100 pf.left = df.left = cf.left = vf.left = mDockLeft;
1101 pf.top = df.top = cf.top = vf.top = mDockTop;
1102 pf.right = df.right = cf.right = vf.right = mDockRight;
1103 pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
1104 // IM dock windows always go to the bottom of the screen.
1105 attrs.gravity = Gravity.BOTTOM;
1106 mDockLayer = win.getSurfaceLayer();
1107 } else {
1108 if ((fl &
1109 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1110 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1111 // This is the case for a normal activity window: we want it
1112 // to cover all of the screen space, and it can take care of
1113 // moving its contents to account for screen decorations that
1114 // intrude into that space.
1115 if (attached != null) {
1116 // If this window is attached to another, our display
1117 // frame is the same as the one we are attached to.
1118 setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
1119 } else {
1120 pf.left = df.left = 0;
1121 pf.top = df.top = 0;
1122 pf.right = df.right = mW;
1123 pf.bottom = df.bottom = mH;
1124 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1125 cf.left = mDockLeft;
1126 cf.top = mDockTop;
1127 cf.right = mDockRight;
1128 cf.bottom = mDockBottom;
1129 } else {
1130 cf.left = mContentLeft;
1131 cf.top = mContentTop;
1132 cf.right = mContentRight;
1133 cf.bottom = mContentBottom;
1134 }
1135 vf.left = mCurLeft;
1136 vf.top = mCurTop;
1137 vf.right = mCurRight;
1138 vf.bottom = mCurBottom;
1139 }
1140 } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
1141 // A window that has requested to fill the entire screen just
1142 // gets everything, period.
1143 pf.left = df.left = cf.left = 0;
1144 pf.top = df.top = cf.top = 0;
1145 pf.right = df.right = cf.right = mW;
1146 pf.bottom = df.bottom = cf.bottom = mH;
1147 vf.left = mCurLeft;
1148 vf.top = mCurTop;
1149 vf.right = mCurRight;
1150 vf.bottom = mCurBottom;
1151 } else if (attached != null) {
1152 // A child window should be placed inside of the same visible
1153 // frame that its parent had.
1154 setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
1155 } else {
1156 // Otherwise, a normal window must be placed inside the content
1157 // of all screen decorations.
1158 pf.left = mContentLeft;
1159 pf.top = mContentTop;
1160 pf.right = mContentRight;
1161 pf.bottom = mContentBottom;
1162 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1163 df.left = cf.left = mDockLeft;
1164 df.top = cf.top = mDockTop;
1165 df.right = cf.right = mDockRight;
1166 df.bottom = cf.bottom = mDockBottom;
1167 } else {
1168 df.left = cf.left = mContentLeft;
1169 df.top = cf.top = mContentTop;
1170 df.right = cf.right = mContentRight;
1171 df.bottom = cf.bottom = mContentBottom;
1172 }
1173 vf.left = mCurLeft;
1174 vf.top = mCurTop;
1175 vf.right = mCurRight;
1176 vf.bottom = mCurBottom;
1177 }
1178 }
1179
1180 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
1181 df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
1182 df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
1183 }
1184
The Android Open Source Project11267662009-03-18 17:39:47 -07001185 if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle()
1186 + ": sim=#" + Integer.toHexString(sim)
1187 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
1188 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
1189
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001190 if (false) {
1191 if ("com.google.android.youtube".equals(attrs.packageName)
1192 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1193 if (true || localLOGV) Log.v(TAG, "Computing frame of " + win +
The Android Open Source Project11267662009-03-18 17:39:47 -07001194 ": sim=#" + Integer.toHexString(sim)
1195 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001196 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
1197 }
1198 }
1199
1200 win.computeFrameLw(pf, df, cf, vf);
1201
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001202 if (win.isVisibleLw()) {
1203 if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
1204 mForceStatusBar = true;
1205 } else if (mTopFullscreenOpaqueWindowState == null
1206 && attrs.type >= FIRST_APPLICATION_WINDOW
1207 && attrs.type <= LAST_APPLICATION_WINDOW
1208 && win.fillsScreenLw(mW, mH, false, false)) {
1209 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
1210 mTopFullscreenOpaqueWindowState = win;
1211 }
Suchi Amalapurapu9cdc9032009-05-14 18:01:07 -07001212 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
1213 // TODO Add a check for the window to be full screen
1214 if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win);
1215 mHideKeyguard = true;
1216 }
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001217 }
1218
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001219 // Dock windows carve out the bottom of the screen, so normal windows
1220 // can't appear underneath them.
1221 if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
1222 int top = win.getContentFrameLw().top;
1223 top += win.getGivenContentInsetsLw().top;
1224 if (mContentBottom > top) {
1225 mContentBottom = top;
1226 }
1227 top = win.getVisibleFrameLw().top;
1228 top += win.getGivenVisibleInsetsLw().top;
1229 if (mCurBottom > top) {
1230 mCurBottom = top;
1231 }
The Android Open Source Project11267662009-03-18 17:39:47 -07001232 if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom="
1233 + mDockBottom + " mContentBottom="
1234 + mContentBottom + " mCurBottom=" + mCurBottom);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001235 }
1236 }
1237
1238 /** {@inheritDoc} */
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001239 public boolean finishLayoutLw() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001240 boolean changed = false;
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001241 boolean hiding = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001242 if (mStatusBar != null) {
1243 //Log.i(TAG, "force=" + mForceStatusBar
1244 // + " top=" + mTopFullscreenOpaqueWindowState);
1245 if (mForceStatusBar) {
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001246 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001247 changed |= mStatusBar.showLw(true);
1248 } else if (mTopFullscreenOpaqueWindowState != null) {
1249 //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
1250 // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
1251 //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs());
1252 WindowManager.LayoutParams lp =
1253 mTopFullscreenOpaqueWindowState.getAttrs();
1254 boolean hideStatusBar =
1255 (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
1256 if (hideStatusBar) {
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001257 if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001258 changed |= mStatusBar.hideLw(true);
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001259 hiding = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001260 } else {
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001261 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001262 changed |= mStatusBar.showLw(true);
1263 }
1264 }
1265 }
Suchi Amalapurapu9cdc9032009-05-14 18:01:07 -07001266 // Hide the key guard if a visible window explicitly specifies that it wants to be displayed
1267 // when the screen is locked
1268 if (mKeyguard != null) {
1269 if (localLOGV) Log.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard);
1270 if (mHideKeyguard) {
1271 changed |= mKeyguard.hideLw(true);
1272 } else {
1273 changed |= mKeyguard.showLw(true);
1274 }
1275 }
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001276
1277 if (changed && hiding) {
1278 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
1279 if (sbs != null) {
1280 try {
1281 // Make sure the window shade is hidden.
1282 sbs.deactivate();
1283 } catch (RemoteException e) {
1284 }
1285 }
1286 }
1287
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001288 return changed;
1289 }
1290
1291 /** {@inheritDoc} */
Dianne Hackborn0ecadf72009-03-31 18:00:37 -07001292 public void beginAnimationLw(int displayWidth, int displayHeight) {
1293 }
1294
1295 /** {@inheritDoc} */
1296 public void animatingWindowLw(WindowState win,
1297 WindowManager.LayoutParams attrs) {
1298 }
1299
1300 /** {@inheritDoc} */
1301 public boolean finishAnimationLw() {
1302 return false;
1303 }
1304
1305 /** {@inheritDoc} */
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001306 public boolean preprocessInputEventTq(RawInputEvent event) {
1307 switch (event.type) {
1308 case RawInputEvent.EV_SW:
1309 if (event.keycode == 0) {
1310 // lid changed state
1311 mLidOpen = event.value == 0;
Dianne Hackborn32bc91d2009-03-27 16:16:03 -07001312 updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001313 if (keyguardIsShowingTq()) {
1314 if (mLidOpen) {
1315 // only do this if it's opening -- closing the device shouldn't turn it
1316 // off, but it also shouldn't turn it on.
1317 mKeyguardMediator.pokeWakelock();
1318 }
1319 } else {
1320 // Light up the keyboard if we are sliding up.
1321 if (mLidOpen) {
1322 mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1323 LocalPowerManager.BUTTON_EVENT);
1324 } else {
1325 mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1326 LocalPowerManager.OTHER_EVENT);
1327 }
1328 }
1329 }
1330 }
1331 return false;
1332 }
1333
1334
1335 /** {@inheritDoc} */
1336 public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
1337 return keycode == KeyEvent.KEYCODE_HOME
1338 || keycode == KeyEvent.KEYCODE_ENDCALL;
1339 }
1340
1341 /** {@inheritDoc} */
1342 public boolean isMovementKeyTi(int keycode) {
1343 switch (keycode) {
1344 case KeyEvent.KEYCODE_DPAD_UP:
1345 case KeyEvent.KEYCODE_DPAD_DOWN:
1346 case KeyEvent.KEYCODE_DPAD_LEFT:
1347 case KeyEvent.KEYCODE_DPAD_RIGHT:
1348 return true;
1349 }
1350 return false;
1351 }
1352
1353
1354 /**
1355 * @return Whether a telephone call is in progress right now.
1356 */
1357 boolean isInCall() {
1358 final ITelephony phone = getPhoneInterface();
1359 if (phone == null) {
1360 Log.w(TAG, "couldn't get ITelephony reference");
1361 return false;
1362 }
1363 try {
1364 return phone.isOffhook();
1365 } catch (RemoteException e) {
1366 Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
1367 return false;
1368 }
1369 }
1370
1371 /**
1372 * @return Whether music is being played right now.
1373 */
1374 boolean isMusicActive() {
Eric Laurent413cb9d2009-07-17 11:52:43 -07001375 final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
1376 if (am == null) {
1377 Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001378 return false;
1379 }
Eric Laurent413cb9d2009-07-17 11:52:43 -07001380 return am.isMusicActive();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001381 }
1382
1383 /**
1384 * Tell the audio service to adjust the volume appropriate to the event.
1385 * @param keycode
1386 */
1387 void sendVolToMusic(int keycode) {
1388 final IAudioService audio = getAudioInterface();
1389 if (audio == null) {
1390 Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
1391 return;
1392 }
1393 try {
1394 // since audio is playing, we shouldn't have to hold a wake lock
1395 // during the call, but we do it as a precaution for the rare possibility
1396 // that the music stops right before we call this
1397 mBroadcastWakeLock.acquire();
1398 audio.adjustStreamVolume(
1399 AudioManager.STREAM_MUSIC,
1400 keycode == KeyEvent.KEYCODE_VOLUME_UP
1401 ? AudioManager.ADJUST_RAISE
1402 : AudioManager.ADJUST_LOWER,
1403 0);
1404 } catch (RemoteException e) {
1405 Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
1406 } finally {
1407 mBroadcastWakeLock.release();
1408 }
1409 }
1410
1411 static boolean isMediaKey(int code) {
1412 if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
Andy Stadler8b89d692009-04-10 16:24:49 -07001413 code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
1414 code == KeyEvent.KEYCODE_MEDIA_STOP ||
1415 code == KeyEvent.KEYCODE_MEDIA_NEXT ||
1416 code == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
1417 code == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
1418 code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001419 return true;
1420 }
1421 return false;
1422 }
1423
1424 /** {@inheritDoc} */
1425 public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
1426 int result = ACTION_PASS_TO_USER;
1427 final boolean isWakeKey = isWakeKeyTq(event);
1428 final boolean keyguardShowing = keyguardIsShowingTq();
1429
1430 if (false) {
1431 Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
1432 + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing);
1433 }
1434
1435 if (keyguardShowing) {
1436 if (screenIsOn) {
1437 // when the screen is on, always give the event to the keyguard
1438 result |= ACTION_PASS_TO_USER;
1439 } else {
1440 // otherwise, don't pass it to the user
1441 result &= ~ACTION_PASS_TO_USER;
1442
1443 final boolean isKeyDown =
1444 (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
1445 if (isWakeKey && isKeyDown) {
1446
1447 // tell the mediator about a wake key, it may decide to
1448 // turn on the screen depending on whether the key is
1449 // appropriate.
1450 if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
1451 && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
1452 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
1453 if (isInCall()) {
1454 // if the keyguard didn't wake the device, we are in call, and
1455 // it is a volume key, turn on the screen so that the user
1456 // can more easily adjust the in call volume.
1457 mKeyguardMediator.pokeWakelock();
1458 } else if (isMusicActive()) {
1459 // when keyguard is showing and screen off, we need
1460 // to handle the volume key for music here
1461 sendVolToMusic(event.keycode);
1462 }
1463 }
1464 }
1465 }
1466 } else if (!screenIsOn) {
1467 if (isWakeKey) {
1468 // a wake key has a sole purpose of waking the device; don't pass
1469 // it to the user
1470 result |= ACTION_POKE_USER_ACTIVITY;
1471 result &= ~ACTION_PASS_TO_USER;
1472 }
1473 }
1474
1475 int type = event.type;
1476 int code = event.keycode;
1477 boolean down = event.value != 0;
1478
1479 if (type == RawInputEvent.EV_KEY) {
Dianne Hackborn0041e972009-07-24 17:14:43 -07001480 if (code == KeyEvent.KEYCODE_ENDCALL
1481 || code == KeyEvent.KEYCODE_POWER) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001482 if (down) {
1483 boolean hungUp = false;
1484 // key repeats are generated by the window manager, and we don't see them
1485 // here, so unless the driver is doing something it shouldn't be, we know
1486 // this is the real press event.
Dianne Hackborn0041e972009-07-24 17:14:43 -07001487 if (code == KeyEvent.KEYCODE_ENDCALL) {
1488 try {
1489 ITelephony phoneServ = getPhoneInterface();
1490 if (phoneServ != null) {
1491 hungUp = phoneServ.endCall();
1492 } else {
1493 Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
1494 }
1495 } catch (RemoteException ex) {
1496 Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001497 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001498 }
1499 if (hungUp || !screenIsOn) {
1500 mShouldTurnOffOnKeyUp = false;
1501 } else {
1502 // only try to turn off the screen if we didn't already hang up
1503 mShouldTurnOffOnKeyUp = true;
Dianne Hackborn0041e972009-07-24 17:14:43 -07001504 mHandler.postDelayed(mPowerLongPress,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001505 ViewConfiguration.getGlobalActionKeyTimeout());
1506 result &= ~ACTION_PASS_TO_USER;
1507 }
1508 } else {
Dianne Hackborn0041e972009-07-24 17:14:43 -07001509 mHandler.removeCallbacks(mPowerLongPress);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001510 if (mShouldTurnOffOnKeyUp) {
1511 mShouldTurnOffOnKeyUp = false;
1512 boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0;
1513 boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0;
1514 if (keyguardShowing
1515 || (sleeps && !gohome)
1516 || (gohome && !goHome() && sleeps)) {
1517 // they must already be on the keyguad or home screen,
1518 // go to sleep instead
1519 Log.d(TAG, "I'm tired mEndcallBehavior=0x"
1520 + Integer.toHexString(mEndcallBehavior));
1521 result &= ~ACTION_POKE_USER_ACTIVITY;
1522 result |= ACTION_GO_TO_SLEEP;
1523 }
1524 result &= ~ACTION_PASS_TO_USER;
1525 }
1526 }
1527 } else if (isMediaKey(code)) {
1528 // This key needs to be handled even if the screen is off.
1529 // If others need to be handled while it's off, this is a reasonable
1530 // pattern to follow.
1531 if ((result & ACTION_PASS_TO_USER) == 0) {
1532 // Only do this if we would otherwise not pass it to the user. In that
1533 // case, the PhoneWindow class will do the same thing, except it will
1534 // only do it if the showing app doesn't process the key on its own.
1535 KeyEvent keyEvent = new KeyEvent(event.when, event.when,
1536 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
1537 code, 0);
1538 mBroadcastWakeLock.acquire();
1539 mHandler.post(new PassHeadsetKey(keyEvent));
1540 }
1541 } else if (code == KeyEvent.KEYCODE_CALL) {
1542 // If an incoming call is ringing, answer it!
1543 // (We handle this key here, rather than in the InCallScreen, to make
1544 // sure we'll respond to the key even if the InCallScreen hasn't come to
1545 // the foreground yet.)
1546
1547 // We answer the call on the DOWN event, to agree with
1548 // the "fallback" behavior in the InCallScreen.
1549 if (down) {
1550 try {
1551 ITelephony phoneServ = getPhoneInterface();
1552 if (phoneServ != null) {
1553 if (phoneServ.isRinging()) {
1554 Log.i(TAG, "interceptKeyTq:"
1555 + " CALL key-down while ringing: Answer the call!");
1556 phoneServ.answerRingingCall();
1557
1558 // And *don't* pass this key thru to the current activity
1559 // (which is presumably the InCallScreen.)
1560 result &= ~ACTION_PASS_TO_USER;
1561 }
1562 } else {
1563 Log.w(TAG, "CALL button: Unable to find ITelephony interface");
1564 }
1565 } catch (RemoteException ex) {
1566 Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
1567 }
1568 }
1569 } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
1570 || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
1571 // If an incoming call is ringing, either VOLUME key means
1572 // "silence ringer". We handle these keys here, rather than
1573 // in the InCallScreen, to make sure we'll respond to them
1574 // even if the InCallScreen hasn't come to the foreground yet.
1575
1576 // Look for the DOWN event here, to agree with the "fallback"
1577 // behavior in the InCallScreen.
1578 if (down) {
1579 try {
1580 ITelephony phoneServ = getPhoneInterface();
1581 if (phoneServ != null) {
1582 if (phoneServ.isRinging()) {
1583 Log.i(TAG, "interceptKeyTq:"
1584 + " VOLUME key-down while ringing: Silence ringer!");
1585 // Silence the ringer. (It's safe to call this
1586 // even if the ringer has already been silenced.)
1587 phoneServ.silenceRinger();
1588
1589 // And *don't* pass this key thru to the current activity
1590 // (which is probably the InCallScreen.)
1591 result &= ~ACTION_PASS_TO_USER;
1592 }
1593 } else {
1594 Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
1595 }
1596 } catch (RemoteException ex) {
1597 Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
1598 }
1599 }
1600 }
1601 }
1602
1603 return result;
1604 }
1605
1606 class PassHeadsetKey implements Runnable {
1607 KeyEvent mKeyEvent;
1608
1609 PassHeadsetKey(KeyEvent keyEvent) {
1610 mKeyEvent = keyEvent;
1611 }
1612
1613 public void run() {
1614 if (ActivityManagerNative.isSystemReady()) {
1615 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
1616 intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
1617 mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
1618 mHandler, Activity.RESULT_OK, null, null);
1619 }
1620 }
1621 }
1622
1623 BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
1624 public void onReceive(Context context, Intent intent) {
1625 mBroadcastWakeLock.release();
1626 }
1627 };
1628
1629 /** {@inheritDoc} */
1630 public boolean isWakeRelMovementTq(int device, int classes,
1631 RawInputEvent event) {
1632 // if it's tagged with one of the wake bits, it wakes up the device
1633 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
1634 }
1635
1636 /** {@inheritDoc} */
1637 public boolean isWakeAbsMovementTq(int device, int classes,
1638 RawInputEvent event) {
1639 // if it's tagged with one of the wake bits, it wakes up the device
1640 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
1641 }
1642
1643 /**
1644 * Given the current state of the world, should this key wake up the device?
1645 */
1646 protected boolean isWakeKeyTq(RawInputEvent event) {
1647 // There are not key maps for trackball devices, but we'd still
1648 // like to have pressing it wake the device up, so force it here.
1649 int keycode = event.keycode;
1650 int flags = event.flags;
1651 if (keycode == RawInputEvent.BTN_MOUSE) {
1652 flags |= WindowManagerPolicy.FLAG_WAKE;
1653 }
1654 return (flags
1655 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
1656 }
1657
1658 /** {@inheritDoc} */
1659 public void screenTurnedOff(int why) {
Dianne Hackborn74489012009-03-24 20:50:09 -07001660 EventLog.writeEvent(70000, 0);
1661 mKeyguardMediator.onScreenTurnedOff(why);
The Android Open Source Project0727d222009-03-11 12:11:58 -07001662 synchronized (mLock) {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001663 mScreenOn = false;
1664 updateOrientationListenerLp();
1665 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001666 }
1667
1668 /** {@inheritDoc} */
1669 public void screenTurnedOn() {
Dianne Hackborn74489012009-03-24 20:50:09 -07001670 EventLog.writeEvent(70000, 1);
1671 mKeyguardMediator.onScreenTurnedOn();
The Android Open Source Project0727d222009-03-11 12:11:58 -07001672 synchronized (mLock) {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001673 mScreenOn = true;
1674 updateOrientationListenerLp();
1675 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001676 }
1677
1678 /** {@inheritDoc} */
1679 public void enableKeyguard(boolean enabled) {
1680 mKeyguardMediator.setKeyguardEnabled(enabled);
1681 }
1682
1683 /** {@inheritDoc} */
1684 public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
1685 mKeyguardMediator.verifyUnlock(callback);
1686 }
1687
1688 /** {@inheritDoc} */
1689 public boolean keyguardIsShowingTq() {
1690 return mKeyguardMediator.isShowing();
1691 }
1692
1693 /** {@inheritDoc} */
1694 public boolean inKeyguardRestrictedKeyInputMode() {
1695 return mKeyguardMediator.isInputRestricted();
1696 }
1697
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001698 void sendCloseSystemWindows() {
1699 sendCloseSystemWindows(mContext, null);
1700 }
1701
1702 void sendCloseSystemWindows(String reason) {
1703 sendCloseSystemWindows(mContext, reason);
1704 }
1705
1706 static void sendCloseSystemWindows(Context context, String reason) {
1707 if (ActivityManagerNative.isSystemReady()) {
1708 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1709 if (reason != null) {
1710 intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason);
1711 }
1712 context.sendBroadcast(intent);
1713 }
1714 }
1715
The Android Open Source Project0727d222009-03-11 12:11:58 -07001716 public int rotationForOrientationLw(int orientation, int lastRotation,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001717 boolean displayEnabled) {
Mitsuru Oshima831d0d92009-06-16 18:27:18 -07001718
1719 if (mPortraitRotation < 0) {
1720 // Initialize the rotation angles for each orientation once.
1721 Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
1722 .getDefaultDisplay();
1723 if (d.getWidth() > d.getHeight()) {
1724 mPortraitRotation = Surface.ROTATION_90;
1725 mLandscapeRotation = Surface.ROTATION_0;
1726 } else {
1727 mPortraitRotation = Surface.ROTATION_0;
1728 mLandscapeRotation = Surface.ROTATION_90;
1729 }
1730 }
1731
The Android Open Source Project0727d222009-03-11 12:11:58 -07001732 synchronized (mLock) {
1733 switch (orientation) {
1734 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
1735 //always return landscape if orientation set to landscape
Mitsuru Oshima831d0d92009-06-16 18:27:18 -07001736 return mLandscapeRotation;
The Android Open Source Project0727d222009-03-11 12:11:58 -07001737 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
1738 //always return portrait if orientation set to portrait
Mitsuru Oshima831d0d92009-06-16 18:27:18 -07001739 return mPortraitRotation;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001740 }
The Android Open Source Project0727d222009-03-11 12:11:58 -07001741 // case for nosensor meaning ignore sensor and consider only lid
1742 // or orientation sensor disabled
1743 //or case.unspecified
1744 if (mLidOpen) {
1745 return Surface.ROTATION_90;
1746 } else {
Dianne Hackborn03759ed2009-03-27 16:04:08 -07001747 if (useSensorForOrientationLp(orientation)) {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001748 // If the user has enabled auto rotation by default, do it.
Dianne Hackborn03759ed2009-03-27 16:04:08 -07001749 int curRotation = mOrientationListener.getCurrentRotation();
1750 return curRotation >= 0 ? curRotation : lastRotation;
The Android Open Source Project0727d222009-03-11 12:11:58 -07001751 }
1752 return Surface.ROTATION_0;
1753 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001754 }
1755 }
1756
1757 public boolean detectSafeMode() {
1758 try {
1759 int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
1760 mSafeMode = menuState > 0;
1761 Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
1762 return mSafeMode;
1763 } catch (RemoteException e) {
1764 // Doom! (it's also local)
1765 throw new RuntimeException("window manager dead");
1766 }
1767 }
1768
1769 /** {@inheritDoc} */
1770 public void systemReady() {
1771 try {
1772 if (mSafeMode) {
1773 // If the user is holding the menu key code, then we are
1774 // going to boot into safe mode.
1775 ActivityManagerNative.getDefault().enterSafeMode();
1776 }
1777 // tell the keyguard
1778 mKeyguardMediator.onSystemReady();
1779 android.os.SystemProperties.set("dev.bootcomplete", "1");
The Android Open Source Project0727d222009-03-11 12:11:58 -07001780 synchronized (mLock) {
1781 updateOrientationListenerLp();
1782 mVibrator = new Vibrator();
1783 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001784 } catch (RemoteException e) {
1785 // Ignore
1786 }
1787 }
1788
1789
1790 /** {@inheritDoc} */
1791 public void enableScreenAfterBoot() {
1792 readLidState();
Dianne Hackborn32bc91d2009-03-27 16:16:03 -07001793 updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001794 }
1795
Dianne Hackborn03759ed2009-03-27 16:04:08 -07001796 void updateRotation(int animFlags) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001797 mPowerManager.setKeyboardVisibility(mLidOpen);
1798 int rotation= Surface.ROTATION_0;
1799 if (mLidOpen) {
1800 // always use landscape if lid is open
1801 rotation = Surface.ROTATION_90;
1802 }
1803 //if lid is closed orientation will be portrait
1804 try {
1805 //set orientation on WindowManager
Dianne Hackborn32bc91d2009-03-27 16:16:03 -07001806 mWindowManager.setRotation(rotation, true,
1807 mFancyRotationAnimation | animFlags);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001808 } catch (RemoteException e) {
1809 // Ignore
1810 }
1811 }
1812
1813 /**
1814 * goes to the home screen
1815 * @return whether it did anything
1816 */
1817 boolean goHome() {
1818 if (false) {
1819 // This code always brings home to the front.
Dianne Hackborn256dd3b2009-05-19 18:51:21 -07001820 try {
1821 ActivityManagerNative.getDefault().stopAppSwitches();
1822 } catch (RemoteException e) {
1823 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001824 mContext.startActivity(mHomeIntent);
1825 } else {
1826 // This code brings home to the front or, if it is already
1827 // at the front, puts the device to sleep.
1828 try {
Dianne Hackborn256dd3b2009-05-19 18:51:21 -07001829 ActivityManagerNative.getDefault().stopAppSwitches();
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001830 int result = ActivityManagerNative.getDefault()
1831 .startActivity(null, mHomeIntent,
1832 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
1833 null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
1834 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
1835 return false;
1836 }
1837 } catch (RemoteException ex) {
1838 // bummer, the activity manager, which is in this process, is dead
1839 }
1840 }
1841 sendCloseSystemWindows();
1842 return true;
1843 }
1844
The Android Open Source Project0727d222009-03-11 12:11:58 -07001845 public void setCurrentOrientationLw(int newOrientation) {
1846 synchronized (mLock) {
1847 if (newOrientation != mCurrentAppOrientation) {
1848 mCurrentAppOrientation = newOrientation;
1849 updateOrientationListenerLp();
1850 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001851 }
1852 }
1853
The Android Open Source Project0727d222009-03-11 12:11:58 -07001854 public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001855 if (!always && Settings.System.getInt(mContext.getContentResolver(),
1856 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
1857 return false;
1858 }
1859 switch (effectId) {
1860 case HapticFeedbackConstants.LONG_PRESS:
1861 mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1);
1862 return true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001863 }
1864 return false;
1865 }
1866
Dianne Hackborn0041e972009-07-24 17:14:43 -07001867 public void keyFeedbackFromInput(KeyEvent event) {
1868 if (event.getAction() == KeyEvent.ACTION_DOWN
1869 && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
1870 mVibrator.vibrate(VIRTUAL_KEY_VIBE_PATTERN, -1);
1871 }
1872 }
1873
The Android Open Source Project0727d222009-03-11 12:11:58 -07001874 public void screenOnStoppedLw() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001875 if (!mKeyguardMediator.isShowing()) {
1876 long curTime = SystemClock.uptimeMillis();
1877 mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
1878 }
1879 }
1880}
Wink Saville37c124c2009-04-02 01:37:02 -07001881