diff options
Diffstat (limited to 'policy')
6 files changed, 545 insertions, 239 deletions
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java index ae23df6..7983278 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java @@ -20,6 +20,7 @@ import com.android.internal.R; import android.content.Context; import android.content.pm.ActivityInfo; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Canvas; import android.util.Log; @@ -94,6 +95,8 @@ public class KeyguardViewManager implements KeyguardWindowController { public synchronized void show() { if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView); + Resources res = mContext.getResources(); + boolean enableScreenRotation = res.getBoolean(R.bool.config_enableLockScreenRotation); if (mKeyguardHost == null) { if (DEBUG) Log.d(TAG, "keyguard host is null, creating it..."); @@ -116,18 +119,22 @@ public class KeyguardViewManager implements KeyguardWindowController { lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen; - // TODO: Sometimes we get the wrong value for the sensor resource we use to configure - // this. However, the current UI design has LockScreen always respond to orientation so - // we don't need this for the time-being. - // - // For reference, the configuration variable is R.bool.config_enableLockScreenRotation - lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; lp.setTitle("Keyguard"); mWindowLayoutParams = lp; mViewManager.addView(mKeyguardHost, lp); } + if (enableScreenRotation) { + Log.d(TAG, "Rotation sensor for lock screen On!"); + mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR; + } else { + Log.d(TAG, "Rotation sensor for lock screen Off!"); + mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; + } + + mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams); + if (mKeyguardView == null) { if (DEBUG) Log.d(TAG, "keyguard view is null, creating it..."); mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this); diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java index e7a9eb1..8a60098 100644 --- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java +++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java @@ -45,7 +45,6 @@ import android.os.SystemProperties; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; -import android.util.Config; import android.util.EventLog; import android.util.Log; import android.view.KeyEvent; diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java index 5b80a93..6734005 100644 --- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java @@ -27,7 +27,9 @@ import com.android.internal.widget.PasswordEntryKeyboardView; import android.os.CountDownTimer; import android.os.SystemClock; +import android.security.KeyStore; import android.telephony.TelephonyManager; +import android.text.InputType; import android.text.method.DigitsKeyListener; import android.text.method.TextKeyListener; import android.util.Log; @@ -70,6 +72,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen private CountDownTimer mCountdownTimer; private StatusView mStatusView; + private final boolean mUseSystemIME = true; // TODO: Make configurable // To avoid accidental lockout due to events while the device in in the pocket, ignore // any passwords with length less than or equal to this length. @@ -108,14 +111,24 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mPasswordEntry.setOnEditorActionListener(this); mPasswordEntry.setOnClickListener(new OnClickListener() { public void onClick(View v) { - if (mIsAlpha && !isPhysicalKbShowing) { - mKeyboardViewAlpha.setVisibility( - mKeyboardViewAlpha.getVisibility() == View.VISIBLE - ? View.GONE : View.VISIBLE); - mCallback.pokeWakelock(); + if (mIsAlpha && !isPhysicalKbShowing && !mUseSystemIME) { + // Toggle visibility of alpha keyboard + final boolean visible = mKeyboardViewAlpha.getVisibility() == View.VISIBLE; + mKeyboardViewAlpha.setVisibility(visible ? View.GONE : View.VISIBLE); } + mCallback.pokeWakelock(); } }); + + // We don't currently use the IME for PIN mode, but this will make it work if we ever do... + if (!mIsAlpha) { + mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER + | InputType.TYPE_NUMBER_VARIATION_PASSWORD); + } else { + mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD); + } + mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall); mEmergencyCallButton.setOnClickListener(this); mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton); @@ -176,7 +189,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen /** {@inheritDoc} */ public boolean needsInput() { - return false; + return mUseSystemIME && mIsAlpha; } /** {@inheritDoc} */ @@ -220,6 +233,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen mCallback.keyguardDone(true); mCallback.reportSuccessfulUnlockAttempt(); mStatusView.setInstructionText(null); + KeyStore.getInstance().password(entry); } else if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. @@ -295,7 +309,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { // Check if this was the result of hitting the enter key - if (actionId == EditorInfo.IME_NULL) { + if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE) { verifyPasswordAndUnlock(); return true; } diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java index 018fe0c..a685497 100644 --- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java +++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Configuration; import android.os.CountDownTimer; import android.os.SystemClock; +import android.security.KeyStore; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -407,6 +408,7 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient mStatusView.updateStatusLines(true); mCallback.keyguardDone(true); mCallback.reportSuccessfulUnlockAttempt(); + KeyStore.getInstance().password(LockPatternUtils.patternToString(pattern)); } else { boolean reportFailedAttempt = false; if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index fc9502c..75f466a 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -26,17 +26,17 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; -import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; -import com.android.internal.view.menu.ActionMenuView; import com.android.internal.view.menu.ContextMenuBuilder; +import com.android.internal.view.menu.IconMenuPresenter; +import com.android.internal.view.menu.ListMenuPresenter; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; -import com.android.internal.view.menu.MenuItemImpl; -import com.android.internal.view.menu.MenuPopupHelper; +import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; +import com.android.internal.widget.ActionBarContainer; import com.android.internal.widget.ActionBarContextView; import com.android.internal.widget.ActionBarView; @@ -54,7 +54,6 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.AndroidRuntimeException; -import android.util.Config; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -76,7 +75,6 @@ import android.view.ViewManager; import android.view.ViewStub; import android.view.Window; import android.view.WindowManager; -import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; @@ -126,6 +124,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private TextView mTitleView; private ActionBarView mActionBar; + private ActionMenuPresenterCallback mActionMenuPresenterCallback; + private PanelMenuPresenterCallback mPanelMenuPresenterCallback; private DrawableFeatureState[] mDrawables; @@ -168,7 +168,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ContextMenuBuilder mContextMenu; private MenuDialogHelper mContextMenuHelper; - private ActionButtonSubmenu mActionButtonPopup; private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; @@ -343,7 +342,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } } - // Call callback, and return if it doesn't want to display menu + + // Call callback, and return if it doesn't want to display menu. + + // Creating the panel menu will involve a lot of manipulation; + // don't dispatch change events to presenters until we're done. + st.menu.stopDispatchingItemsChanged(); if ((cb == null) || !cb.onCreatePanelMenu(st.featureId, st.menu)) { // Ditch the menu created above st.menu = null; @@ -354,14 +358,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.refreshMenuContent = false; if (mActionBar != null) { - mActionBar.setMenu(st.menu); + if (mActionMenuPresenterCallback == null) { + mActionMenuPresenterCallback = new ActionMenuPresenterCallback(); + } + mActionBar.setMenu(st.menu, mActionMenuPresenterCallback); } } // Callback and return if the callback does not want to show the menu + + // Preparing the panel menu can involve a lot of manipulation; + // don't dispatch change events to presenters until we're done. + st.menu.stopDispatchingItemsChanged(); if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { + st.menu.startDispatchingItemsChanged(); return false; } + st.menu.startDispatchingItemsChanged(); // Set the proper keymap KeyCharacterMap kmap = KeyCharacterMap.load( @@ -384,12 +397,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mActionBar == null) { PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); if ((st != null) && (st.menu != null)) { - final MenuBuilder menuBuilder = (MenuBuilder) st.menu; - if (st.isOpen) { // Freeze state final Bundle state = new Bundle(); - menuBuilder.saveHierarchyState(state); + if (st.iconMenuPresenter != null) { + st.iconMenuPresenter.saveHierarchyState(state); + } + if (st.expandedMenuPresenter != null) { + st.expandedMenuPresenter.saveHierarchyState(state); + } // Remove the menu views since they need to be recreated // according to the new configuration @@ -399,7 +415,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { reopenMenu(false); // Restore state - menuBuilder.restoreHierarchyState(state); + if (st.iconMenuPresenter != null) { + st.iconMenuPresenter.restoreHierarchyState(state); + } + if (st.expandedMenuPresenter != null) { + st.expandedMenuPresenter.restoreHierarchyState(state); + } } else { // Clear menu views so on next menu opening, it will use @@ -419,8 +440,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Causes the decor view to be recreated st.refreshDecorView = true; - - ((MenuBuilder) st.menu).clearMenuViews(); + + st.clearMenuPresenters(); } @Override @@ -450,11 +471,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (st.featureId == FEATURE_OPTIONS_PANEL) { Context context = getContext(); Configuration config = context.getResources().getConfiguration(); + boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == + Configuration.SCREENLAYOUT_SIZE_XLARGE; boolean isHoneycombApp = context.getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB; - if (isHoneycombApp && - config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE)) { + if (isXLarge && isHoneycombApp) { return; } } @@ -487,7 +509,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } // This will populate st.shownPanelView - if (!initializePanelContent(st) || (st.shownPanelView == null)) { + if (!initializePanelContent(st) || !st.hasPanelItems()) { return; } @@ -563,6 +585,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public final void closePanel(PanelFeatureState st, boolean doCallback) { // System.out.println("Close panel: isOpen=" + st.isOpen); + if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL && + mActionBar != null && mActionBar.isOverflowMenuShowing()) { + checkCloseActionMenu(st.menu); + return; + } + final ViewManager wm = getWindowManager(); if ((wm != null) && st.isOpen) { if (st.decorView != null) { @@ -573,10 +601,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (doCallback) { callOnPanelClosed(st.featureId, st, null); } - } else if (st.featureId == FEATURE_OPTIONS_PANEL && doCallback && - mActionBar != null) { - checkCloseActionMenu(st.menu); } + st.isPrepared = false; st.isHandled = false; st.isOpen = false; @@ -597,22 +623,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - private void checkCloseActionMenu(Menu menu) { + void checkCloseActionMenu(Menu menu) { if (mClosingActionMenu) { return; } - boolean closed = false; mClosingActionMenu = true; - if (mActionBar.isOverflowMenuOpen() && mActionBar.hideOverflowMenu()) { - closed = true; - } - if (mActionButtonPopup != null) { - mActionButtonPopup.dismiss(); - closed = true; - } + mActionBar.dismissPopupMenus(); Callback cb = getCallback(); - if (cb != null && closed && !isDestroyed()) { + if (cb != null && !isDestroyed()) { cb.onPanelClosed(FEATURE_ACTION_BAR, menu); } mClosingActionMenu = false; @@ -849,67 +868,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return false; } - public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { - final PanelFeatureState panel = findMenuPanel(menu); - if (panel != null) { - // Close the panel and only do the callback if the menu is being - // closed - // completely, not if opening a sub menu - closePanel(panel, allMenusAreClosing); - } - } - - public void onCloseSubMenu(SubMenuBuilder subMenu) { - final Menu parentMenu = subMenu.getRootMenu(); - final PanelFeatureState panel = findMenuPanel(parentMenu); - - // Callback - if (panel != null) { - callOnPanelClosed(panel.featureId, panel, parentMenu); - closePanel(panel, true); - } - } - - public boolean onSubMenuSelected(final SubMenuBuilder subMenu) { - if (!subMenu.hasVisibleItems()) { - return true; - } - - final Menu parentMenu = subMenu.getRootMenu(); - final PanelFeatureState panel = findMenuPanel(parentMenu); - - if (hasFeature(FEATURE_ACTION_BAR) && panel.featureId == FEATURE_OPTIONS_PANEL) { - mDecor.post(new Runnable() { - public void run() { - mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu); - mActionButtonPopup.show(); - Callback cb = getCallback(); - if (cb != null && !isDestroyed()) { - cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); - } - } - }); - } else { - // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); - } - - return true; - } - public void onMenuModeChange(MenuBuilder menu) { reopenMenu(true); } private void reopenMenu(boolean toggleMenuMode) { - if (mActionBar != null) { + if (mActionBar != null && mActionBar.isOverflowReserved()) { final Callback cb = getCallback(); if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) { final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) { cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu); - mActionBar.openOverflowMenu(); + mActionBar.showOverflowMenu(); } } } else { @@ -978,23 +949,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * @return Whether the initialization was successful. */ protected boolean initializePanelContent(PanelFeatureState st) { - if (st.createdPanelView != null) { st.shownPanelView = st.createdPanelView; return true; } - final MenuBuilder menu = (MenuBuilder)st.menu; - if (menu == null) { + if (st.menu == null) { return false; } - st.shownPanelView = menu.getMenuView((st.isInExpandedMode) ? MenuBuilder.TYPE_EXPANDED - : MenuBuilder.TYPE_ICON, st.decorView); + if (mPanelMenuPresenterCallback == null) { + mPanelMenuPresenterCallback = new PanelMenuPresenterCallback(); + } + + MenuView menuView = st.isInExpandedMode + ? st.getExpandedMenuView(mPanelMenuPresenterCallback) + : st.getIconMenuView(mPanelMenuPresenterCallback); + + st.shownPanelView = (View) menuView; if (st.shownPanelView != null) { // Use the menu View's default animations if it has any - final int defaultAnimations = ((MenuView) st.shownPanelView).getWindowAnimations(); + final int defaultAnimations = menuView.getWindowAnimations(); if (defaultAnimations != 0) { st.windowAnimations = defaultAnimations; } @@ -1455,7 +1431,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (focusedView.getId() != View.NO_ID) { outState.putInt(FOCUSED_ID_TAG, focusedView.getId()); } else { - if (Config.LOGD) { + if (false) { Log.d(TAG, "couldn't save which view has focus because the focused view " + focusedView + " has no id."); } @@ -1470,7 +1446,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (mActionBar != null) { - outState.putBoolean(ACTION_BAR_TAG, mActionBar.isOverflowMenuShowing()); + SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>(); + mActionBar.saveHierarchyState(actionBarStates); + outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates); } return outState; @@ -1508,8 +1486,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { restorePanelState(panelStates); } - if (mActionBar != null && savedInstanceState.getBoolean(ACTION_BAR_TAG)) { - mActionBar.postShowOverflowMenu(); + if (mActionBar != null) { + SparseArray<Parcelable> actionBarStates = + savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG); + mActionBar.restoreHierarchyState(actionBarStates); } } @@ -1548,6 +1528,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } st.onRestoreInstanceState(icicles.get(curFeatureId)); + invalidatePanelMenu(curFeatureId); } /* @@ -1581,6 +1562,54 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + private class PanelMenuPresenterCallback implements MenuPresenter.Callback { + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + final Menu parentMenu = menu.getRootMenu(); + final boolean isSubMenu = parentMenu != menu; + final PanelFeatureState panel = findMenuPanel(isSubMenu ? parentMenu : menu); + if (panel != null) { + if (isSubMenu) { + callOnPanelClosed(panel.featureId, panel, parentMenu); + closePanel(panel, true); + } else { + // Close the panel and only do the callback if the menu is being + // closed completely, not if opening a sub menu + closePanel(panel, allMenusAreClosing); + } + } + } + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (subMenu == null && hasFeature(FEATURE_ACTION_BAR)) { + Callback cb = getCallback(); + if (cb != null && !isDestroyed()) { + cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); + } + } + + return true; + } + } + + private final class ActionMenuPresenterCallback implements MenuPresenter.Callback { + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + Callback cb = getCallback(); + if (cb != null) { + cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu); + return true; + } + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + checkCloseActionMenu(menu); + } + } + private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { /* package */int mDefaultOpacity = PixelFormat.OPAQUE; @@ -1938,8 +1967,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mContextMenu.clearAll(); } - mContextMenuHelper = mContextMenu.show(originalView, originalView.getWindowToken()); - return mContextMenuHelper != null; + final MenuDialogHelper helper = mContextMenu.show(originalView, + originalView.getWindowToken()); + if (helper != null) { + helper.setPresenterCallback(mContextMenuCallback); + } + mContextMenuHelper = helper; + return helper != null; } @Override @@ -2104,7 +2138,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // if either the frame -or- the background is opaque. int fop = fg.getOpacity(); int bop = bg.getOpacity(); - if (Config.LOGV) + if (false) Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { opacity = PixelFormat.OPAQUE; @@ -2119,15 +2153,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // For now we have to assume translucent if there is a // frame with padding... there is no way to tell if the // frame and background together will draw all pixels. - if (Config.LOGV) + if (false) Log.v(TAG, "Padding: " + mFramePadding); opacity = PixelFormat.TRANSLUCENT; } } - if (Config.LOGV) + if (false) Log.v(TAG, "Background: " + bg + ", Frame: " + fg); - if (Config.LOGV) + if (false) Log.v(TAG, "Selected default opacity: " + opacity); mDefaultOpacity = opacity; @@ -2190,11 +2224,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { cb.onDetachedFromWindow(); } - if (mActionButtonPopup != null) { - if (mActionButtonPopup.isShowing()) { - mActionButtonPopup.dismiss(); - } - mActionButtonPopup = null; + if (mActionBar != null) { + mActionBar.dismissPopupMenus(); } if (mActionModePopup != null) { @@ -2207,14 +2238,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - protected void onConfigurationChanged(Configuration newConfig) { - if (mActionButtonPopup != null) { - mActionButtonPopup.dismiss(); - post(mActionButtonPopup); - } - } - - @Override public void onCloseSystemDialogs(String reason) { if (mFeatureId >= 0) { closeAllPanels(); @@ -2572,6 +2595,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { mActionBar.initIndeterminateProgress(); } + + final boolean splitActionBar = getWindowStyle().getBoolean( + com.android.internal.R.styleable.Window_windowSplitActionBar, false); + if (splitActionBar) { + final ActionBarContainer splitView = (ActionBarContainer) findViewById( + com.android.internal.R.id.split_action_bar); + if (splitView != null) { + splitView.setVisibility(View.VISIBLE); + mActionBar.setSplitActionBar(splitActionBar); + mActionBar.setSplitView(splitView); + + final ActionBarContextView cab = (ActionBarContextView) findViewById( + com.android.internal.R.id.action_context_bar); + cab.setSplitView(splitView); + } else { + Log.e(TAG, "Window style requested split action bar with " + + "incompatible window decor! Ignoring request."); + } + } + // Post the panel invalidate for later; avoid application onCreateOptionsMenu // being called in the middle of onCreate or similar. mDecor.post(new Runnable() { @@ -2914,7 +2957,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { View shownPanelView; /** Use {@link #setMenu} to set this. */ - Menu menu; + MenuBuilder menu; + + IconMenuPresenter iconMenuPresenter; + ListMenuPresenter expandedMenuPresenter; /** * Whether the panel has been prepared (see @@ -2958,6 +3004,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { refreshDecorView = false; } + public boolean hasPanelItems() { + if (shownPanelView == null) return false; + + if (isInExpandedMode) { + return expandedMenuPresenter.getAdapter().getCount() > 0; + } else { + return ((ViewGroup) shownPanelView).getChildCount() > 0; + } + } + + /** + * Unregister and free attached MenuPresenters. They will be recreated as needed. + */ + public void clearMenuPresenters() { + if (menu != null) { + menu.removeMenuPresenter(iconMenuPresenter); + menu.removeMenuPresenter(expandedMenuPresenter); + } + iconMenuPresenter = null; + expandedMenuPresenter = null; + } + void setStyle(Context context) { TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme); background = a.getResourceId( @@ -2969,13 +3037,56 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { a.recycle(); } - void setMenu(Menu menu) { + void setMenu(MenuBuilder menu) { this.menu = menu; + } + + MenuView getExpandedMenuView(MenuPresenter.Callback cb) { + if (menu == null) return null; + + getIconMenuView(cb); // Need this initialized to know where our offset goes - if (frozenMenuState != null) { - ((MenuBuilder) menu).restoreHierarchyState(frozenMenuState); + boolean init = false; + if (expandedMenuPresenter == null) { + expandedMenuPresenter = new ListMenuPresenter( + com.android.internal.R.layout.list_menu_item_layout, + com.android.internal.R.style.Theme_ExpandedMenu); + expandedMenuPresenter.setCallback(cb); + menu.addMenuPresenter(expandedMenuPresenter); + init = true; + } + + expandedMenuPresenter.setItemIndexOffset(iconMenuPresenter.getNumActualItemsShown()); + MenuView result = expandedMenuPresenter.getMenuView(decorView); + + if (init && frozenMenuState != null) { + expandedMenuPresenter.restoreHierarchyState(frozenMenuState); + // Once we initialize the expanded menu we're done with the frozen state + // since we will have also restored any icon menu state. frozenMenuState = null; } + + return result; + } + + MenuView getIconMenuView(MenuPresenter.Callback cb) { + if (menu == null) return null; + + boolean init = false; + if (iconMenuPresenter == null) { + iconMenuPresenter = new IconMenuPresenter(); + iconMenuPresenter.setCallback(cb); + menu.addMenuPresenter(iconMenuPresenter); + init = true; + } + + MenuView result = iconMenuPresenter.getMenuView(decorView); + + if (init && frozenMenuState != null) { + iconMenuPresenter.restoreHierarchyState(frozenMenuState); + } + + return result; } Parcelable onSaveInstanceState() { @@ -2986,7 +3097,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (menu != null) { savedState.menuState = new Bundle(); - ((MenuBuilder) menu).saveHierarchyState(savedState.menuState); + if (iconMenuPresenter != null) { + iconMenuPresenter.saveHierarchyState(savedState.menuState); + } + if (expandedMenuPresenter != null) { + expandedMenuPresenter.saveHierarchyState(savedState.menuState); + } } return savedState; @@ -3004,9 +3120,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * The first time the menu is being shown after restoring, the * Activity.onCreateOptionsMenu should be called. But, if it is the * same instance then menu != null and we won't call that method. - * So, clear this. Also clear any cached views. + * We clear any cached views here. The caller should invalidatePanelMenu. */ - menu = null; createdPanelView = null; shownPanelView = null; decorView = null; @@ -3065,7 +3180,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * <li> Calls back to the callback's onMenuItemSelected when an item is * selected. */ - private final class DialogMenuCallback implements MenuBuilder.Callback { + private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback { private int mFeatureId; private MenuDialogHelper mSubMenuHelper; @@ -3074,6 +3189,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (menu.getRootMenu() != menu) { + onCloseSubMenu(menu); + } + if (allMenusAreClosing) { Callback callback = getCallback(); if (callback != null && !isDestroyed()) { @@ -3092,7 +3211,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - public void onCloseSubMenu(SubMenuBuilder menu) { + public void onCloseSubMenu(MenuBuilder menu) { Callback callback = getCallback(); if (callback != null && !isDestroyed()) { callback.onPanelClosed(mFeatureId, menu.getRootMenu()); @@ -3108,7 +3227,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void onMenuModeChange(MenuBuilder menu) { } - public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + public boolean onOpenSubMenu(MenuBuilder subMenu) { // Set a simple callback for the submenu subMenu.setCallback(this); @@ -3127,44 +3246,4 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void sendCloseSystemWindows(String reason) { PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); } - - private class ActionButtonSubmenu extends MenuPopupHelper implements Runnable { - private SubMenuBuilder mSubMenu; - - public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) { - super(context, subMenu); - mSubMenu = subMenu; - - MenuBuilder parentMenu = subMenu.getRootMenu(); - MenuItemImpl item = (MenuItemImpl) subMenu.getItem(); - if (!item.isActionButton()) { - // Give a reasonable anchor to nested submenus. - ActionMenuView amv = (ActionMenuView) parentMenu.getMenuView( - MenuBuilder.TYPE_ACTION_BUTTON, null); - - View anchor = amv.getOverflowButton(); - if (anchor == null) { - anchor = amv; - } - setAnchorView(anchor); - } - } - - @Override - public void onDismiss() { - super.onDismiss(); - mSubMenu.getCallback().onCloseSubMenu(mSubMenu); - mActionButtonPopup = null; - } - - @Override - public void run() { - if (tryShow()) { - Callback cb = getCallback(); - if (cb != null && !isDestroyed()) { - cb.onMenuOpened(FEATURE_ACTION_BAR, mSubMenu); - } - } - } - } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 8d8ff96..8520219 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -23,6 +23,7 @@ import android.app.IUiModeManager; import android.app.UiModeManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -113,6 +114,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_POINTER; +import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.KeyCharacterMap.FallbackAction; @@ -177,14 +179,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { // responsible for power management when displayed. static final int KEYGUARD_LAYER = 15; static final int KEYGUARD_DIALOG_LAYER = 16; + // the navigation bar, if available, shows atop most things + static final int NAVIGATION_BAR_LAYER = 17; // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - static final int DRAG_LAYER = 17; + static final int DRAG_LAYER = 18; // things in here CAN NOT take focus, but are shown on top of everything else. - static final int SYSTEM_OVERLAY_LAYER = 18; - static final int SECURE_SYSTEM_OVERLAY_LAYER = 19; + static final int SYSTEM_OVERLAY_LAYER = 19; + static final int SECURE_SYSTEM_OVERLAY_LAYER = 20; // the (mouse) pointer layer - static final int POINTER_LAYER = 20; + static final int POINTER_LAYER = 21; static final int APPLICATION_MEDIA_SUBLAYER = -2; static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; @@ -231,6 +235,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mStatusBarCanHide; int mStatusBarHeight; final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>(); + WindowState mNavigationBar = null; + WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; @@ -341,6 +347,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mLockScreenTimeout; boolean mLockScreenTimerActive; + // visual screen saver support + int mScreenSaverTimeout; + boolean mScreenSaverEnabled = false; + // Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.) int mEndcallBehavior; @@ -396,6 +406,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.DEFAULT_INPUT_METHOD), false, this); resolver.registerContentObserver(Settings.System.getUriFor( "fancy_rotation_anim"), false, this); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.Secure.DREAM_TIMEOUT), false, this); updateSettings(); } @@ -735,12 +747,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeEnabledVibePattern); - // watch for HDMI plug messages if the hdmi switch exists - if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) { - mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi"); - } - mHdmiPlugged = !readHdmiState(); - setHdmiPlugged(!mHdmiPlugged); + // Controls rotation and the like. + initializeHdmiState(); } public void setInitialDisplaySize(int width, int height) { @@ -845,6 +853,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHasSoftInput = hasSoftInput; updateRotation = true; } + + mScreenSaverTimeout = Settings.System.getInt(resolver, + Settings.Secure.DREAM_TIMEOUT, 0); + mScreenSaverEnabled = true; + updateScreenSaverTimeoutLocked(); } if (updateRotation) { updateRotation(0); @@ -1056,6 +1069,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { return DRAG_LAYER; case TYPE_POINTER: return POINTER_LAYER; + case TYPE_NAVIGATION_BAR: + return NAVIGATION_BAR_LAYER; } Log.e(TAG, "Unknown window type: " + type); return APPLICATION_LAYER; @@ -1252,6 +1267,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; break; + case TYPE_NAVIGATION_BAR: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.STATUS_BAR_SERVICE, + "PhoneWindowManager"); + mNavigationBar = win; + if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar); + break; case TYPE_STATUS_BAR_PANEL: mContext.enforceCallingOrSelfPermission( android.Manifest.permission.STATUS_BAR_SERVICE, @@ -1278,9 +1300,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void removeWindowLw(WindowState win) { if (mStatusBar == win) { mStatusBar = null; - } - else if (mKeyguard == win) { + } else if (mKeyguard == win) { mKeyguard = null; + } else if (mNavigationBar == win) { + mNavigationBar = null; } else { mStatusBarPanels.remove(win); } @@ -1647,17 +1670,48 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDockBottom = mContentBottom = mCurBottom = displayHeight; mDockLayer = 0x10000000; + // start with the current dock rect, which will be (0,0,displayWidth,displayHeight) + final Rect pf = mTmpParentFrame; + final Rect df = mTmpDisplayFrame; + final Rect vf = mTmpVisibleFrame; + pf.left = df.left = vf.left = mDockLeft; + pf.top = df.top = vf.top = mDockTop; + pf.right = df.right = vf.right = mDockRight; + pf.bottom = df.bottom = vf.bottom = mDockBottom; + // decide where the status bar goes ahead of time if (mStatusBar != null) { - 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; - + Rect navr = null; + if (mNavigationBar != null) { + mNavigationBar.computeFrameLw(pf, df, vf, vf); + if (mNavigationBar.isVisibleLw()) { + navr = mNavigationBar.getFrameLw(); + + if (navr.top == 0) { + // Navigation bar is vertical + if (mDockLeft == navr.left) { + mDockLeft = navr.right; + } else if (mDockRight == navr.right) { + mDockRight = navr.left; + } + } else { + // Navigation bar horizontal, at bottom + if (mDockBottom == navr.bottom) { + mDockBottom = navr.top; + } + } + } + } + if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + navr); + + // apply navigation bar insets + pf.left = df.left = vf.left = mDockLeft; + pf.top = df.top = vf.top = mDockTop; + pf.right = df.right = vf.right = mDockRight; + pf.bottom = df.bottom = vf.bottom = mDockBottom; + mStatusBar.computeFrameLw(pf, df, vf, vf); + if (mStatusBar.isVisibleLw()) { // If the status bar is hidden, we don't want to cause // windows behind it to scroll. @@ -1668,14 +1722,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // status bar is visible. if (mDockTop == r.top) mDockTop = r.bottom; else if (mDockBottom == r.bottom) mDockBottom = r.top; + mContentTop = mCurTop = mDockTop; mContentBottom = mCurBottom = mDockBottom; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockTop=" + mDockTop - + " mContentTop=" + mContentTop - + " mCurTop=" + mCurTop - + " mDockBottom=" + mDockBottom - + " mContentBottom=" + mContentBottom - + " mCurBottom=" + mCurBottom); + mContentLeft = mCurLeft = mDockLeft; + mContentRight = mCurRight = mDockRight; + + if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " + + String.format( + "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", + mDockLeft, mDockTop, mDockRight, mDockBottom, + mContentLeft, mContentTop, mContentRight, mContentBottom, + mCurLeft, mCurTop, mCurRight, mCurBottom)); } else { // Status bar can't go away; the part of the screen it // covers does not exist for anything behind it. @@ -1685,12 +1743,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { mRestrictedScreenHeight -= (r.bottom-r.top); } + + if (navr != null) { + if (navr.top == 0) { + // Navigation bar is vertical + if (mRestrictedScreenLeft == navr.left) { + mRestrictedScreenLeft = navr.right; + mRestrictedScreenWidth -= (navr.right - navr.left); + } else if ((mRestrictedScreenLeft+mRestrictedScreenWidth) == navr.right) { + mRestrictedScreenWidth -= (navr.right - navr.left); + } + } else { + // Navigation bar horizontal, at bottom + if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { + mRestrictedScreenHeight -= (navr.bottom-navr.top); + } + } + } + mContentTop = mCurTop = mDockTop = mRestrictedScreenTop; mContentBottom = mCurBottom = mDockBottom = mRestrictedScreenTop + mRestrictedScreenHeight; - if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mRestrictedScreenTop=" - + mRestrictedScreenTop - + " mRestrictedScreenHeight=" + mRestrictedScreenHeight); + if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: (" + + mRestrictedScreenLeft + "," + + mRestrictedScreenTop + "," + + (mRestrictedScreenLeft + mRestrictedScreenWidth) + "," + + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")"); } } } @@ -1760,6 +1838,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Rect cf = mTmpContentFrame; final Rect vf = mTmpVisibleFrame; + final boolean hasNavBar = (mNavigationBar != null && mNavigationBar.isVisibleLw()); + if (attrs.type == TYPE_INPUT_METHOD) { pf.left = df.left = cf.left = vf.left = mDockLeft; pf.top = df.top = cf.top = vf.top = mDockTop; @@ -1773,6 +1853,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN"); // 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 @@ -1782,10 +1865,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { // 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 = mRestrictedScreenLeft; - pf.top = df.top = mRestrictedScreenTop; - pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; - pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; + if (attrs.type == TYPE_STATUS_BAR_PANEL + || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { + // Status bar panels are the only windows who can go on top of + // the status bar. They are protected by the STATUS_BAR_SERVICE + // permission, so they have the same privileges as the status + // bar itself. + // + // However, they should still dodge the navigation bar if it exists. A + // straightforward way to do this is to only allow the status bar panels to + // extend to the extrema of the allowable region for the IME dock. + + pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; + pf.top = df.top = mUnrestrictedScreenTop; + pf.right = df.right = hasNavBar + ? mDockRight + : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = hasNavBar + ? mDockBottom + : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + + } else { + pf.left = df.left = mRestrictedScreenLeft; + pf.top = df.top = mRestrictedScreenTop; + pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; + pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; + } if (adjust != SOFT_INPUT_ADJUST_RESIZE) { cf.left = mDockLeft; cf.top = mDockTop; @@ -1807,15 +1912,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); // A window that has requested to fill the entire screen just // gets everything, period. - if (attrs.type == TYPE_STATUS_BAR_PANEL) { - pf.left = df.left = cf.left = mUnrestrictedScreenLeft; + if (attrs.type == TYPE_STATUS_BAR_PANEL + || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { + pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; pf.top = df.top = cf.top = mUnrestrictedScreenTop; - pf.right = df.right = cf.right - = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; - pf.bottom = df.bottom = cf.bottom - = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + pf.right = df.right = cf.right = hasNavBar + ? mDockRight + : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; + pf.bottom = df.bottom = cf.bottom = hasNavBar + ? mDockBottom + : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; + } else { pf.left = df.left = cf.left = mRestrictedScreenLeft; pf.top = df.top = cf.top = mRestrictedScreenTop; @@ -1832,10 +1943,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { vf.set(cf); } } else if (attached != null) { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); // A child window should be placed inside of the same visible // frame that its parent had. setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf); } else { + if (DEBUG_LAYOUT) + Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); // Otherwise, a normal window must be placed inside the content // of all screen decorations. if (attrs.type == TYPE_STATUS_BAR_PANEL) { @@ -1884,6 +1999,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + + " attach=" + attached + " type=" + attrs.type + + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); @@ -2158,32 +2275,38 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - boolean readHdmiState() { - final String filename = "/sys/class/switch/hdmi/state"; - FileReader reader = null; - try { - reader = new FileReader(filename); - char[] buf = new char[15]; - int n = reader.read(buf); - if (n > 1) { - return 0 != Integer.parseInt(new String(buf, 0, n-1)); - } else { - return false; - } - } catch (IOException ex) { - Slog.d(TAG, "couldn't read hdmi state from " + filename + ": " + ex); - return false; - } catch (NumberFormatException ex) { - Slog.d(TAG, "couldn't read hdmi state from " + filename + ": " + ex); - return false; - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException ex) { + void initializeHdmiState() { + boolean plugged = false; + // watch for HDMI plug messages if the hdmi switch exists + if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) { + mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi"); + + final String filename = "/sys/class/switch/hdmi/state"; + FileReader reader = null; + try { + reader = new FileReader(filename); + char[] buf = new char[15]; + int n = reader.read(buf); + if (n > 1) { + plugged = 0 != Integer.parseInt(new String(buf, 0, n-1)); + } + } catch (IOException ex) { + Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex); + } catch (NumberFormatException ex) { + Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ex) { + } } } } + // This dance forces the code in setHdmiPlugged to run. + // Always do this so the sticky intent is stuck (to false) if there is no hdmi. + mHdmiPlugged = !plugged; + setHdmiPlugged(!mHdmiPlugged); } /** @@ -2520,6 +2643,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOn = false; updateOrientationListenerLp(); updateLockScreenTimeout(); + updateScreenSaverTimeoutLocked(); } } @@ -2531,6 +2655,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenOn = true; updateOrientationListenerLp(); updateLockScreenTimeout(); + updateScreenSaverTimeoutLocked(); } } @@ -2805,6 +2930,69 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } + + if (mStatusBarService != null) { + try { + mStatusBarService.userActivity(); + } catch (RemoteException ex) {} + } + + synchronized (mLock) { + updateScreenSaverTimeoutLocked(); + } + } + + Runnable mScreenSaverActivator = new Runnable() { + public void run() { + synchronized (this) { + if (!(mScreenSaverEnabled && mScreenOn)) { + Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?"); + return; + } + + if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland"); + try { + String component = Settings.System.getString( + mContext.getContentResolver(), Settings.Secure.DREAM_COMPONENT); + if (component != null) { + ComponentName cn = ComponentName.unflattenFromString(component); + Intent intent = new Intent(Intent.ACTION_MAIN) + .setComponent(cn) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_NO_USER_ACTION + | Intent.FLAG_ACTIVITY_SINGLE_TOP); + mContext.startActivity(intent); + } else { + Log.e(TAG, "Couldn't start screen saver: none selected"); + } + } catch (android.content.ActivityNotFoundException exc) { + // no screensaver? give up + Log.e(TAG, "Couldn't start screen saver: none installed"); + } + } + } + }; + + // Must call while holding mLock + private void updateScreenSaverTimeoutLocked() { + synchronized (mScreenSaverActivator) { + mHandler.removeCallbacks(mScreenSaverActivator); + if (mScreenSaverEnabled && mScreenOn && mScreenSaverTimeout > 0) { + if (localLOGV) + Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now"); + mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout); + } else { + if (localLOGV) { + if (mScreenSaverTimeout == 0) + Log.v(TAG, "screen saver disabled by user"); + else if (!mScreenOn) + Log.v(TAG, "screen saver disabled while screen off"); + else + Log.v(TAG, "screen saver disabled by wakelock"); + } + } + } } Runnable mScreenLockTimeout = new Runnable() { @@ -3000,10 +3188,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } + public void screenOnStartedLw() { + // The window manager has just grabbed a wake lock. This is our cue to disable the screen + // saver. + synchronized (mLock) { + mScreenSaverEnabled = false; + } + } + public void screenOnStoppedLw() { - if (!mKeyguardMediator.isShowingAndNotHidden() && mPowerManager.isScreenOn()) { - long curTime = SystemClock.uptimeMillis(); - mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); + if (mPowerManager.isScreenOn()) { + if (!mKeyguardMediator.isShowingAndNotHidden()) { + long curTime = SystemClock.uptimeMillis(); + mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); + } + + synchronized (mLock) { + // even if the keyguard is up, now that all the wakelocks have been released, we + // should re-enable the screen saver + mScreenSaverEnabled = true; + updateScreenSaverTimeoutLocked(); + } } } |