diff --git a/policy/Android.mk b/policy/Android.mk index 462431f905fbb..29f62b8723067 100644 --- a/policy/Android.mk +++ b/policy/Android.mk @@ -7,6 +7,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ $(call all-subdir-java-files) -LOCAL_MODULE:= android.policy +LOCAL_MODULE := android.policy_phone +LOCAL_UNINSTALLABLE_MODULE := true include $(BUILD_JAVA_LIBRARY) diff --git a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java index 832288b1a04cf..b46b37d04db0c 100644 --- a/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java +++ b/policy/com/android/internal/policy/impl/KeyguardScreenCallback.java @@ -58,4 +58,9 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback { */ void reportFailedPatternAttempt(); + /** + * Report whether we there's another way to unlock the device. + * @return true + */ + boolean doesFallbackUnlockScreenExist(); } diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java index ab7c744c73633..4671957592cca 100644 --- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java +++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java @@ -160,8 +160,8 @@ public class KeyguardUpdateMonitor { } }; - mDeviceProvisioned = Settings.System.getInt( - mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... @@ -170,8 +170,8 @@ public class KeyguardUpdateMonitor { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); - mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; if (mDeviceProvisioned && mContentObserver != null) { // We don't need the observer anymore... mContext.getContentResolver().unregisterContentObserver(mContentObserver); @@ -182,13 +182,13 @@ public class KeyguardUpdateMonitor { }; mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.DEVICE_PROVISIONED), + Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), false, mContentObserver); // prevent a race condition between where we check the flag and where we register the // observer by grabbing the value once again... - mDeviceProvisioned = Settings.System.getInt(mContext.getContentResolver(), - Settings.System.DEVICE_PROVISIONED, 0) != 0; + mDeviceProvisioned = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } mInPortrait = queryInPortrait(); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/com/android/internal/policy/impl/KeyguardViewBase.java index 491300ea11e83..5a3ebdee1be49 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewBase.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewBase.java @@ -131,7 +131,13 @@ public abstract class KeyguardViewBase extends FrameLayout { final int keyCode = event.getKeyCode(); if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -161,7 +167,13 @@ public abstract class KeyguardViewBase extends FrameLayout { } } else if (event.getAction() == KeyEvent.ACTION_UP) { switch (keyCode) { - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); diff --git a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java index ac816b0bd60e9..2431ffe8075da 100644 --- a/policy/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -131,6 +131,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private Context mContext; private AlarmManager mAlarmManager; + private boolean mSystemReady; + /** Low level access to the power manager for enableUserActivity. Having this * requires that we run in the system process. */ LocalPowerManager mRealPowerManager; @@ -254,6 +256,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, public void onSystemReady() { synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); + mSystemReady = true; doKeyguard(); } } @@ -638,7 +641,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback, switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: case KeyEvent.KEYCODE_CAMERA: return false; } @@ -806,6 +815,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback, private void handleShow() { synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleShow"); + if (!mSystemReady) return; + // while we're showing, we control the wake state, so ask the power // manager not to honor request for userActivity. mRealPowerManager.enableUserActivity(false); @@ -875,6 +886,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback, synchronized (KeyguardViewMediator.this) { if (DEBUG) Log.d(TAG, "handleVerifyUnlock"); mKeyguardViewManager.verifyUnlock(); + mShowing = true; } } diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java index 66a4c4e7813a2..4ff87e3a196c7 100644 --- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java +++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java @@ -16,9 +16,15 @@ package com.android.internal.policy.impl; +import android.accounts.AccountsServiceConstants; +import android.accounts.IAccountsService; import android.app.AlertDialog; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; import android.os.SystemProperties; import com.android.internal.telephony.SimCard; import android.text.TextUtils; @@ -51,6 +57,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase { private View mUnlockScreen; private boolean mScreenOn = false; + private boolean mHasAccount = false; // assume they don't have an account until we know better + /** * The current {@link KeyguardScreen} will use this to communicate back to us. @@ -114,6 +122,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { */ private final LockPatternUtils mLockPatternUtils; + /** + * Used to fetch accounts from GLS. + */ + private ServiceConnection mServiceConnection; /** * @return Whether we are stuck on the lock screen because the sim is @@ -137,7 +149,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase { KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils) { super(context); - + + asyncCheckForAccount(); + mRequiresSim = TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim")); @@ -145,6 +159,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase { mLockPatternUtils = lockPatternUtils; mMode = getInitialMode(); + mKeyguardScreenCallback = new KeyguardScreenCallback() { public void goToLockScreen() { @@ -210,10 +225,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase { public void reportFailedPatternAttempt() { mUpdateMonitor.reportFailedAttempt(); final int failedAttempts = mUpdateMonitor.getFailedAttempts(); - if (failedAttempts == - (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { + if (mHasAccount && failedAttempts == + (LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET + - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) { showAlmostAtAccountLoginDialog(); - } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { + } else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) { mLockPatternUtils.setPermanentlyLocked(true); updateScreen(mMode); } else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) @@ -221,6 +237,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase { showTimeoutDialog(); } } + + public boolean doesFallbackUnlockScreenExist() { + return mHasAccount; + } }; /** @@ -241,6 +261,36 @@ public class LockPatternKeyguardView extends KeyguardViewBase { updateScreen(mMode); } + /** + * Asynchronously checks for at least one account. This will set mHasAccount + * to true if an account is found. + */ + private void asyncCheckForAccount() { + + mServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + try { + IAccountsService accountsService = IAccountsService.Stub.asInterface(service); + String accounts[] = accountsService.getAccounts(); + mHasAccount = (accounts.length > 0); + } catch (RemoteException e) { + // Not much we can do here... + Log.e(TAG, "Gls died while attempting to get accounts: " + e); + } finally { + getContext().unbindService(mServiceConnection); + mServiceConnection = null; + } + } + + public void onServiceDisconnected(ComponentName className) { + // nothing to do here + } + }; + boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT, + mServiceConnection, Context.BIND_AUTO_CREATE); + if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account"); + } + @Override public void reset() { mIsVerifyUnlockOnly = false; diff --git a/policy/com/android/internal/policy/impl/LockScreen.java b/policy/com/android/internal/policy/impl/LockScreen.java index c717cc37ae158..0825c3bde2ee3 100644 --- a/policy/com/android/internal/policy/impl/LockScreen.java +++ b/policy/com/android/internal/policy/impl/LockScreen.java @@ -20,7 +20,7 @@ import com.android.internal.R; import com.android.internal.widget.LockPatternUtils; import android.content.Context; -import android.pim.DateFormat; +import android.text.format.DateFormat; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -299,7 +299,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM mHeaderSimOk1.setVisibility(View.VISIBLE); mHeaderSimOk1.setText(plmn); } else { - mHeaderSimOk2.setVisibility(View.GONE); + mHeaderSimOk1.setVisibility(View.GONE); } if (spn != null) { diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java index 2d5bd31aedd2e..dfc4b6c940be9 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/com/android/internal/policy/impl/PhoneWindow.java @@ -41,7 +41,6 @@ import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.provider.CallLog.Calls; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.EventLog; @@ -66,6 +65,7 @@ import android.view.WindowManager; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_RESTORED_STATE; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; @@ -482,7 +482,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WRAP_CONTENT, WRAP_CONTENT, st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, - WindowManager.LayoutParams.FLAG_DITHER, + WindowManager.LayoutParams.FLAG_DITHER + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, st.decorView.mDefaultOpacity); lp.gravity = st.gravity; @@ -493,7 +494,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void closePanel(int featureId) { - closePanel(getPanelState(featureId, true), true); + if (featureId == FEATURE_CONTEXT_MENU) { + closeContextMenu(); + } else { + closePanel(getPanelState(featureId, true), true); + } } /** @@ -628,8 +633,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { closeContextMenu(); } - + + /** + * Closes the context menu. This notifies the menu logic of the close, along + * with dismissing it from the UI. + */ private synchronized void closeContextMenu() { + if (mContextMenu != null) { + mContextMenu.close(); + dismissContextMenu(); + } + } + + /** + * Dismisses just the context menu UI. To close the context menu, use + * {@link #closeContextMenu()}. + */ + private synchronized void dismissContextMenu() { mContextMenu = null; if (mContextMenuHelper != null) { @@ -1117,7 +1137,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1226,7 +1252,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - case KeyEvent.KEYCODE_HEADSETHOOK: { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_PLAYPAUSE: + case KeyEvent.KEYCODE_STOP: + case KeyEvent.KEYCODE_NEXTSONG: + case KeyEvent.KEYCODE_PREVIOUSSONG: + case KeyEvent.KEYCODE_REWIND: + case KeyEvent.KEYCODE_FORWARD: { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); intent.putExtra(Intent.EXTRA_KEY_EVENT, event); getContext().sendOrderedBroadcast(intent, null); @@ -1344,6 +1376,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } + setFlags(FLAG_RESTORED_STATE, FLAG_RESTORED_STATE); + SparseArray savedStates = savedInstanceState.getSparseParcelableArray(VIEWS_TAG); if (savedStates != null) { @@ -1503,7 +1537,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * If not handled, then pass it to the view hierarchy * and anyone else that may be interested. */ - handled = dispatchKeyShortcut(event); + handled = dispatchKeyShortcutEvent(event); if (handled && mPreparedPanel != null) { mPreparedPanel.isHandled = true; @@ -1534,11 +1568,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { : PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event); } - private boolean dispatchKeyShortcut(KeyEvent event) { - View focusedView = findFocus(); - return focusedView == null ? false : focusedView.dispatchKeyShortcutEvent(event); - } - @Override public boolean dispatchTouchEvent(MotionEvent ev) { final Callback cb = getCallback(); @@ -1884,7 +1913,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { protected ViewGroup generateLayout(DecorView decor) { // Apply data from current theme. - final Context c = getContext(); TypedArray a = getWindowStyle(); if (false) { @@ -1903,19 +1931,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mIsFloating) { setLayout(WRAP_CONTENT, WRAP_CONTENT); setFlags(0, flagsToUpdate); - - /* All dialogs should have the window dimmed */ - WindowManager.LayoutParams params = getAttributes(); - TypedArray attrs = c.obtainStyledAttributes( - com.android.internal.R.styleable.Theme); - params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; - params.dimAmount = attrs.getFloat( - android.R.styleable.Theme_backgroundDimAmount, 0.5f); - attrs.recycle(); } else { setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate); } - + if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) { requestFeature(FEATURE_NO_TITLE); } @@ -1924,6 +1943,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags())); } + WindowManager.LayoutParams params = getAttributes(); + + if (!hasSoftInputMode()) { + params.softInputMode = (byte)a.getInt( + com.android.internal.R.styleable.Window_windowSoftInputMode, + params.softInputMode); + } + + if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled, + mIsFloating)) { + /* All dialogs should have the window dimmed */ + if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) { + params.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND; + } + params.dimAmount = a.getFloat( + android.R.styleable.Window_backgroundDimAmount, 0.5f); + } + + params.windowAnimations = a.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, + params.windowAnimations); + // The rest are only done if this window is not embedded; otherwise, // the values are inherited from our container. if (getContainer() == null) { @@ -2529,6 +2570,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ private final class ContextMenuCallback implements MenuBuilder.Callback { private int mFeatureId; + private MenuDialogHelper mSubMenuHelper; public ContextMenuCallback(int featureId) { mFeatureId = featureId; @@ -2540,7 +2582,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (callback != null) callback.onPanelClosed(mFeatureId, menu); if (menu == mContextMenu) { - closeContextMenu(); + dismissContextMenu(); + } + + // Dismiss the submenu, if it is showing + if (mSubMenuHelper != null) { + mSubMenuHelper.dismiss(); + mSubMenuHelper = null; } } } @@ -2553,7 +2601,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { Callback callback = getCallback(); return (callback != null) && callback.onMenuItemSelected(mFeatureId, item); - } public void onMenuModeChange(MenuBuilder menu) { @@ -2564,7 +2611,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { subMenu.setCallback(this); // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); + mSubMenuHelper = new MenuDialogHelper(subMenu); + mSubMenuHelper.show(null); return true; } diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java index 17312062960e0..603b2216e4183 100644 --- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java @@ -23,14 +23,13 @@ import android.app.IStatusBar; import android.content.BroadcastReceiver; import android.content.ContentQueryMap; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.Cursor; +import android.database.ContentObserver; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -41,13 +40,13 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; -import static android.provider.Settings.System.END_BUTTON_BEHAVIOR; import com.android.internal.policy.PolicyManager; import com.android.internal.telephony.ITelephony; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.view.Gravity; import android.view.IWindowManager; import android.view.KeyEvent; import android.view.MotionEvent; @@ -64,10 +63,13 @@ import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_PHONE; @@ -77,6 +79,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import android.view.WindowManagerImpl; @@ -91,117 +95,159 @@ import java.util.Observer; * WindowManagerPolicy implementation for the Android phone UI. */ public class PhoneWindowManager implements WindowManagerPolicy { - private static final String TAG = "WindowManager"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; - private static final boolean SHOW_STARTING_ANIMATIONS = true; - private static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; + static final String TAG = "WindowManager"; + static final boolean DEBUG = false; + static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + static final boolean SHOW_STARTING_ANIMATIONS = true; + static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; - private static final int APPLICATION_LAYER = 1; - private static final int PHONE_LAYER = 2; - private static final int SEARCH_BAR_LAYER = 3; - private static final int STATUS_BAR_PANEL_LAYER = 4; + static final int APPLICATION_LAYER = 1; + static final int PHONE_LAYER = 2; + static final int SEARCH_BAR_LAYER = 3; + static final int STATUS_BAR_PANEL_LAYER = 4; // toasts and the plugged-in battery thing - private static final int TOAST_LAYER = 5; - private static final int STATUS_BAR_LAYER = 6; + static final int TOAST_LAYER = 5; + static final int STATUS_BAR_LAYER = 6; // SIM errors and unlock. Not sure if this really should be in a high layer. - private static final int PRIORITY_PHONE_LAYER = 7; + static final int PRIORITY_PHONE_LAYER = 7; // like the ANR / app crashed dialogs - private static final int SYSTEM_ALERT_LAYER = 8; + static final int SYSTEM_ALERT_LAYER = 8; // system-level error dialogs - private static final int SYSTEM_ERROR_LAYER = 9; + static final int SYSTEM_ERROR_LAYER = 9; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_LAYER = 10; + // on-screen keyboards and other such input method user interfaces go here. + static final int INPUT_METHOD_DIALOG_LAYER = 11; // the keyguard; nothing on top of these can take focus, since they are // responsible for power management when displayed. - private static final int KEYGUARD_LAYER = 10; - private static final int KEYGUARD_DIALOG_LAYER = 11; + static final int KEYGUARD_LAYER = 12; + static final int KEYGUARD_DIALOG_LAYER = 13; // things in here CAN NOT take focus, but are shown on top of everything else. - private static final int SYSTEM_OVERLAY_LAYER = 12; + static final int SYSTEM_OVERLAY_LAYER = 14; - private static final int APPLICATION_PANEL_SUBLAYER = 1; - private static final int APPLICATION_MEDIA_SUBLAYER = -1; - private static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; + static final int APPLICATION_PANEL_SUBLAYER = 1; + static final int APPLICATION_MEDIA_SUBLAYER = -1; + static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; - private static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; + + // Debugging: set this to have the system act like there is no hard keyboard. + static final boolean KEYBOARD_ALWAYS_HIDDEN = false; static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; - private Context mContext; - private IWindowManager mWindowManager; - private LocalPowerManager mPowerManager; + Context mContext; + IWindowManager mWindowManager; + LocalPowerManager mPowerManager; /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ - private boolean mEnableShiftMenuBugReports = false; + boolean mEnableShiftMenuBugReports = false; - private WindowState mStatusBar = null; - private WindowState mSearchBar = null; - private WindowState mKeyguard = null; - private KeyguardViewMediator mKeyguardMediator; - private GlobalActions mGlobalActions; - private boolean mShouldTurnOffOnKeyUp; - private RecentApplicationsDialog mRecentAppsDialog; - private Handler mHandler; + WindowState mStatusBar = null; + WindowState mSearchBar = null; + WindowState mKeyguard = null; + KeyguardViewMediator mKeyguardMediator; + GlobalActions mGlobalActions; + boolean mShouldTurnOffOnKeyUp; + RecentApplicationsDialog mRecentAppsDialog; + Handler mHandler; - private boolean mLidOpen; - private int mSensorOrientation = OrientationListener.ORIENTATION_UNKNOWN; - private int mSensorRotation = -1; - private boolean mScreenOn = false; - private boolean mOrientationSensorEnabled = false; - private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + boolean mLidOpen; + int mSensorRotation = -1; + boolean mScreenOn = false; + boolean mOrientationSensorEnabled = false; + int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + static final int DEFAULT_ACCELEROMETER_ROTATION = 0; + int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; + boolean mHasSoftInput = false; - private int mW, mH; - private int mCurLeft, mCurTop, mCurRight, mCurBottom; - private WindowState mTopFullscreenOpaqueWindowState; - private boolean mForceStatusBar; - private boolean mHomePressed; - private Intent mHomeIntent; - private boolean mSearchKeyPressed; - private boolean mConsumeSearchKeyUp; + // The current size of the screen. + int mW, mH; + // During layout, the current screen borders with all outer decoration + // (status bar, input method dock) accounted for. + int mCurLeft, mCurTop, mCurRight, mCurBottom; + // During layout, the frame in which content should be displayed + // to the user, accounting for all screen decoration except for any + // space they deem as available for other content. This is usually + // the same as mCur*, but may be larger if the screen decor has supplied + // content insets. + int mContentLeft, mContentTop, mContentRight, mContentBottom; + // During layout, the current screen borders along with input method + // windows are placed. + int mDockLeft, mDockTop, mDockRight, mDockBottom; + // During layout, the layer at which the doc window is placed. + int mDockLayer; + + static final Rect mTmpParentFrame = new Rect(); + static final Rect mTmpDisplayFrame = new Rect(); + static final Rect mTmpContentFrame = new Rect(); + static final Rect mTmpVisibleFrame = new Rect(); + + WindowState mTopFullscreenOpaqueWindowState; + boolean mForceStatusBar; + boolean mHomePressed; + Intent mHomeIntent; + boolean mSearchKeyPressed; + boolean mConsumeSearchKeyUp; - private static final int ENDCALL_HOME = 0x1; - private static final int ENDCALL_SLEEPS = 0x2; - private static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; - private int mEndcallBehavior; + static final int ENDCALL_HOME = 0x1; + static final int ENDCALL_SLEEPS = 0x2; + static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; + int mEndcallBehavior; - private ShortcutManager mShortcutManager; - private PowerManager.WakeLock mBroadcastWakeLock; + ShortcutManager mShortcutManager; + PowerManager.WakeLock mBroadcastWakeLock; - private class SettingsObserver implements Observer { + class SettingsObserver extends ContentObserver { private ContentQueryMap mSettings; + SettingsObserver(Handler handler) { + super(handler); + } + void observe() { ContentResolver resolver = mContext.getContentResolver(); - Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null, - Settings.System.NAME + "=?", - new String[] { END_BUTTON_BEHAVIOR}, - null); - mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler); - mSettings.addObserver(this); - - // pretend that the settings changed so we will get their initial state - update(mSettings, null); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.END_BUTTON_BEHAVIOR), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.ACCELEROMETER_ROTATION), false, this); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.DEFAULT_INPUT_METHOD), false, this); + update(); } - private int getInt(String name, int def) { - ContentValues row = mSettings.getValues(name); - if (row != null) { - Integer ret = row.getAsInteger(Settings.System.VALUE); - if(ret == null) { - return def; - } - return ret; - } else { - return def; + @Override public void onChange(boolean selfChange) { + update(); + try { + mWindowManager.setRotation(USE_LAST_ROTATION, false); + } catch (RemoteException e) { + // Ignore } } - - public void update(Observable o, Object arg) { - mEndcallBehavior = getInt(END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + + public void update() { + ContentResolver resolver = mContext.getContentResolver(); + mEndcallBehavior = Settings.System.getInt(resolver, + Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); + int accelerometerDefault = Settings.System.getInt(resolver, + Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); + if (mAccelerometerDefault != accelerometerDefault) { + mAccelerometerDefault = accelerometerDefault; + updateOrientationListener(); + } + String imId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + boolean hasSoftInput = imId != null && imId.length() > 0; + if (mHasSoftInput != hasSoftInput) { + mHasSoftInput = hasSoftInput; + updateRotation(); + } } } - private class MyOrientationListener extends OrientationListener { + class MyOrientationListener extends OrientationListener { MyOrientationListener(Context context) { super(context); @@ -214,7 +260,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { // portrait range is 270+45 to 359 and 0 to 45 // landscape range is 270-45 to 270+45 if ((orientation >= 0 && orientation <= 45) || (orientation >= 270 - 45)) { - mSensorOrientation = orientation; int rotation = (orientation >= 270 - 45 && orientation <= 270 + 45) ? Surface.ROTATION_90 : Surface.ROTATION_0; @@ -233,8 +278,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - private MyOrientationListener mOrientationListener; + MyOrientationListener mOrientationListener; + boolean useSensorForOrientation() { + if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + return true; + } + if (mAccelerometerDefault != 0 && ( + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_USER || + mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { + return true; + } + return false; + } + /* * Various use cases for invoking this function * screen turning off, should always disable listeners if already enabled @@ -245,7 +302,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * screen turning on and current app has sensor based orientation, enable listeners if needed * screen turning on and current app has nosensor based orientation, do nothing */ - private void updateOrientationListener() { + void updateOrientationListener() { //Could have been invoked due to screen turning on or off or //change of the currently visible window's orientation if(localLOGV) Log.i(TAG, "Screen status="+mScreenOn+ @@ -253,7 +310,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ", SensorEnabled="+mOrientationSensorEnabled); boolean disable = true; if(mScreenOn) { - if(mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { + if(useSensorForOrientation()) { disable = false; //enable listener if not already enabled if(!mOrientationSensorEnabled) { @@ -271,7 +328,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private Runnable mEndCallLongPress = new Runnable() { + Runnable mEndCallLongPress = new Runnable() { public void run() { mShouldTurnOffOnKeyUp = false; sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); @@ -279,7 +336,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - private void showGlobalActionsDialog() { + void showGlobalActionsDialog() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mPowerManager); } @@ -292,15 +349,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private boolean isDeviceProvisioned() { - return Settings.System.getInt( - mContext.getContentResolver(), Settings.System.DEVICE_PROVISIONED, 0) != 0; + boolean isDeviceProvisioned() { + return Settings.Secure.getInt( + mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; } /** * When a home-key longpress expires, close other system windows and launch the recent apps */ - private Runnable mHomeLongPress = new Runnable() { + Runnable mHomeLongPress = new Runnable() { public void run() { /* * Eat the longpress so it won't dismiss the recent apps dialog when @@ -315,7 +372,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Create (if necessary) and launch the recent apps dialog */ - private void showRecentAppsDialog() { + void showRecentAppsDialog() { if (mRecentAppsDialog == null) { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } @@ -331,7 +388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); mHandler = new Handler(); mOrientationListener = new MyOrientationListener(mContext); - SettingsObserver settingsObserver = new SettingsObserver(); + SettingsObserver settingsObserver = new SettingsObserver(mHandler); settingsObserver.observe(); mShortcutManager = new ShortcutManager(context, mHandler); mShortcutManager.observe(); @@ -359,6 +416,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // this... should introduce a token to let the system // monitor/control what they are doing. break; + case TYPE_INPUT_METHOD: + // The window manager will check this. + break; case TYPE_PHONE: case TYPE_PRIORITY_PHONE: case TYPE_SYSTEM_ALERT: @@ -389,7 +449,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void readLidState() { + void readLidState() { try { int sw = mWindowManager.getSwitchState(0); if (sw >= 0) { @@ -403,8 +463,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ public void adjustConfigurationLw(Configuration config) { readLidState(); - mPowerManager.setKeyboardVisibility(mLidOpen); - config.keyboardHidden = mLidOpen + final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; + mPowerManager.setKeyboardVisibility(lidOpen); + config.keyboardHidden = (lidOpen || mHasSoftInput) + ? Configuration.KEYBOARDHIDDEN_NO + : Configuration.KEYBOARDHIDDEN_YES; + config.hardKeyboardHidden = lidOpen ? Configuration.KEYBOARDHIDDEN_NO : Configuration.KEYBOARDHIDDEN_YES; if (keyguardIsShowingTq()) { @@ -438,10 +502,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return APPLICATION_LAYER; } switch (type) { - case TYPE_APPLICATION_PANEL: - return APPLICATION_LAYER; - case TYPE_APPLICATION_SUB_PANEL: - return APPLICATION_LAYER; case TYPE_STATUS_BAR: return STATUS_BAR_LAYER; case TYPE_STATUS_BAR_PANEL: @@ -458,6 +518,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return SYSTEM_ALERT_LAYER; case TYPE_SYSTEM_ERROR: return SYSTEM_ERROR_LAYER; + case TYPE_INPUT_METHOD: + return INPUT_METHOD_LAYER; + case TYPE_INPUT_METHOD_DIALOG: + return INPUT_METHOD_DIALOG_LAYER; case TYPE_SYSTEM_OVERLAY: return SYSTEM_OVERLAY_LAYER; case TYPE_PRIORITY_PHONE: @@ -473,6 +537,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int subWindowTypeToLayerLw(int type) { switch (type) { case TYPE_APPLICATION_PANEL: + case TYPE_APPLICATION_ATTACHED_DIALOG: return APPLICATION_PANEL_SUBLAYER; case TYPE_APPLICATION_MEDIA: return APPLICATION_MEDIA_SUBLAYER; @@ -514,6 +579,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } Window win = PolicyManager.makeNewWindow(context); + if (win.getWindowStyle().getBoolean( + com.android.internal.R.styleable.Window_windowDisablePreview, false)) { + return null; + } + Resources r = context.getResources(); win.setTitle(r.getText(labelRes, nonLocalizedLabel)); @@ -634,7 +704,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private static final boolean PRINT_ANIM = false; + static final boolean PRINT_ANIM = false; /** {@inheritDoc} */ public int selectAnimationLw(WindowState win, int transit) { @@ -650,15 +720,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - private static ITelephony getPhoneInterface() { + static ITelephony getPhoneInterface() { return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); } - private static IAudioService getAudioInterface() { + static IAudioService getAudioInterface() { return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); } - private boolean keyguardOn() { + boolean keyguardOn() { return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); } @@ -826,7 +896,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * A home key -> launch home action was detected. Take the appropriate action * given the situation with the keyguard. */ - private void launchHomeFromHotKey() { + void launchHomeFromHotKey() { if (mKeyguardMediator.isShowing()) { // don't launch home if keyguard showing } else if (mKeyguardMediator.isInputRestricted()) { @@ -847,15 +917,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - public void getCoveredInsetHintLw(WindowManager.LayoutParams attrs, Rect coveredInset) { + public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { final int fl = attrs.flags; if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { - coveredInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); + contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); } else { - coveredInset.setEmpty(); + contentInset.setEmpty(); } } @@ -863,19 +933,75 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void beginLayoutLw(int displayWidth, int displayHeight) { mW = displayWidth; mH = displayHeight; - mCurLeft = 0; - mCurTop = 0; - mCurRight = displayWidth; - mCurBottom = displayHeight; + mDockLeft = mContentLeft = mCurLeft = 0; + mDockTop = mContentTop = mCurTop = 0; + mDockRight = mContentRight = mCurRight = displayWidth; + mDockBottom = mContentBottom = mCurBottom = displayHeight; + mDockLayer = 0x10000000; // decide where the status bar goes ahead of time if (mStatusBar != null) { - mStatusBar.computeFrameLw(0, 0, displayWidth, displayHeight, - 0, 0, displayWidth, displayHeight); - mCurTop = mStatusBar.getFrameLw().bottom; + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect vf = mTmpVisibleFrame; + pf.left = df.left = vf.left = 0; + pf.top = df.top = vf.top = 0; + pf.right = df.right = vf.right = displayWidth; + pf.bottom = df.bottom = vf.bottom = displayHeight; + + mStatusBar.computeFrameLw(pf, df, vf, vf); + mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; } } + void setAttachedWindowFrames(WindowState win, int fl, int sim, + WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { + if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { + // Here's a special case: if this attached window is a panel that is + // above the dock window, and the window it is attached to is below + // the dock window, then the frames we computed for the window it is + // attached to can not be used because the dock is effectively part + // of the underlying window and the attached window is floating on top + // of the whole thing. So, we ignore the attached window and explicitly + // compute the frames that would be appropriate without the dock. + df.left = cf.left = vf.left = mDockLeft; + df.top = cf.top = vf.top = mDockTop; + df.right = cf.right = vf.right = mDockRight; + df.bottom = cf.bottom = vf.bottom = mDockBottom; + } else { + // The effective display frame of the attached window depends on + // whether it is taking care of insetting its content. If not, + // we need to use the parent's content frame so that the entire + // window is positioned within that content. Otherwise we can use + // the display frame and let the attached window take care of + // positioning its content appropriately. + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.set(attached.getDisplayFrameLw()); + } else { + // If the window is resizing, then we want to base the content + // frame on our attached content frame to resize... however, + // things can be tricky if the attached window is NOT in resize + // mode, in which case its content frame will be larger. + // Ungh. So to deal with that, make sure the content frame + // we end up using is not covering the IM dock. + cf.set(attached.getContentFrameLw()); + if (attached.getSurfaceLayer() < mDockLayer) { + if (cf.left < mContentLeft) cf.left = mContentLeft; + if (cf.top < mContentTop) cf.top = mContentTop; + if (cf.right > mContentRight) cf.right = mContentRight; + if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; + } + } + df.set(insetDecors ? attached.getDisplayFrameLw() : cf); + vf.set(attached.getVisibleFrameLw()); + } + // The LAYOUT_IN_SCREEN flag is used to determine whether the attached + // window should be positioned relative to its parent or the entire + // screen. + pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 + ? attached.getFrameLw() : df); + } + /** {@inheritDoc} */ public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached) { // we've already done the status bar @@ -883,52 +1009,132 @@ public class PhoneWindowManager implements WindowManagerPolicy { return; } + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + Log.i(TAG, "GOTCHA!"); + } + } + final int fl = attrs.flags; + final int sim = attrs.softInputMode; - int dl, dt, dr, db; - if ((fl & FLAG_LAYOUT_IN_SCREEN) == 0) { - // Make sure this window doesn't intrude into the status bar. - dl = mCurLeft; - dt = mCurTop; - dr = mCurRight; - db = mCurBottom; - } else { - dl = 0; - dt = 0; - dr = mW; - db = mH; - } + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect cf = mTmpContentFrame; + final Rect vf = mTmpVisibleFrame; - if ((fl & - (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) - == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { - win.setCoveredInsetsLw(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); + if (attrs.type == TYPE_INPUT_METHOD) { + pf.left = df.left = cf.left = vf.left = mDockLeft; + pf.top = df.top = cf.top = vf.top = mDockTop; + pf.right = df.right = cf.right = vf.right = mDockRight; + pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; + // IM dock windows always go to the bottom of the screen. + attrs.gravity = Gravity.BOTTOM; + mDockLayer = win.getSurfaceLayer(); } else { - win.setCoveredInsetsLw(0, 0, 0, 0); - } - - int pl, pt, pr, pb; - if (attached != null && (fl & (FLAG_LAYOUT_IN_SCREEN)) == 0) { - final Rect r = attached.getFrameLw(); - pl = r.left; - pt = r.top; - pr = r.right; - pb = r.bottom; - } else { - pl = dl; - pt = dt; - pr = dr; - pb = db; + if ((fl & + (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) + == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { + // This is the case for a normal activity window: we want it + // to cover all of the screen space, and it can take care of + // moving its contents to account for screen decorations that + // intrude into that space. + if (attached != null) { + // If this window is attached to another, our display + // frame is the same as the one we are attached to. + setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); + } else { + pf.left = df.left = 0; + pf.top = df.top = 0; + pf.right = df.right = mW; + pf.bottom = df.bottom = mH; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } + } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { + // A window that has requested to fill the entire screen just + // gets everything, period. + pf.left = df.left = cf.left = 0; + pf.top = df.top = cf.top = 0; + pf.right = df.right = cf.right = mW; + pf.bottom = df.bottom = cf.bottom = mH; + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } else if (attached != null) { + // A child window should be placed inside of the same visible + // frame that its parent had. + setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf); + } else { + // Otherwise, a normal window must be placed inside the content + // of all screen decorations. + pf.left = mContentLeft; + pf.top = mContentTop; + pf.right = mContentRight; + pf.bottom = mContentBottom; + if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { + df.left = cf.left = mDockLeft; + df.top = cf.top = mDockTop; + df.right = cf.right = mDockRight; + df.bottom = cf.bottom = mDockBottom; + } else { + df.left = cf.left = mContentLeft; + df.top = cf.top = mContentTop; + df.right = cf.right = mContentRight; + df.bottom = cf.bottom = mContentBottom; + } + vf.left = mCurLeft; + vf.top = mCurTop; + vf.right = mCurRight; + vf.bottom = mCurBottom; + } } if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { - dl = -100000; - dt = -100000; - dr = 100000; - db = 100000; + df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; + df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; } - win.computeFrameLw(pl, pt, pr, pb, dl, dt, dr, db); + if (false) { + if ("com.google.android.youtube".equals(attrs.packageName) + && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { + if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + + ": pf=" + pf.toShortString() + " df=" + df.toShortString() + + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); + } + } + + win.computeFrameLw(pf, df, cf, vf); + + // Dock windows carve out the bottom of the screen, so normal windows + // can't appear underneath them. + if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { + int top = win.getContentFrameLw().top; + top += win.getGivenContentInsetsLw().top; + if (mContentBottom > top) { + mContentBottom = top; + } + top = win.getVisibleFrameLw().top; + top += win.getGivenVisibleInsetsLw().top; + if (mCurBottom > top) { + mCurBottom = top; + } + } } /** {@inheritDoc} */ @@ -1011,7 +1217,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * @return Whether a telephone call is in progress right now. */ - private boolean isInCall() { + boolean isInCall() { final ITelephony phone = getPhoneInterface(); if (phone == null) { Log.w(TAG, "couldn't get ITelephony reference"); @@ -1028,7 +1234,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * @return Whether music is being played right now. */ - private boolean isMusicActive() { + boolean isMusicActive() { final IAudioService audio = getAudioInterface(); if (audio == null) { Log.w(TAG, "isMusicActive: couldn't get IAudioService reference"); @@ -1046,7 +1252,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * Tell the audio service to adjust the volume appropriate to the event. * @param keycode */ - private void sendVolToMusic(int keycode) { + void sendVolToMusic(int keycode) { final IAudioService audio = getAudioInterface(); if (audio == null) { Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference"); @@ -1069,7 +1275,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { mBroadcastWakeLock.release(); } } - + + static boolean isMediaKey(int code) { + if (code == KeyEvent.KEYCODE_HEADSETHOOK || + code == KeyEvent.KEYCODE_PLAYPAUSE || + code == KeyEvent.KEYCODE_STOP || + code == KeyEvent.KEYCODE_NEXTSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_PREVIOUSSONG || + code == KeyEvent.KEYCODE_FORWARD) { + return true; + } + return false; + } + /** {@inheritDoc} */ public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { int result = ACTION_PASS_TO_USER; @@ -1165,7 +1384,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { result &= ~ACTION_PASS_TO_USER; } } - } else if (code == KeyEvent.KEYCODE_HEADSETHOOK) { + } else if (isMediaKey(code)) { // This key needs to be handled even if the screen is off. // If others need to be handled while it's off, this is a reasonable // pattern to follow. @@ -1175,7 +1394,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // only do it if the showing app doesn't process the key on its own. KeyEvent keyEvent = new KeyEvent(event.when, event.when, down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, - KeyEvent.KEYCODE_HEADSETHOOK, 0); + code, 0); mBroadcastWakeLock.acquire(); mHandler.post(new PassHeadsetKey(keyEvent)); } @@ -1200,7 +1419,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { + BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { mBroadcastWakeLock.release(); } @@ -1298,20 +1517,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: //always return portrait if orientation set to portrait return Surface.ROTATION_0; - case ActivityInfo.SCREEN_ORIENTATION_SENSOR: - if(mOrientationSensorEnabled) { - //consider only sensor based orientation keyboard slide ignored - return mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; - } - //if orientation sensor is disabled fall back to default behaviour - //based on lid } // case for nosensor meaning ignore sensor and consider only lid // or orientation sensor disabled //or case.unspecified - if(mLidOpen) { + if (mLidOpen) { return Surface.ROTATION_90; } else { + if (useSensorForOrientation()) { + // If the user has enabled auto rotation by default, do it. + return mSensorRotation >= 0 ? mSensorRotation : Surface.ROTATION_0; + } return Surface.ROTATION_0; } } @@ -1329,6 +1545,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // tell the keyguard mKeyguardMediator.onSystemReady(); android.os.SystemProperties.set("dev.bootcomplete", "1"); + updateOrientationListener(); } catch (RemoteException e) { // Ignore } @@ -1340,7 +1557,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(); } - private void updateRotation() { + void updateRotation() { mPowerManager.setKeyboardVisibility(mLidOpen); int rotation= Surface.ROTATION_0; if (mLidOpen) { diff --git a/policy/com/android/internal/policy/impl/Policy.java b/policy/com/android/internal/policy/impl/Policy.java index f537186766cdf..17f3e91296667 100644 --- a/policy/com/android/internal/policy/impl/Policy.java +++ b/policy/com/android/internal/policy/impl/Policy.java @@ -17,6 +17,7 @@ package com.android.internal.policy.impl; import android.content.Context; +import android.util.Log; import com.android.internal.policy.IPolicy; import com.android.internal.policy.impl.PhoneLayoutInflater; @@ -30,6 +31,29 @@ import com.android.internal.policy.impl.PhoneWindowManager; // Simple implementation of the policy interface that spawns the right // set of objects public class Policy implements IPolicy { + private static final String TAG = "PhonePolicy"; + + private static final String[] preload_classes = { + "com.android.internal.policy.impl.PhoneLayoutInflater", + "com.android.internal.policy.impl.PhoneWindow", + "com.android.internal.policy.impl.PhoneWindow$1", + "com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback", + "com.android.internal.policy.impl.PhoneWindow$DecorView", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState", + "com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState", + }; + + static { + // For performance reasons, preload some policy specific classes when + // the policy gets loaded. + for (String s : preload_classes) { + try { + Class.forName(s); + } catch (ClassNotFoundException ex) { + Log.e(TAG, "Could not preload class for phone policy: " + s); + } + } + } public PhoneWindow makeNewWindow(Context context) { return new PhoneWindow(context); diff --git a/policy/com/android/internal/policy/impl/SimUnlockScreen.java b/policy/com/android/internal/policy/impl/SimUnlockScreen.java index 4c713925d1749..fceec5fb997e3 100644 --- a/policy/com/android/internal/policy/impl/SimUnlockScreen.java +++ b/policy/com/android/internal/policy/impl/SimUnlockScreen.java @@ -101,11 +101,19 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie public void onResume() { // start fresh mHeaderText.setText(R.string.keyguard_password_enter_pin_code); + + // make sure that the number of entered digits is consistent when we + // erase the SIM unlock code, including orientation changes. mPinText.setText(""); + mEnteredDigits = 0; } /** {@inheritDoc} */ public void cleanUp() { + // hide the dialog. + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } mUpdateMonitor.removeCallback(this); } @@ -143,7 +151,7 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie } } } - + public void onClick(View v) { if (v == mBackSpaceButton) { final Editable digits = mPinText.getText(); @@ -191,7 +199,9 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie new CheckSimPin(mPinText.getText().toString()) { void onSimLockChangedResponse(boolean success) { - getSimUnlockProgressDialog().hide(); + if (mSimUnlockProgressDialog != null) { + mSimUnlockProgressDialog.hide(); + } if (success) { // before closing the keyguard, report back that // the sim is unlocked so it knows right away diff --git a/policy/com/android/internal/policy/impl/UnlockScreen.java b/policy/com/android/internal/policy/impl/UnlockScreen.java index bd0b6d521e507..65ab439c336f9 100644 --- a/policy/com/android/internal/policy/impl/UnlockScreen.java +++ b/policy/com/android/internal/policy/impl/UnlockScreen.java @@ -16,9 +16,14 @@ package com.android.internal.policy.impl; +import android.content.ComponentName; import android.content.Context; +import android.content.ServiceConnection; import android.os.CountDownTimer; +import android.os.IBinder; +import android.os.RemoteException; import android.os.SystemClock; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -85,6 +90,8 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient private Button mForgotPatternButton; + private ServiceConnection mServiceConnection; + enum FooterMode { Normal, @@ -177,6 +184,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient // stealth mode will be the same for the life of this screen mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled()); + // vibrate mode will be the same for the life of this screen + mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled()); + // assume normal footer mode for now updateFooter(FooterMode.Normal); @@ -237,6 +247,10 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient mLockPatternView.enableInput(); mLockPatternView.setEnabled(true); mLockPatternView.clearPattern(); + + // show "forgot pattern?" button if we have an alternate authentication method + mForgotPatternButton.setVisibility(mCallback.doesFallbackUnlockScreenExist() + ? View.VISIBLE : View.INVISIBLE); // if the user is currently locked out, enforce it. long deadline = mLockPatternUtils.getLockoutAttemptDeadline();