blob: 9a254bcfae2bcf56b8e0f1ecb26e251aea60e968 [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;
50import android.view.Gravity;
51import android.view.HapticFeedbackConstants;
52import android.view.IWindowManager;
53import android.view.KeyEvent;
54import android.view.MotionEvent;
55import android.view.WindowOrientationListener;
56import android.view.RawInputEvent;
57import android.view.Surface;
58import android.view.View;
59import android.view.ViewConfiguration;
60import android.view.Window;
61import android.view.WindowManager;
62import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
63import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
64import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
65import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
66import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
67import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
68import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
69import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
70import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
71import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
72import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
73import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
74import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
75import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
76import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
77import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
78import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
79import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
80import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
81import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
82import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
83import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
84import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
85import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
86import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
87import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
88import android.view.WindowManagerImpl;
89import android.view.WindowManagerPolicy;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080090import android.media.IAudioService;
91import android.media.AudioManager;
92
93/**
The Android Open Source Project0727d222009-03-11 12:11:58 -070094 * WindowManagerPolicy implementation for the Android phone UI. This
95 * introduces a new method suffix, Lp, for an internal lock of the
96 * PhoneWindowManager. This is used to protect some internal state, and
97 * can be acquired with either thw Lw and Li lock held, so has the restrictions
98 * of both of those when held.
The Android Open Source Project1f838aa2009-03-03 19:32:13 -080099 */
100public class PhoneWindowManager implements WindowManagerPolicy {
101 static final String TAG = "WindowManager";
102 static final boolean DEBUG = false;
103 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
104 static final boolean SHOW_STARTING_ANIMATIONS = true;
105 static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
106
107 static final int APPLICATION_LAYER = 1;
108 static final int PHONE_LAYER = 2;
109 static final int SEARCH_BAR_LAYER = 3;
110 static final int STATUS_BAR_PANEL_LAYER = 4;
111 // toasts and the plugged-in battery thing
112 static final int TOAST_LAYER = 5;
113 static final int STATUS_BAR_LAYER = 6;
114 // SIM errors and unlock. Not sure if this really should be in a high layer.
115 static final int PRIORITY_PHONE_LAYER = 7;
116 // like the ANR / app crashed dialogs
117 static final int SYSTEM_ALERT_LAYER = 8;
118 // system-level error dialogs
119 static final int SYSTEM_ERROR_LAYER = 9;
120 // on-screen keyboards and other such input method user interfaces go here.
121 static final int INPUT_METHOD_LAYER = 10;
122 // on-screen keyboards and other such input method user interfaces go here.
123 static final int INPUT_METHOD_DIALOG_LAYER = 11;
124 // the keyguard; nothing on top of these can take focus, since they are
125 // responsible for power management when displayed.
126 static final int KEYGUARD_LAYER = 12;
127 static final int KEYGUARD_DIALOG_LAYER = 13;
128 // things in here CAN NOT take focus, but are shown on top of everything else.
129 static final int SYSTEM_OVERLAY_LAYER = 14;
130
131 static final int APPLICATION_PANEL_SUBLAYER = 1;
132 static final int APPLICATION_MEDIA_SUBLAYER = -1;
133 static final int APPLICATION_SUB_PANEL_SUBLAYER = 2;
134
135 static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f;
136
137 // Debugging: set this to have the system act like there is no hard keyboard.
138 static final boolean KEYBOARD_ALWAYS_HIDDEN = false;
139
140 static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
141 static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
142 static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
143
144 // Vibrator pattern for haptic feedback of a long press.
145 private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800146
The Android Open Source Project0727d222009-03-11 12:11:58 -0700147 final Object mLock = new Object();
148
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800149 Context mContext;
150 IWindowManager mWindowManager;
151 LocalPowerManager mPowerManager;
152 Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
153
154 /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
155 boolean mEnableShiftMenuBugReports = false;
156
157 boolean mSafeMode;
158 WindowState mStatusBar = null;
159 WindowState mSearchBar = null;
160 WindowState mKeyguard = null;
161 KeyguardViewMediator mKeyguardMediator;
162 GlobalActions mGlobalActions;
163 boolean mShouldTurnOffOnKeyUp;
164 RecentApplicationsDialog mRecentAppsDialog;
165 Handler mHandler;
166
167 boolean mLidOpen;
168 int mSensorRotation = -1;
169 boolean mScreenOn = false;
170 boolean mOrientationSensorEnabled = false;
171 int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
172 static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
173 int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
174 boolean mHasSoftInput = false;
175
176 // The current size of the screen.
177 int mW, mH;
178 // During layout, the current screen borders with all outer decoration
179 // (status bar, input method dock) accounted for.
180 int mCurLeft, mCurTop, mCurRight, mCurBottom;
181 // During layout, the frame in which content should be displayed
182 // to the user, accounting for all screen decoration except for any
183 // space they deem as available for other content. This is usually
184 // the same as mCur*, but may be larger if the screen decor has supplied
185 // content insets.
186 int mContentLeft, mContentTop, mContentRight, mContentBottom;
187 // During layout, the current screen borders along with input method
188 // windows are placed.
189 int mDockLeft, mDockTop, mDockRight, mDockBottom;
190 // During layout, the layer at which the doc window is placed.
191 int mDockLayer;
192
193 static final Rect mTmpParentFrame = new Rect();
194 static final Rect mTmpDisplayFrame = new Rect();
195 static final Rect mTmpContentFrame = new Rect();
196 static final Rect mTmpVisibleFrame = new Rect();
197
198 WindowState mTopFullscreenOpaqueWindowState;
199 boolean mForceStatusBar;
200 boolean mHomePressed;
201 Intent mHomeIntent;
202 boolean mSearchKeyPressed;
203 boolean mConsumeSearchKeyUp;
204
205 static final int ENDCALL_HOME = 0x1;
206 static final int ENDCALL_SLEEPS = 0x2;
207 static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS;
208 int mEndcallBehavior;
209
210 ShortcutManager mShortcutManager;
211 PowerManager.WakeLock mBroadcastWakeLock;
212
213 class SettingsObserver extends ContentObserver {
214 private ContentQueryMap mSettings;
215
216 SettingsObserver(Handler handler) {
217 super(handler);
218 }
219
220 void observe() {
221 ContentResolver resolver = mContext.getContentResolver();
222 resolver.registerContentObserver(Settings.System.getUriFor(
223 Settings.System.END_BUTTON_BEHAVIOR), false, this);
224 resolver.registerContentObserver(Settings.System.getUriFor(
225 Settings.System.ACCELEROMETER_ROTATION), false, this);
226 resolver.registerContentObserver(Settings.Secure.getUriFor(
227 Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
228 update();
229 }
230
231 @Override public void onChange(boolean selfChange) {
232 update();
233 try {
234 mWindowManager.setRotation(USE_LAST_ROTATION, false);
235 } catch (RemoteException e) {
236 // Ignore
237 }
238 }
239
240 public void update() {
241 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project0727d222009-03-11 12:11:58 -0700242 synchronized (mLock) {
243 mEndcallBehavior = Settings.System.getInt(resolver,
244 Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR);
245 int accelerometerDefault = Settings.System.getInt(resolver,
246 Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
247 if (mAccelerometerDefault != accelerometerDefault) {
248 mAccelerometerDefault = accelerometerDefault;
249 updateOrientationListenerLp();
250 }
251 String imId = Settings.Secure.getString(resolver,
252 Settings.Secure.DEFAULT_INPUT_METHOD);
253 boolean hasSoftInput = imId != null && imId.length() > 0;
254 if (mHasSoftInput != hasSoftInput) {
255 mHasSoftInput = hasSoftInput;
256 updateRotation();
257 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800258 }
259 }
260 }
261
262 class MyOrientationListener extends WindowOrientationListener {
263 private static final int _LOWER_THRESHOLD = 30;
264 private static final int _UPPER_THRESHOLD = 60;
265
266 MyOrientationListener(Context context) {
267 super(context);
268 }
269
270 @Override
271 public void onOrientationChanged(int orientation) {
272 // ignore orientation changes unless the value is in a range
273 // When switching from portrait to landscape try to use a lower threshold limit
274 // Use upper threshold limit when switching from landscape to portrait
275 // this is to delay the switch as much as we can
276 int rotation;
277 int threshold = (mSensorRotation == Surface.ROTATION_90) ? _UPPER_THRESHOLD :
278 _LOWER_THRESHOLD;
279
280 if ((orientation >= 0 && orientation <= _UPPER_THRESHOLD) ||
281 (orientation >= 270 - _LOWER_THRESHOLD)) {
282 rotation = (orientation >= 270 - _LOWER_THRESHOLD
283 && orientation <= 270 + threshold)
284 ? Surface.ROTATION_90 : Surface.ROTATION_0;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800285 } else {
286 // ignore orientation value
287 return;
288 }
289 // Send updates based on orientation value
290 if (rotation != mSensorRotation) {
291 if(localLOGV) Log.i(TAG, "onOrientationChanged, rotation changed from "+rotation+" to "+mSensorRotation);
292 // Update window manager. The lid rotation hasn't changed,
293 // but we want it to re-evaluate the final rotation in case
294 // it needs to call back and get the sensor orientation.
295 mSensorRotation = rotation;
296 try {
297 mWindowManager.setRotation(rotation, false);
298 } catch (RemoteException e) {
299 // Ignore
300 }
301 }
302 }
303 }
304 MyOrientationListener mOrientationListener;
305
The Android Open Source Project0727d222009-03-11 12:11:58 -0700306 boolean useSensorForOrientationLp() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800307 if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
308 return true;
309 }
310 if (mAccelerometerDefault != 0 && (
311 mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
312 mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
313 return true;
314 }
315 return false;
316 }
317
The Android Open Source Project0727d222009-03-11 12:11:58 -0700318 boolean needSensorRunningLp() {
319 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800320 // If the application has explicitly requested to follow the
321 // orientation, then we need to turn the sensor or.
322 return true;
323 }
324 if (mAccelerometerDefault != 0) {
325 // If the setting for using the sensor by default is enabled, then
326 // we will always leave it on. Note that the user could go to
327 // a window that forces an orientation that does not use the
328 // sensor and in theory we could turn it off... however, when next
329 // turning it on we won't have a good value for the current
330 // orientation for a little bit, which can cause orientation
331 // changes to lag, so we'd like to keep it always on. (It will
332 // still be turned off when the screen is off.)
333 return true;
334 }
335 return false;
336 }
337
338 /*
339 * Various use cases for invoking this function
340 * screen turning off, should always disable listeners if already enabled
341 * screen turned on and current app has sensor based orientation, enable listeners
342 * if not already enabled
343 * screen turned on and current app does not have sensor orientation, disable listeners if
344 * already enabled
345 * screen turning on and current app has sensor based orientation, enable listeners if needed
346 * screen turning on and current app has nosensor based orientation, do nothing
347 */
The Android Open Source Project0727d222009-03-11 12:11:58 -0700348 void updateOrientationListenerLp() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800349 if (!mOrientationListener.canDetectOrientation()) {
350 // If sensor is turned off or nonexistent for some reason
351 return;
352 }
353 //Could have been invoked due to screen turning on or off or
354 //change of the currently visible window's orientation
The Android Open Source Project0727d222009-03-11 12:11:58 -0700355 if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800356 ", current orientation="+mCurrentAppOrientation+
357 ", SensorEnabled="+mOrientationSensorEnabled);
358 boolean disable = true;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700359 if (mScreenOn) {
360 if (needSensorRunningLp()) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800361 disable = false;
362 //enable listener if not already enabled
The Android Open Source Project0727d222009-03-11 12:11:58 -0700363 if (!mOrientationSensorEnabled) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800364 mOrientationListener.enable();
365 if(localLOGV) Log.i(TAG, "Enabling listeners");
366 // We haven't had the sensor on, so don't yet know
367 // the rotation.
368 mSensorRotation = -1;
369 mOrientationSensorEnabled = true;
370 }
371 }
372 }
373 //check if sensors need to be disabled
The Android Open Source Project0727d222009-03-11 12:11:58 -0700374 if (disable && mOrientationSensorEnabled) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800375 mOrientationListener.disable();
376 if(localLOGV) Log.i(TAG, "Disabling listeners");
377 mSensorRotation = -1;
378 mOrientationSensorEnabled = false;
379 }
380 }
381
382 Runnable mEndCallLongPress = new Runnable() {
383 public void run() {
384 mShouldTurnOffOnKeyUp = false;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700385 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800386 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
387 showGlobalActionsDialog();
388 }
389 };
390
391 void showGlobalActionsDialog() {
392 if (mGlobalActions == null) {
393 mGlobalActions = new GlobalActions(mContext);
394 }
395 final boolean keyguardShowing = mKeyguardMediator.isShowing();
396 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
397 if (keyguardShowing) {
398 // since it took two seconds of long press to bring this up,
399 // poke the wake lock so they have some time to see the dialog.
400 mKeyguardMediator.pokeWakelock();
401 }
402 }
403
404 boolean isDeviceProvisioned() {
405 return Settings.Secure.getInt(
406 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
407 }
408
409 /**
410 * When a home-key longpress expires, close other system windows and launch the recent apps
411 */
412 Runnable mHomeLongPress = new Runnable() {
413 public void run() {
414 /*
415 * Eat the longpress so it won't dismiss the recent apps dialog when
416 * the user lets go of the home key
417 */
418 mHomePressed = false;
The Android Open Source Project0727d222009-03-11 12:11:58 -0700419 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
The Android Open Source Project1f838aa2009-03-03 19:32:13 -0800420 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
421 showRecentAppsDialog();
422 }
423 };
424
425 /**
426 * Create (if necessary) and launch the recent apps dialog
427 */
428 void showRecentAppsDialog() {
429 if (mRecentAppsDialog == null) {
430 mRecentAppsDialog = new RecentApplicationsDialog(mContext);
431 }
432 mRecentAppsDialog.show();
433 }
434
435 /** {@inheritDoc} */
436 public void init(Context context, IWindowManager windowManager,
437 LocalPowerManager powerManager) {
438 mContext = context;
439 mWindowManager = windowManager;
440 mPowerManager = powerManager;
441 mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
442 mHandler = new Handler();
443 mOrientationListener = new MyOrientationListener(mContext);
444 SettingsObserver settingsObserver = new SettingsObserver(mHandler);
445 settingsObserver.observe();
446 mShortcutManager = new ShortcutManager(context, mHandler);
447 mShortcutManager.observe();
448 mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
449 mHomeIntent.addCategory(Intent.CATEGORY_HOME);
450 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
451 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
452 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
453 mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
454 "PhoneWindowManager.mBroadcastWakeLock");
455 mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
456 }
457
458 /** {@inheritDoc} */
459 public int checkAddPermission(WindowManager.LayoutParams attrs) {
460 int type = attrs.type;
461 if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
462 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
463 return WindowManagerImpl.ADD_OKAY;
464 }
465 String permission = null;
466 switch (type) {
467 case TYPE_TOAST:
468 // XXX right now the app process has complete control over
469 // this... should introduce a token to let the system
470 // monitor/control what they are doing.
471 break;
472 case TYPE_INPUT_METHOD:
473 // The window manager will check this.
474 break;
475 case TYPE_PHONE:
476 case TYPE_PRIORITY_PHONE:
477 case TYPE_SYSTEM_ALERT:
478 case TYPE_SYSTEM_ERROR:
479 case TYPE_SYSTEM_OVERLAY:
480 permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
481 break;
482 default:
483 permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
484 }
485 if (permission != null) {
486 if (mContext.checkCallingOrSelfPermission(permission)
487 != PackageManager.PERMISSION_GRANTED) {
488 return WindowManagerImpl.ADD_PERMISSION_DENIED;
489 }
490 }
491 return WindowManagerImpl.ADD_OKAY;
492 }
493
494 public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
495 switch (attrs.type) {
496 case TYPE_SYSTEM_OVERLAY:
497 case TYPE_TOAST:
498 // These types of windows can't receive input events.
499 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
500 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
501 break;
502 }
503 }
504
505 void readLidState() {
506 try {
507 int sw = mWindowManager.getSwitchState(0);
508 if (sw >= 0) {
509 mLidOpen = sw == 0;
510 }
511 } catch (RemoteException e) {
512 // Ignore
513 }
514 }
515
516 /** {@inheritDoc} */
517 public void adjustConfigurationLw(Configuration config) {
518 readLidState();
519 final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
520 mPowerManager.setKeyboardVisibility(lidOpen);
521 config.keyboardHidden = (lidOpen || mHasSoftInput)
522 ? Configuration.KEYBOARDHIDDEN_NO
523 : Configuration.KEYBOARDHIDDEN_YES;
524 config.hardKeyboardHidden = lidOpen
525 ? Configuration.KEYBOARDHIDDEN_NO
526 : Configuration.KEYBOARDHIDDEN_YES;
527 }
528
529 public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
530 if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
531 return true;
532 }
533 int size = ev.getHistorySize();
534 for(int i = 0; i < size; i++) {
535 if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) {
536 return true;
537 }
538 }
539 return false;
540 }
541
542 /** {@inheritDoc} */
543 public int windowTypeToLayerLw(int type) {
544 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
545 return APPLICATION_LAYER;
546 }
547 switch (type) {
548 case TYPE_STATUS_BAR:
549 return STATUS_BAR_LAYER;
550 case TYPE_STATUS_BAR_PANEL:
551 return STATUS_BAR_PANEL_LAYER;
552 case TYPE_SEARCH_BAR:
553 return SEARCH_BAR_LAYER;
554 case TYPE_PHONE:
555 return PHONE_LAYER;
556 case TYPE_KEYGUARD:
557 return KEYGUARD_LAYER;
558 case TYPE_KEYGUARD_DIALOG:
559 return KEYGUARD_DIALOG_LAYER;
560 case TYPE_SYSTEM_ALERT:
561 return SYSTEM_ALERT_LAYER;
562 case TYPE_SYSTEM_ERROR:
563 return SYSTEM_ERROR_LAYER;
564 case TYPE_INPUT_METHOD:
565 return INPUT_METHOD_LAYER;
566 case TYPE_INPUT_METHOD_DIALOG:
567 return INPUT_METHOD_DIALOG_LAYER;
568 case TYPE_SYSTEM_OVERLAY:
569 return SYSTEM_OVERLAY_LAYER;
570 case TYPE_PRIORITY_PHONE:
571 return PRIORITY_PHONE_LAYER;
572 case TYPE_TOAST:
573 return TOAST_LAYER;
574 }
575 Log.e(TAG, "Unknown window type: " + type);
576 return APPLICATION_LAYER;
577 }
578
579 /** {@inheritDoc} */
580 public int subWindowTypeToLayerLw(int type) {
581 switch (type) {
582 case TYPE_APPLICATION_PANEL:
583 case TYPE_APPLICATION_ATTACHED_DIALOG:
584 return APPLICATION_PANEL_SUBLAYER;
585 case TYPE_APPLICATION_MEDIA:
586 return APPLICATION_MEDIA_SUBLAYER;
587 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>
710 * <li>SEARCH_BAR_TYPE</li>
711 * <li>KEYGUARD_TYPE</li>
712 * </ul>
713 *
714 * @param win The window to be added
715 * @param attrs Information about the window to be added
716 *
717 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
718 */
719 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
720 switch (attrs.type) {
721 case TYPE_STATUS_BAR:
722 if (mStatusBar != null) {
723 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
724 }
725 mStatusBar = win;
726 break;
727 case TYPE_SEARCH_BAR:
728 if (mSearchBar != null) {
729 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
730 }
731 mSearchBar = win;
732 break;
733 case TYPE_KEYGUARD:
734 if (mKeyguard != null) {
735 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
736 }
737 mKeyguard = win;
738 break;
739 }
740 return WindowManagerImpl.ADD_OKAY;
741 }
742
743 /** {@inheritDoc} */
744 public void removeWindowLw(WindowState win) {
745 if (mStatusBar == win) {
746 mStatusBar = null;
747 }
748 else if (mSearchBar == win) {
749 mSearchBar = null;
750 }
751 else if (mKeyguard == win) {
752 mKeyguard = null;
753 }
754 }
755
756 static final boolean PRINT_ANIM = false;
757
758 /** {@inheritDoc} */
759 public int selectAnimationLw(WindowState win, int transit) {
760 if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
761 + ": transit=" + transit);
762 if (transit == TRANSIT_PREVIEW_DONE) {
763 if (win.hasAppShownWindows()) {
764 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
765 return com.android.internal.R.anim.app_starting_exit;
766 }
767 }
768
769 return 0;
770 }
771
772 static ITelephony getPhoneInterface() {
773 return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
774 }
775
776 static IAudioService getAudioInterface() {
777 return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
778 }
779
780 boolean keyguardOn() {
781 return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode();
782 }
783
784 private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
785 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
786 WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
787 };
788
789 /** {@inheritDoc} */
790 public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
791 int repeatCount) {
792 boolean keyguardOn = keyguardOn();
793
794 if (false) {
795 Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
796 + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
797 }
798
799 // Clear a pending HOME longpress if the user releases Home
800 // TODO: This could probably be inside the next bit of logic, but that code
801 // turned out to be a bit fragile so I'm doing it here explicitly, for now.
802 if ((code == KeyEvent.KEYCODE_HOME) && !down) {
803 mHandler.removeCallbacks(mHomeLongPress);
804 }
805
806 // If the HOME button is currently being held, then we do special
807 // chording with it.
808 if (mHomePressed) {
809
810 // If we have released the home key, and didn't do anything else
811 // while it was pressed, then it is time to go home!
812 if (code == KeyEvent.KEYCODE_HOME) {
813 if (!down) {
814 mHomePressed = false;
815
816 // If an incoming call is ringing, HOME is totally disabled.
817 // (The user is already on the InCallScreen at this point,
818 // and his ONLY options are to answer or reject the call.)
819 boolean incomingRinging = false;
820 try {
821 ITelephony phoneServ = getPhoneInterface();
822 if (phoneServ != null) {
823 incomingRinging = phoneServ.isRinging();
824 } else {
825 Log.w(TAG, "Unable to find ITelephony interface");
826 }
827 } catch (RemoteException ex) {
828 Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
829 }
830
831 if (incomingRinging) {
832 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
833 } else {
834 launchHomeFromHotKey();
835 }
836 }
837 }
838
839 return true;
840 }
841
842 // First we always handle the home key here, so applications
843 // can never break it, although if keyguard is on, we do let
844 // it handle it, because that gives us the correct 5 second
845 // timeout.
846 if (code == KeyEvent.KEYCODE_HOME) {
847
848 // If a system window has focus, then it doesn't make sense
849 // right now to interact with applications.
850 WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
851 if (attrs != null) {
852 final int type = attrs.type;
853 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
854 || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
855 // the "app" is keyguard, so give it the key
856 return false;
857 }
858 final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
859 for (int i=0; i<typeCount; i++) {
860 if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
861 // don't do anything, but also don't pass it to the app
862 return true;
863 }
864 }
865 }
866
867 if (down && repeatCount == 0) {
868 if (!keyguardOn) {
869 mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
870 }
871 mHomePressed = true;
872 }
873 return true;
874 } else if (code == KeyEvent.KEYCODE_MENU) {
875 // Hijack modified menu keys for debugging features
876 final int chordBug = KeyEvent.META_SHIFT_ON;
877
878 if (down && repeatCount == 0) {
879 if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) {
880 Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
881 mContext.sendOrderedBroadcast(intent, null);
882 return true;
883 } else if (SHOW_PROCESSES_ON_ALT_MENU &&
884 (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
885 Intent service = new Intent();
886 service.setClassName(mContext, "com.android.server.LoadAverageService");
887 ContentResolver res = mContext.getContentResolver();
888 boolean shown = Settings.System.getInt(
889 res, Settings.System.SHOW_PROCESSES, 0) != 0;
890 if (!shown) {
891 mContext.startService(service);
892 } else {
893 mContext.stopService(service);
894 }
895 Settings.System.putInt(
896 res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
897 return true;
898 }
899 }
900 } else if (code == KeyEvent.KEYCODE_NOTIFICATION) {
901 if (down) {
902 // this key doesn't exist on current hardware, but if a device
903 // didn't have a touchscreen, it would want one of these to open
904 // the status bar.
905 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
906 if (sbs != null) {
907 try {
908 sbs.toggle();
909 } catch (RemoteException e) {
910 // we're screwed anyway, since it's in this process
911 throw new RuntimeException(e);
912 }
913 }
914 }
915 return true;
916 } else if (code == KeyEvent.KEYCODE_SEARCH) {
917 if (down) {
918 if (repeatCount == 0) {
919 mSearchKeyPressed = true;
920 }
921 } else {
922 mSearchKeyPressed = false;
923
924 if (mConsumeSearchKeyUp) {
925 // Consume the up-event
926 mConsumeSearchKeyUp = false;
927 return true;
928 }
929 }
930 }
931
932 // Shortcuts are invoked through Search+key, so intercept those here
933 if (mSearchKeyPressed) {
934 if (down && repeatCount == 0 && !keyguardOn) {
935 Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys);
936 if (shortcutIntent != null) {
937 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
938 mContext.startActivity(shortcutIntent);
939
940 /*
941 * We launched an app, so the up-event of the search key
942 * should be consumed
943 */
944 mConsumeSearchKeyUp = true;
945 return true;
946 }
947 }
948 }
949
950 return false;
951 }
952
953 /**
954 * A home key -> launch home action was detected. Take the appropriate action
955 * given the situation with the keyguard.
956 */
957 void launchHomeFromHotKey() {
958 if (mKeyguardMediator.isShowing()) {
959 // don't launch home if keyguard showing
960 } else if (mKeyguardMediator.isInputRestricted()) {
961 // when in keyguard restricted mode, must first verify unlock
962 // before launching home
963 mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
964 public void onKeyguardExitResult(boolean success) {
965 if (success) {
966 mContext.startActivity(mHomeIntent);
967 sendCloseSystemWindows();
968 }
969 }
970 });
971 } else {
972 // no keyguard stuff to worry about, just launch home!
973 mContext.startActivity(mHomeIntent);
974 sendCloseSystemWindows();
975 }
976 }
977
978 public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
979 final int fl = attrs.flags;
980
981 if ((fl &
982 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
983 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
984 contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom);
985 } else {
986 contentInset.setEmpty();
987 }
988 }
989
990 /** {@inheritDoc} */
991 public void beginLayoutLw(int displayWidth, int displayHeight) {
992 mW = displayWidth;
993 mH = displayHeight;
994 mDockLeft = mContentLeft = mCurLeft = 0;
995 mDockTop = mContentTop = mCurTop = 0;
996 mDockRight = mContentRight = mCurRight = displayWidth;
997 mDockBottom = mContentBottom = mCurBottom = displayHeight;
998 mDockLayer = 0x10000000;
999
1000 // decide where the status bar goes ahead of time
1001 if (mStatusBar != null) {
1002 final Rect pf = mTmpParentFrame;
1003 final Rect df = mTmpDisplayFrame;
1004 final Rect vf = mTmpVisibleFrame;
1005 pf.left = df.left = vf.left = 0;
1006 pf.top = df.top = vf.top = 0;
1007 pf.right = df.right = vf.right = displayWidth;
1008 pf.bottom = df.bottom = vf.bottom = displayHeight;
1009
1010 mStatusBar.computeFrameLw(pf, df, vf, vf);
1011 if (mStatusBar.isVisibleLw()) {
1012 // If the status bar is hidden, we don't want to cause
1013 // windows behind it to scroll.
1014 mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom;
1015 }
1016 }
1017 }
1018
1019 void setAttachedWindowFrames(WindowState win, int fl, int sim,
1020 WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
1021 if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
1022 // Here's a special case: if this attached window is a panel that is
1023 // above the dock window, and the window it is attached to is below
1024 // the dock window, then the frames we computed for the window it is
1025 // attached to can not be used because the dock is effectively part
1026 // of the underlying window and the attached window is floating on top
1027 // of the whole thing. So, we ignore the attached window and explicitly
1028 // compute the frames that would be appropriate without the dock.
1029 df.left = cf.left = vf.left = mDockLeft;
1030 df.top = cf.top = vf.top = mDockTop;
1031 df.right = cf.right = vf.right = mDockRight;
1032 df.bottom = cf.bottom = vf.bottom = mDockBottom;
1033 } else {
1034 // The effective display frame of the attached window depends on
1035 // whether it is taking care of insetting its content. If not,
1036 // we need to use the parent's content frame so that the entire
1037 // window is positioned within that content. Otherwise we can use
1038 // the display frame and let the attached window take care of
1039 // positioning its content appropriately.
1040 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1041 cf.set(attached.getDisplayFrameLw());
1042 } else {
1043 // If the window is resizing, then we want to base the content
1044 // frame on our attached content frame to resize... however,
1045 // things can be tricky if the attached window is NOT in resize
1046 // mode, in which case its content frame will be larger.
1047 // Ungh. So to deal with that, make sure the content frame
1048 // we end up using is not covering the IM dock.
1049 cf.set(attached.getContentFrameLw());
1050 if (attached.getSurfaceLayer() < mDockLayer) {
1051 if (cf.left < mContentLeft) cf.left = mContentLeft;
1052 if (cf.top < mContentTop) cf.top = mContentTop;
1053 if (cf.right > mContentRight) cf.right = mContentRight;
1054 if (cf.bottom > mContentBottom) cf.bottom = mContentBottom;
1055 }
1056 }
1057 df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
1058 vf.set(attached.getVisibleFrameLw());
1059 }
1060 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached
1061 // window should be positioned relative to its parent or the entire
1062 // screen.
1063 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0
1064 ? attached.getFrameLw() : df);
1065 }
1066
1067 /** {@inheritDoc} */
1068 public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) {
1069 // we've already done the status bar
1070 if (win == mStatusBar) {
1071 return;
1072 }
1073
1074 if (false) {
1075 if ("com.google.android.youtube".equals(attrs.packageName)
1076 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1077 Log.i(TAG, "GOTCHA!");
1078 }
1079 }
1080
1081 final int fl = attrs.flags;
1082 final int sim = attrs.softInputMode;
1083
1084 final Rect pf = mTmpParentFrame;
1085 final Rect df = mTmpDisplayFrame;
1086 final Rect cf = mTmpContentFrame;
1087 final Rect vf = mTmpVisibleFrame;
1088
1089 if (attrs.type == TYPE_INPUT_METHOD) {
1090 pf.left = df.left = cf.left = vf.left = mDockLeft;
1091 pf.top = df.top = cf.top = vf.top = mDockTop;
1092 pf.right = df.right = cf.right = vf.right = mDockRight;
1093 pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom;
1094 // IM dock windows always go to the bottom of the screen.
1095 attrs.gravity = Gravity.BOTTOM;
1096 mDockLayer = win.getSurfaceLayer();
1097 } else {
1098 if ((fl &
1099 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
1100 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
1101 // This is the case for a normal activity window: we want it
1102 // to cover all of the screen space, and it can take care of
1103 // moving its contents to account for screen decorations that
1104 // intrude into that space.
1105 if (attached != null) {
1106 // If this window is attached to another, our display
1107 // frame is the same as the one we are attached to.
1108 setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
1109 } else {
1110 pf.left = df.left = 0;
1111 pf.top = df.top = 0;
1112 pf.right = df.right = mW;
1113 pf.bottom = df.bottom = mH;
1114 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1115 cf.left = mDockLeft;
1116 cf.top = mDockTop;
1117 cf.right = mDockRight;
1118 cf.bottom = mDockBottom;
1119 } else {
1120 cf.left = mContentLeft;
1121 cf.top = mContentTop;
1122 cf.right = mContentRight;
1123 cf.bottom = mContentBottom;
1124 }
1125 vf.left = mCurLeft;
1126 vf.top = mCurTop;
1127 vf.right = mCurRight;
1128 vf.bottom = mCurBottom;
1129 }
1130 } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
1131 // A window that has requested to fill the entire screen just
1132 // gets everything, period.
1133 pf.left = df.left = cf.left = 0;
1134 pf.top = df.top = cf.top = 0;
1135 pf.right = df.right = cf.right = mW;
1136 pf.bottom = df.bottom = cf.bottom = mH;
1137 vf.left = mCurLeft;
1138 vf.top = mCurTop;
1139 vf.right = mCurRight;
1140 vf.bottom = mCurBottom;
1141 } else if (attached != null) {
1142 // A child window should be placed inside of the same visible
1143 // frame that its parent had.
1144 setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
1145 } else {
1146 // Otherwise, a normal window must be placed inside the content
1147 // of all screen decorations.
1148 pf.left = mContentLeft;
1149 pf.top = mContentTop;
1150 pf.right = mContentRight;
1151 pf.bottom = mContentBottom;
1152 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
1153 df.left = cf.left = mDockLeft;
1154 df.top = cf.top = mDockTop;
1155 df.right = cf.right = mDockRight;
1156 df.bottom = cf.bottom = mDockBottom;
1157 } else {
1158 df.left = cf.left = mContentLeft;
1159 df.top = cf.top = mContentTop;
1160 df.right = cf.right = mContentRight;
1161 df.bottom = cf.bottom = mContentBottom;
1162 }
1163 vf.left = mCurLeft;
1164 vf.top = mCurTop;
1165 vf.right = mCurRight;
1166 vf.bottom = mCurBottom;
1167 }
1168 }
1169
1170 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
1171 df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
1172 df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
1173 }
1174
1175 if (false) {
1176 if ("com.google.android.youtube".equals(attrs.packageName)
1177 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
1178 if (true || localLOGV) Log.v(TAG, "Computing frame of " + win +
1179 ": pf=" + pf.toShortString() + " df=" + df.toShortString()
1180 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
1181 }
1182 }
1183
1184 win.computeFrameLw(pf, df, cf, vf);
1185
1186 // Dock windows carve out the bottom of the screen, so normal windows
1187 // can't appear underneath them.
1188 if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
1189 int top = win.getContentFrameLw().top;
1190 top += win.getGivenContentInsetsLw().top;
1191 if (mContentBottom > top) {
1192 mContentBottom = top;
1193 }
1194 top = win.getVisibleFrameLw().top;
1195 top += win.getGivenVisibleInsetsLw().top;
1196 if (mCurBottom > top) {
1197 mCurBottom = top;
1198 }
1199 }
1200 }
1201
1202 /** {@inheritDoc} */
1203 public void finishLayoutLw() {
1204 }
1205
1206 /** {@inheritDoc} */
1207 public void beginAnimationLw(int displayWidth, int displayHeight) {
1208 mTopFullscreenOpaqueWindowState = null;
1209 mForceStatusBar = false;
1210 }
1211
1212 /** {@inheritDoc} */
1213 public void animatingWindowLw(WindowState win,
1214 WindowManager.LayoutParams attrs) {
1215 if (win.isVisibleLw()) {
1216 if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
1217 mForceStatusBar = true;
1218 } else if (mTopFullscreenOpaqueWindowState == null
1219 && attrs.type >= FIRST_APPLICATION_WINDOW
1220 && attrs.type <= LAST_APPLICATION_WINDOW
1221 && win.fillsScreenLw(mW, mH, true, false)
1222 && win.isVisibleLw()) {
1223 mTopFullscreenOpaqueWindowState = win;
1224 }
1225 }
1226 }
1227
1228 /** {@inheritDoc} */
1229 public boolean finishAnimationLw() {
1230 boolean changed = false;
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001231 boolean hiding = false;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001232 if (mStatusBar != null) {
1233 //Log.i(TAG, "force=" + mForceStatusBar
1234 // + " top=" + mTopFullscreenOpaqueWindowState);
1235 if (mForceStatusBar) {
1236 changed |= mStatusBar.showLw(true);
1237 } else if (mTopFullscreenOpaqueWindowState != null) {
1238 //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
1239 // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
1240 //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs());
1241 WindowManager.LayoutParams lp =
1242 mTopFullscreenOpaqueWindowState.getAttrs();
1243 boolean hideStatusBar =
1244 (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
1245 if (hideStatusBar) {
1246 changed |= mStatusBar.hideLw(true);
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001247 hiding = true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001248 } else {
1249 changed |= mStatusBar.showLw(true);
1250 }
1251 }
1252 }
The Android Open Source Projectc84bf282009-03-09 11:52:14 -07001253
1254 if (changed && hiding) {
1255 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
1256 if (sbs != null) {
1257 try {
1258 // Make sure the window shade is hidden.
1259 sbs.deactivate();
1260 } catch (RemoteException e) {
1261 }
1262 }
1263 }
1264
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001265 return changed;
1266 }
1267
1268 /** {@inheritDoc} */
1269 public boolean preprocessInputEventTq(RawInputEvent event) {
1270 switch (event.type) {
1271 case RawInputEvent.EV_SW:
1272 if (event.keycode == 0) {
1273 // lid changed state
1274 mLidOpen = event.value == 0;
1275 updateRotation();
1276 if (keyguardIsShowingTq()) {
1277 if (mLidOpen) {
1278 // only do this if it's opening -- closing the device shouldn't turn it
1279 // off, but it also shouldn't turn it on.
1280 mKeyguardMediator.pokeWakelock();
1281 }
1282 } else {
1283 // Light up the keyboard if we are sliding up.
1284 if (mLidOpen) {
1285 mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1286 LocalPowerManager.BUTTON_EVENT);
1287 } else {
1288 mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
1289 LocalPowerManager.OTHER_EVENT);
1290 }
1291 }
1292 }
1293 }
1294 return false;
1295 }
1296
1297
1298 /** {@inheritDoc} */
1299 public boolean isAppSwitchKeyTqTiLwLi(int keycode) {
1300 return keycode == KeyEvent.KEYCODE_HOME
1301 || keycode == KeyEvent.KEYCODE_ENDCALL;
1302 }
1303
1304 /** {@inheritDoc} */
1305 public boolean isMovementKeyTi(int keycode) {
1306 switch (keycode) {
1307 case KeyEvent.KEYCODE_DPAD_UP:
1308 case KeyEvent.KEYCODE_DPAD_DOWN:
1309 case KeyEvent.KEYCODE_DPAD_LEFT:
1310 case KeyEvent.KEYCODE_DPAD_RIGHT:
1311 return true;
1312 }
1313 return false;
1314 }
1315
1316
1317 /**
1318 * @return Whether a telephone call is in progress right now.
1319 */
1320 boolean isInCall() {
1321 final ITelephony phone = getPhoneInterface();
1322 if (phone == null) {
1323 Log.w(TAG, "couldn't get ITelephony reference");
1324 return false;
1325 }
1326 try {
1327 return phone.isOffhook();
1328 } catch (RemoteException e) {
1329 Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
1330 return false;
1331 }
1332 }
1333
1334 /**
1335 * @return Whether music is being played right now.
1336 */
1337 boolean isMusicActive() {
1338 final IAudioService audio = getAudioInterface();
1339 if (audio == null) {
1340 Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
1341 return false;
1342 }
1343 try {
1344 return audio.isMusicActive();
1345 } catch (RemoteException e) {
1346 Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
1347 return false;
1348 }
1349 }
1350
1351 /**
1352 * Tell the audio service to adjust the volume appropriate to the event.
1353 * @param keycode
1354 */
1355 void sendVolToMusic(int keycode) {
1356 final IAudioService audio = getAudioInterface();
1357 if (audio == null) {
1358 Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
1359 return;
1360 }
1361 try {
1362 // since audio is playing, we shouldn't have to hold a wake lock
1363 // during the call, but we do it as a precaution for the rare possibility
1364 // that the music stops right before we call this
1365 mBroadcastWakeLock.acquire();
1366 audio.adjustStreamVolume(
1367 AudioManager.STREAM_MUSIC,
1368 keycode == KeyEvent.KEYCODE_VOLUME_UP
1369 ? AudioManager.ADJUST_RAISE
1370 : AudioManager.ADJUST_LOWER,
1371 0);
1372 } catch (RemoteException e) {
1373 Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
1374 } finally {
1375 mBroadcastWakeLock.release();
1376 }
1377 }
1378
1379 static boolean isMediaKey(int code) {
1380 if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
1381 code == KeyEvent.KEYCODE_PLAYPAUSE ||
1382 code == KeyEvent.KEYCODE_STOP ||
1383 code == KeyEvent.KEYCODE_NEXTSONG ||
1384 code == KeyEvent.KEYCODE_PREVIOUSSONG ||
1385 code == KeyEvent.KEYCODE_PREVIOUSSONG ||
1386 code == KeyEvent.KEYCODE_FORWARD) {
1387 return true;
1388 }
1389 return false;
1390 }
1391
1392 /** {@inheritDoc} */
1393 public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
1394 int result = ACTION_PASS_TO_USER;
1395 final boolean isWakeKey = isWakeKeyTq(event);
1396 final boolean keyguardShowing = keyguardIsShowingTq();
1397
1398 if (false) {
1399 Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
1400 + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing);
1401 }
1402
1403 if (keyguardShowing) {
1404 if (screenIsOn) {
1405 // when the screen is on, always give the event to the keyguard
1406 result |= ACTION_PASS_TO_USER;
1407 } else {
1408 // otherwise, don't pass it to the user
1409 result &= ~ACTION_PASS_TO_USER;
1410
1411 final boolean isKeyDown =
1412 (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
1413 if (isWakeKey && isKeyDown) {
1414
1415 // tell the mediator about a wake key, it may decide to
1416 // turn on the screen depending on whether the key is
1417 // appropriate.
1418 if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
1419 && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
1420 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
1421 if (isInCall()) {
1422 // if the keyguard didn't wake the device, we are in call, and
1423 // it is a volume key, turn on the screen so that the user
1424 // can more easily adjust the in call volume.
1425 mKeyguardMediator.pokeWakelock();
1426 } else if (isMusicActive()) {
1427 // when keyguard is showing and screen off, we need
1428 // to handle the volume key for music here
1429 sendVolToMusic(event.keycode);
1430 }
1431 }
1432 }
1433 }
1434 } else if (!screenIsOn) {
1435 if (isWakeKey) {
1436 // a wake key has a sole purpose of waking the device; don't pass
1437 // it to the user
1438 result |= ACTION_POKE_USER_ACTIVITY;
1439 result &= ~ACTION_PASS_TO_USER;
1440 }
1441 }
1442
1443 int type = event.type;
1444 int code = event.keycode;
1445 boolean down = event.value != 0;
1446
1447 if (type == RawInputEvent.EV_KEY) {
1448 if (code == KeyEvent.KEYCODE_ENDCALL) {
1449 if (down) {
1450 boolean hungUp = false;
1451 // key repeats are generated by the window manager, and we don't see them
1452 // here, so unless the driver is doing something it shouldn't be, we know
1453 // this is the real press event.
1454 try {
1455 ITelephony phoneServ = getPhoneInterface();
1456 if (phoneServ != null) {
1457 hungUp = phoneServ.endCall();
1458 } else {
1459 Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
1460 }
1461 } catch (RemoteException ex) {
1462 Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
1463 }
1464 if (hungUp || !screenIsOn) {
1465 mShouldTurnOffOnKeyUp = false;
1466 } else {
1467 // only try to turn off the screen if we didn't already hang up
1468 mShouldTurnOffOnKeyUp = true;
1469 mHandler.postDelayed(mEndCallLongPress,
1470 ViewConfiguration.getGlobalActionKeyTimeout());
1471 result &= ~ACTION_PASS_TO_USER;
1472 }
1473 } else {
1474 mHandler.removeCallbacks(mEndCallLongPress);
1475 if (mShouldTurnOffOnKeyUp) {
1476 mShouldTurnOffOnKeyUp = false;
1477 boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0;
1478 boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0;
1479 if (keyguardShowing
1480 || (sleeps && !gohome)
1481 || (gohome && !goHome() && sleeps)) {
1482 // they must already be on the keyguad or home screen,
1483 // go to sleep instead
1484 Log.d(TAG, "I'm tired mEndcallBehavior=0x"
1485 + Integer.toHexString(mEndcallBehavior));
1486 result &= ~ACTION_POKE_USER_ACTIVITY;
1487 result |= ACTION_GO_TO_SLEEP;
1488 }
1489 result &= ~ACTION_PASS_TO_USER;
1490 }
1491 }
1492 } else if (isMediaKey(code)) {
1493 // This key needs to be handled even if the screen is off.
1494 // If others need to be handled while it's off, this is a reasonable
1495 // pattern to follow.
1496 if ((result & ACTION_PASS_TO_USER) == 0) {
1497 // Only do this if we would otherwise not pass it to the user. In that
1498 // case, the PhoneWindow class will do the same thing, except it will
1499 // only do it if the showing app doesn't process the key on its own.
1500 KeyEvent keyEvent = new KeyEvent(event.when, event.when,
1501 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
1502 code, 0);
1503 mBroadcastWakeLock.acquire();
1504 mHandler.post(new PassHeadsetKey(keyEvent));
1505 }
1506 } else if (code == KeyEvent.KEYCODE_CALL) {
1507 // If an incoming call is ringing, answer it!
1508 // (We handle this key here, rather than in the InCallScreen, to make
1509 // sure we'll respond to the key even if the InCallScreen hasn't come to
1510 // the foreground yet.)
1511
1512 // We answer the call on the DOWN event, to agree with
1513 // the "fallback" behavior in the InCallScreen.
1514 if (down) {
1515 try {
1516 ITelephony phoneServ = getPhoneInterface();
1517 if (phoneServ != null) {
1518 if (phoneServ.isRinging()) {
1519 Log.i(TAG, "interceptKeyTq:"
1520 + " CALL key-down while ringing: Answer the call!");
1521 phoneServ.answerRingingCall();
1522
1523 // And *don't* pass this key thru to the current activity
1524 // (which is presumably the InCallScreen.)
1525 result &= ~ACTION_PASS_TO_USER;
1526 }
1527 } else {
1528 Log.w(TAG, "CALL button: Unable to find ITelephony interface");
1529 }
1530 } catch (RemoteException ex) {
1531 Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
1532 }
1533 }
1534 } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
1535 || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
1536 // If an incoming call is ringing, either VOLUME key means
1537 // "silence ringer". We handle these keys here, rather than
1538 // in the InCallScreen, to make sure we'll respond to them
1539 // even if the InCallScreen hasn't come to the foreground yet.
1540
1541 // Look for the DOWN event here, to agree with the "fallback"
1542 // behavior in the InCallScreen.
1543 if (down) {
1544 try {
1545 ITelephony phoneServ = getPhoneInterface();
1546 if (phoneServ != null) {
1547 if (phoneServ.isRinging()) {
1548 Log.i(TAG, "interceptKeyTq:"
1549 + " VOLUME key-down while ringing: Silence ringer!");
1550 // Silence the ringer. (It's safe to call this
1551 // even if the ringer has already been silenced.)
1552 phoneServ.silenceRinger();
1553
1554 // And *don't* pass this key thru to the current activity
1555 // (which is probably the InCallScreen.)
1556 result &= ~ACTION_PASS_TO_USER;
1557 }
1558 } else {
1559 Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
1560 }
1561 } catch (RemoteException ex) {
1562 Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
1563 }
1564 }
1565 }
1566 }
1567
1568 return result;
1569 }
1570
1571 class PassHeadsetKey implements Runnable {
1572 KeyEvent mKeyEvent;
1573
1574 PassHeadsetKey(KeyEvent keyEvent) {
1575 mKeyEvent = keyEvent;
1576 }
1577
1578 public void run() {
1579 if (ActivityManagerNative.isSystemReady()) {
1580 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
1581 intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent);
1582 mContext.sendOrderedBroadcast(intent, null, mBroadcastDone,
1583 mHandler, Activity.RESULT_OK, null, null);
1584 }
1585 }
1586 }
1587
1588 BroadcastReceiver mBroadcastDone = new BroadcastReceiver() {
1589 public void onReceive(Context context, Intent intent) {
1590 mBroadcastWakeLock.release();
1591 }
1592 };
1593
1594 /** {@inheritDoc} */
1595 public boolean isWakeRelMovementTq(int device, int classes,
1596 RawInputEvent event) {
1597 // if it's tagged with one of the wake bits, it wakes up the device
1598 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
1599 }
1600
1601 /** {@inheritDoc} */
1602 public boolean isWakeAbsMovementTq(int device, int classes,
1603 RawInputEvent event) {
1604 // if it's tagged with one of the wake bits, it wakes up the device
1605 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0);
1606 }
1607
1608 /**
1609 * Given the current state of the world, should this key wake up the device?
1610 */
1611 protected boolean isWakeKeyTq(RawInputEvent event) {
1612 // There are not key maps for trackball devices, but we'd still
1613 // like to have pressing it wake the device up, so force it here.
1614 int keycode = event.keycode;
1615 int flags = event.flags;
1616 if (keycode == RawInputEvent.BTN_MOUSE) {
1617 flags |= WindowManagerPolicy.FLAG_WAKE;
1618 }
1619 return (flags
1620 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
1621 }
1622
1623 /** {@inheritDoc} */
1624 public void screenTurnedOff(int why) {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001625 synchronized (mLock) {
1626 EventLog.writeEvent(70000, 0);
1627 mKeyguardMediator.onScreenTurnedOff(why);
1628 mScreenOn = false;
1629 updateOrientationListenerLp();
1630 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001631 }
1632
1633 /** {@inheritDoc} */
1634 public void screenTurnedOn() {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001635 synchronized (mLock) {
1636 EventLog.writeEvent(70000, 1);
1637 mKeyguardMediator.onScreenTurnedOn();
1638 mScreenOn = true;
1639 updateOrientationListenerLp();
1640 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001641 }
1642
1643 /** {@inheritDoc} */
1644 public void enableKeyguard(boolean enabled) {
1645 mKeyguardMediator.setKeyguardEnabled(enabled);
1646 }
1647
1648 /** {@inheritDoc} */
1649 public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
1650 mKeyguardMediator.verifyUnlock(callback);
1651 }
1652
1653 /** {@inheritDoc} */
1654 public boolean keyguardIsShowingTq() {
1655 return mKeyguardMediator.isShowing();
1656 }
1657
1658 /** {@inheritDoc} */
1659 public boolean inKeyguardRestrictedKeyInputMode() {
1660 return mKeyguardMediator.isInputRestricted();
1661 }
1662
1663 /**
1664 * Callback from {@link KeyguardViewMediator}
1665 */
1666 public void onKeyguardShow() {
1667 sendCloseSystemWindows();
1668 }
1669
1670 void sendCloseSystemWindows() {
1671 sendCloseSystemWindows(mContext, null);
1672 }
1673
1674 void sendCloseSystemWindows(String reason) {
1675 sendCloseSystemWindows(mContext, reason);
1676 }
1677
1678 static void sendCloseSystemWindows(Context context, String reason) {
1679 if (ActivityManagerNative.isSystemReady()) {
1680 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1681 if (reason != null) {
1682 intent.putExtra(SYSTEM_DIALOG_REASON_KEY, reason);
1683 }
1684 context.sendBroadcast(intent);
1685 }
1686 }
1687
The Android Open Source Project0727d222009-03-11 12:11:58 -07001688 public int rotationForOrientationLw(int orientation, int lastRotation,
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001689 boolean displayEnabled) {
The Android Open Source Project0727d222009-03-11 12:11:58 -07001690 synchronized (mLock) {
1691 switch (orientation) {
1692 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
1693 //always return landscape if orientation set to landscape
1694 return Surface.ROTATION_90;
1695 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
1696 //always return portrait if orientation set to portrait
1697 return Surface.ROTATION_0;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001698 }
The Android Open Source Project0727d222009-03-11 12:11:58 -07001699 // case for nosensor meaning ignore sensor and consider only lid
1700 // or orientation sensor disabled
1701 //or case.unspecified
1702 if (mLidOpen) {
1703 return Surface.ROTATION_90;
1704 } else {
1705 if (useSensorForOrientationLp()) {
1706 // If the user has enabled auto rotation by default, do it.
1707 return mSensorRotation >= 0 ? mSensorRotation : lastRotation;
1708 }
1709 return Surface.ROTATION_0;
1710 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001711 }
1712 }
1713
1714 public boolean detectSafeMode() {
1715 try {
1716 int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
1717 mSafeMode = menuState > 0;
1718 Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
1719 return mSafeMode;
1720 } catch (RemoteException e) {
1721 // Doom! (it's also local)
1722 throw new RuntimeException("window manager dead");
1723 }
1724 }
1725
1726 /** {@inheritDoc} */
1727 public void systemReady() {
1728 try {
1729 if (mSafeMode) {
1730 // If the user is holding the menu key code, then we are
1731 // going to boot into safe mode.
1732 ActivityManagerNative.getDefault().enterSafeMode();
1733 }
1734 // tell the keyguard
1735 mKeyguardMediator.onSystemReady();
1736 android.os.SystemProperties.set("dev.bootcomplete", "1");
The Android Open Source Project0727d222009-03-11 12:11:58 -07001737 synchronized (mLock) {
1738 updateOrientationListenerLp();
1739 mVibrator = new Vibrator();
1740 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001741 } catch (RemoteException e) {
1742 // Ignore
1743 }
1744 }
1745
1746
1747 /** {@inheritDoc} */
1748 public void enableScreenAfterBoot() {
1749 readLidState();
1750 updateRotation();
1751 }
1752
1753 void updateRotation() {
1754 mPowerManager.setKeyboardVisibility(mLidOpen);
1755 int rotation= Surface.ROTATION_0;
1756 if (mLidOpen) {
1757 // always use landscape if lid is open
1758 rotation = Surface.ROTATION_90;
1759 }
1760 //if lid is closed orientation will be portrait
1761 try {
1762 //set orientation on WindowManager
1763 mWindowManager.setRotation(rotation, true);
1764 } catch (RemoteException e) {
1765 // Ignore
1766 }
1767 }
1768
1769 /**
1770 * goes to the home screen
1771 * @return whether it did anything
1772 */
1773 boolean goHome() {
1774 if (false) {
1775 // This code always brings home to the front.
1776 mContext.startActivity(mHomeIntent);
1777 } else {
1778 // This code brings home to the front or, if it is already
1779 // at the front, puts the device to sleep.
1780 try {
1781 int result = ActivityManagerNative.getDefault()
1782 .startActivity(null, mHomeIntent,
1783 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
1784 null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
1785 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
1786 return false;
1787 }
1788 } catch (RemoteException ex) {
1789 // bummer, the activity manager, which is in this process, is dead
1790 }
1791 }
1792 sendCloseSystemWindows();
1793 return true;
1794 }
1795
The Android Open Source Project0727d222009-03-11 12:11:58 -07001796 public void setCurrentOrientationLw(int newOrientation) {
1797 synchronized (mLock) {
1798 if (newOrientation != mCurrentAppOrientation) {
1799 mCurrentAppOrientation = newOrientation;
1800 updateOrientationListenerLp();
1801 }
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001802 }
1803 }
1804
The Android Open Source Project0727d222009-03-11 12:11:58 -07001805 public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001806 if (!always && Settings.System.getInt(mContext.getContentResolver(),
1807 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
1808 return false;
1809 }
1810 switch (effectId) {
1811 case HapticFeedbackConstants.LONG_PRESS:
1812 mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1);
1813 return true;
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001814 }
1815 return false;
1816 }
1817
The Android Open Source Project0727d222009-03-11 12:11:58 -07001818 public void screenOnStoppedLw() {
The Android Open Source Project1f838aa2009-03-03 19:32:13 -08001819 if (!mKeyguardMediator.isShowing()) {
1820 long curTime = SystemClock.uptimeMillis();
1821 mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
1822 }
1823 }
1824}