diff options
Diffstat (limited to 'policy')
13 files changed, 1129 insertions, 536 deletions
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java index 0ce4b12..bfbd60d 100644 --- a/policy/src/com/android/internal/policy/impl/BarController.java +++ b/policy/src/com/android/internal/policy/impl/BarController.java @@ -108,13 +108,20 @@ public class BarController { if (mWin != null) { if (win != null && (win.getAttrs().privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) { - if ((win.getAttrs().flags & mTranslucentWmFlag) != 0) { + int fl = PolicyControl.getWindowFlags(win, null); + if ((fl & mTranslucentWmFlag) != 0) { vis |= mTranslucentFlag; } else { vis &= ~mTranslucentFlag; } + if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) { + vis |= View.SYSTEM_UI_TRANSPARENT; + } else { + vis &= ~View.SYSTEM_UI_TRANSPARENT; + } } else { vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag); + vis = (vis & ~View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT); } } return vis; @@ -230,7 +237,8 @@ public class BarController { vis |= mTransientFlag; // ignore clear requests until transition completes vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile } - if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0) { + if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 || + ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) { mLastTranslucent = SystemClock.uptimeMillis(); } return vis; diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 371fa0f..673ce0b 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -423,36 +423,38 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } private void addUsersToMenu(ArrayList<Action> items) { - List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) - .getUsers(); - if (users.size() > 1) { + UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + if (um.isUserSwitcherEnabled()) { + List<UserInfo> users = um.getUsers(); UserInfo currentUser = getCurrentUser(); for (final UserInfo user : users) { - boolean isCurrentUser = currentUser == null - ? user.id == 0 : (currentUser.id == user.id); - Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath) - : null; - SinglePressAction switchToUser = new SinglePressAction( - com.android.internal.R.drawable.ic_menu_cc, icon, - (user.name != null ? user.name : "Primary") - + (isCurrentUser ? " \u2714" : "")) { - public void onPress() { - try { - ActivityManagerNative.getDefault().switchUser(user.id); - } catch (RemoteException re) { - Log.e(TAG, "Couldn't switch user " + re); + if (user.supportsSwitchTo()) { + boolean isCurrentUser = currentUser == null + ? user.id == 0 : (currentUser.id == user.id); + Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath) + : null; + SinglePressAction switchToUser = new SinglePressAction( + com.android.internal.R.drawable.ic_menu_cc, icon, + (user.name != null ? user.name : "Primary") + + (isCurrentUser ? " \u2714" : "")) { + public void onPress() { + try { + ActivityManagerNative.getDefault().switchUser(user.id); + } catch (RemoteException re) { + Log.e(TAG, "Couldn't switch user " + re); + } } - } - public boolean showDuringKeyguard() { - return true; - } + public boolean showDuringKeyguard() { + return true; + } - public boolean showBeforeProvisioning() { - return false; - } - }; - items.add(switchToUser); + public boolean showBeforeProvisioning() { + return false; + } + }; + items.add(switchToUser); + } } } } @@ -651,7 +653,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac icon.setImageDrawable(mIcon); icon.setScaleType(ScaleType.CENTER_CROP); } else if (mIconResId != 0) { - icon.setImageDrawable(context.getResources().getDrawable(mIconResId)); + icon.setImageDrawable(context.getDrawable(mIconResId)); } if (mMessage != null) { messageView.setText(mMessage); @@ -741,7 +743,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac boolean on = ((mState == State.On) || (mState == State.TurningOn)); if (icon != null) { - icon.setImageDrawable(context.getResources().getDrawable( + icon.setImageDrawable(context.getDrawable( (on ? mEnabledIconResId : mDisabledIconResid))); icon.setEnabled(enabled); } diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java index a47c904..82f26ad 100644 --- a/policy/src/com/android/internal/policy/impl/IconUtilities.java +++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java @@ -24,22 +24,13 @@ import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; -import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.TableMaskFilter; -import android.graphics.Typeface; -import android.text.Layout.Alignment; -import android.text.StaticLayout; -import android.text.TextPaint; import android.util.DisplayMetrics; -import android.util.Log; import android.util.TypedValue; -import android.view.ContextThemeWrapper; import android.content.res.Resources; import android.content.Context; diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java index b734c41..a4c2ddd 100644 --- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java +++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java @@ -19,6 +19,7 @@ package com.android.internal.policy.impl; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -27,12 +28,12 @@ import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; -import android.text.TextUtils; -import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Slog; +import android.util.SparseBooleanArray; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -46,8 +47,6 @@ import android.widget.FrameLayout; import com.android.internal.R; -import java.util.Arrays; - /** * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden * entering immersive mode. @@ -56,19 +55,19 @@ public class ImmersiveModeConfirmation { private static final String TAG = "ImmersiveModeConfirmation"; private static final boolean DEBUG = false; private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution + private static final String CONFIRMED = "confirmed"; private final Context mContext; private final H mHandler; - private final ArraySet<String> mConfirmedPackages = new ArraySet<String>(); private final long mShowDelayMs; private final long mPanicThresholdMs; + private final SparseBooleanArray mUserPanicResets = new SparseBooleanArray(); + private boolean mConfirmed; private ClingWindowView mClingWindow; - private String mLastPackage; - private String mPromptPackage; private long mPanicTime; - private String mPanicPackage; private WindowManager mWindowManager; + private int mCurrentUserId; public ImmersiveModeConfirmation(Context context) { mContext = context; @@ -85,83 +84,85 @@ public class ImmersiveModeConfirmation { return exit != null ? exit.getDuration() : 0; } - public void loadSetting() { - if (DEBUG) Slog.d(TAG, "loadSetting()"); - mConfirmedPackages.clear(); - String packages = null; + public void loadSetting(int currentUserId) { + mConfirmed = false; + mCurrentUserId = currentUserId; + if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s", + mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false))); + String value = null; try { - packages = Settings.Secure.getStringForUser(mContext.getContentResolver(), + value = Settings.Secure.getStringForUser(mContext.getContentResolver(), Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, UserHandle.USER_CURRENT); - if (packages != null) { - mConfirmedPackages.addAll(Arrays.asList(packages.split(","))); - if (DEBUG) Slog.d(TAG, "Loaded mConfirmedPackages=" + mConfirmedPackages); - } + mConfirmed = CONFIRMED.equals(value); + if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed); } catch (Throwable t) { - Slog.w(TAG, "Error loading confirmations, packages=" + packages, t); + Slog.w(TAG, "Error loading confirmations, value=" + value, t); } } private void saveSetting() { if (DEBUG) Slog.d(TAG, "saveSetting()"); try { - final String packages = TextUtils.join(",", mConfirmedPackages); + final String value = mConfirmed ? CONFIRMED : null; Settings.Secure.putStringForUser(mContext.getContentResolver(), Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, - packages, + value, UserHandle.USER_CURRENT); - if (DEBUG) Slog.d(TAG, "Saved packages=" + packages); + if (DEBUG) Slog.d(TAG, "Saved value=" + value); } catch (Throwable t) { - Slog.w(TAG, "Error saving confirmations, mConfirmedPackages=" + mConfirmedPackages, t); + Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t); } } - public void immersiveModeChanged(String pkg, boolean isImmersiveMode) { - if (pkg == null) { - return; - } + public void immersiveModeChanged(String pkg, boolean isImmersiveMode, + boolean userSetupComplete) { mHandler.removeMessages(H.SHOW); if (isImmersiveMode) { - mLastPackage = pkg; - if (DEBUG_SHOW_EVERY_TIME || !mConfirmedPackages.contains(pkg)) { - mHandler.sendMessageDelayed(mHandler.obtainMessage(H.SHOW, pkg), mShowDelayMs); + final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg); + if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s", + disabled, mConfirmed)); + if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) { + mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); } } else { - mLastPackage = null; mHandler.sendEmptyMessage(H.HIDE); } } - public void onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) { - if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { + public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) { + if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { // turning the screen back on within the panic threshold - unconfirmPackage(mPanicPackage); + mHandler.sendEmptyMessage(H.PANIC); + return mClingWindow == null; } if (isScreenOn && inImmersiveMode) { // turning the screen off, remember if we were in immersive mode mPanicTime = time; - mPanicPackage = mLastPackage; } else { mPanicTime = 0; - mPanicPackage = null; } + return false; } public void confirmCurrentPrompt() { - mHandler.post(confirmAction(mPromptPackage)); + if (mClingWindow != null) { + if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()"); + mHandler.post(mConfirm); + } } - private void unconfirmPackage(String pkg) { - if (pkg != null) { - if (DEBUG) Slog.d(TAG, "Unconfirming immersive mode confirmation for " + pkg); - mConfirmedPackages.remove(pkg); - saveSetting(); - } + private void handlePanic() { + if (DEBUG) Slog.d(TAG, "handlePanic()"); + if (mUserPanicResets.get(mCurrentUserId, false)) return; // already reset for panic + mUserPanicResets.put(mCurrentUserId, true); + mConfirmed = false; + saveSetting(); } private void handleHide() { if (mClingWindow != null) { - if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation for " + mPromptPackage); + if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); mWindowManager.removeView(mClingWindow); mClingWindow = null; } @@ -297,11 +298,10 @@ public class ImmersiveModeConfirmation { } } - private void handleShow(String pkg) { - mPromptPackage = pkg; - if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation for " + pkg); + private void handleShow() { + if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation"); - mClingWindow = new ClingWindowView(mContext, confirmAction(pkg)); + mClingWindow = new ClingWindowView(mContext, mConfirm); // we will be hiding the nav bar, so layout as if it's already hidden mClingWindow.setSystemUiVisibility( @@ -313,33 +313,35 @@ public class ImmersiveModeConfirmation { mWindowManager.addView(mClingWindow, lp); } - private Runnable confirmAction(final String pkg) { - return new Runnable() { - @Override - public void run() { - if (pkg != null && !mConfirmedPackages.contains(pkg)) { - if (DEBUG) Slog.d(TAG, "Confirming immersive mode for " + pkg); - mConfirmedPackages.add(pkg); - saveSetting(); - } - handleHide(); + private final Runnable mConfirm = new Runnable() { + @Override + public void run() { + if (DEBUG) Slog.d(TAG, "mConfirm.run()"); + if (!mConfirmed) { + mConfirmed = true; + saveSetting(); } - }; - } + handleHide(); + } + }; private final class H extends Handler { - private static final int SHOW = 0; - private static final int HIDE = 1; + private static final int SHOW = 1; + private static final int HIDE = 2; + private static final int PANIC = 3; @Override public void handleMessage(Message msg) { switch(msg.what) { case SHOW: - handleShow((String)msg.obj); + handleShow(); break; case HIDE: handleHide(); break; + case PANIC: + handlePanic(); + break; } } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java index 968976b..df6fca4c 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java +++ b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java @@ -16,8 +16,6 @@ package com.android.internal.policy.impl; -import java.util.Map; - import android.content.Context; import android.util.AttributeSet; import android.view.View; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index c670b5c..2fea785 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -22,8 +22,6 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.*; -import android.view.ViewConfiguration; - import com.android.internal.R; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; @@ -38,8 +36,10 @@ import com.android.internal.widget.ActionBarContainer; import com.android.internal.widget.ActionBarContextView; import com.android.internal.widget.ActionBarOverlayLayout; import com.android.internal.widget.ActionBarView; +import com.android.internal.widget.DecorContentParent; import com.android.internal.widget.SwipeDismissLayout; +import android.app.ActivityManager; import android.app.KeyguardManager; import android.content.Context; import android.content.pm.ActivityInfo; @@ -48,23 +48,26 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; -import android.os.Debug; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.transition.Scene; +import android.transition.Transition; +import android.transition.TransitionInflater; +import android.transition.TransitionManager; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; -import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; @@ -82,6 +85,7 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewManager; import android.view.ViewParent; @@ -113,7 +117,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static String TAG = "PhoneWindow"; private final static boolean SWEEP_OPEN_MENU = false; - /** * Simple callback used by the context menu and its submenus. The options * menu submenus do not use this (their behavior is more complex). @@ -136,19 +139,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ViewGroup mContentParent; SurfaceHolder.Callback2 mTakeSurfaceCallback; - + InputQueue.Callback mTakeInputQueueCallback; - + private boolean mIsFloating; private LayoutInflater mLayoutInflater; private TextView mTitleView; - - private ActionBarView mActionBar; + + private DecorContentParent mDecorContentParent; private ActionMenuPresenterCallback mActionMenuPresenterCallback; private PanelMenuPresenterCallback mPanelMenuPresenterCallback; + private TransitionManager mTransitionManager; + private Scene mContentScene; + // The icon resource has been explicitly set elsewhere // and should not be overwritten with a default. static final int FLAG_RESOURCE_SET_ICON = 1 << 0; @@ -197,6 +203,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private int mFrameResource = 0; private int mTextColor = 0; + private int mStatusBarColor = 0; + private int mNavigationBarColor = 0; + private boolean mForcedStatusBarColor = false; + private boolean mForcedNavigationBarColor = false; private CharSequence mTitle = null; @@ -229,6 +239,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } }; + private Transition mEnterTransition; + private Transition mExitTransition; + private Transition mSharedElementEnterTransition; + private Transition mSharedElementExitTransition; + private Boolean mAllowExitTransitionOverlap; + private Boolean mAllowEnterTransitionOverlap; + static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); @@ -298,13 +315,38 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public TransitionManager getTransitionManager() { + return mTransitionManager; + } + + @Override + public void setTransitionManager(TransitionManager tm) { + mTransitionManager = tm; + } + + @Override + public Scene getContentScene() { + return mContentScene; + } + + @Override public void setContentView(int layoutResID) { + // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window + // decor, when theme attributes and the like are crystalized. Do not check the feature + // before this happens. if (mContentParent == null) { installDecor(); - } else { + } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } - mLayoutInflater.inflate(layoutResID, mContentParent); + + if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { + final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, + getContext()); + transitionTo(newScene); + } else { + mLayoutInflater.inflate(layoutResID, mContentParent); + } final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); @@ -318,12 +360,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void setContentView(View view, ViewGroup.LayoutParams params) { + // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window + // decor, when theme attributes and the like are crystalized. Do not check the feature + // before this happens. if (mContentParent == null) { installDecor(); - } else { + } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); } - mContentParent.addView(view, params); + + if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { + view.setLayoutParams(params); + final Scene newScene = new Scene(mContentParent, view); + transitionTo(newScene); + } else { + mContentParent.addView(view, params); + } final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); @@ -335,6 +387,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent == null) { installDecor(); } + if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { + // TODO Augment the scenes/transitions API to support this. + throw new UnsupportedOperationException( + "addContentView does not support content transitions"); + } mContentParent.addView(view, params); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { @@ -342,6 +399,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + private void transitionTo(Scene scene) { + if (mContentScene == null) { + scene.enter(); + } else { + mTransitionManager.transitionTo(scene); + } + mContentScene = scene; + } + @Override public View getCurrentFocus() { return mDecor != null ? mDecor.findFocus() : null; @@ -351,11 +417,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void takeSurface(SurfaceHolder.Callback2 callback) { mTakeSurfaceCallback = callback; } - + public void takeInputQueue(InputQueue.Callback callback) { mTakeInputQueueCallback = callback; } - + @Override public boolean isFloating() { return mIsFloating; @@ -376,13 +442,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setTitle(CharSequence title) { if (mTitleView != null) { mTitleView.setText(title); - } else if (mActionBar != null) { - mActionBar.setWindowTitle(title); + } else if (mDecorContentParent != null) { + mDecorContentParent.setWindowTitle(title); } mTitle = title; } @Override + @Deprecated public void setTitleColor(int textColor) { if (mTitleView != null) { mTitleView.setTextColor(textColor); @@ -423,10 +490,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final boolean isActionBarMenu = (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR); - if (isActionBarMenu && mActionBar != null) { + if (isActionBarMenu && mDecorContentParent != null) { // Enforce ordering guarantees around events so that the action bar never // dispatches menu-related events before the panel is prepared. - mActionBar.setMenuPrepared(); + mDecorContentParent.setMenuPrepared(); } if (st.createdPanelView == null) { @@ -438,11 +505,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - if (isActionBarMenu && mActionBar != null) { + if (isActionBarMenu && mDecorContentParent != null) { if (mActionMenuPresenterCallback == null) { mActionMenuPresenterCallback = new ActionMenuPresenterCallback(); } - mActionBar.setMenu(st.menu, mActionMenuPresenterCallback); + mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback); } // Call callback, and return if it doesn't want to display menu. @@ -454,9 +521,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Ditch the menu created above st.setMenu(null); - if (isActionBarMenu && mActionBar != null) { + if (isActionBarMenu && mDecorContentParent != null) { // Don't show it in the action bar either - mActionBar.setMenu(null, mActionMenuPresenterCallback); + mDecorContentParent.setMenu(null, mActionMenuPresenterCallback); } return false; @@ -479,10 +546,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) { - if (isActionBarMenu && mActionBar != null) { + if (isActionBarMenu && mDecorContentParent != null) { // The app didn't want to show the menu for now but it still exists. // Clear it out of the action bar. - mActionBar.setMenu(null, mActionMenuPresenterCallback); + mDecorContentParent.setMenu(null, mActionMenuPresenterCallback); } st.menu.startDispatchingItemsChanged(); return false; @@ -507,7 +574,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public void onConfigurationChanged(Configuration newConfig) { // Action bars handle their own menu state - if (mActionBar == null) { + if (mDecorContentParent == null) { PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); if ((st != null) && (st.menu != null)) { if (st.isOpen) { @@ -559,12 +626,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void openPanel(int featureId, KeyEvent event) { - if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved() && + if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null && + mDecorContentParent.canShowOverflowMenu() && !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { - if (mActionBar.getVisibility() == View.VISIBLE) { - mActionBar.showOverflowMenu(); - } + mDecorContentParent.showOverflowMenu(); } else { openPanel(getPanelState(featureId, true), event); } @@ -641,7 +706,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Otherwise, set the normal panel background backgroundResId = st.background; } - st.decorView.setWindowBackground(getContext().getResources().getDrawable( + st.decorView.setWindowBackground(getContext().getDrawable( backgroundResId)); ViewParent shownPanelParent = st.shownPanelView.getParent(); @@ -693,10 +758,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void closePanel(int featureId) { - if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved() && + if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null && + mDecorContentParent.canShowOverflowMenu() && !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { - mActionBar.hideOverflowMenu(); + mDecorContentParent.hideOverflowMenu(); } else if (featureId == FEATURE_CONTEXT_MENU) { closeContextMenu(); } else { @@ -718,7 +783,7 @@ 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()) { + mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) { checkCloseActionMenu(st.menu); return; } @@ -764,7 +829,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } mClosingActionMenu = true; - mActionBar.dismissPopupMenus(); + mDecorContentParent.dismissPopups(); Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onPanelClosed(FEATURE_ACTION_BAR, menu); @@ -810,7 +875,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Prepare the options panel if we have an action bar if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL) - && mActionBar != null) { + && mDecorContentParent != null) { st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false); if (st != null) { st.isPrepared = false; @@ -857,17 +922,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean playSoundEffect = false; final PanelFeatureState st = getPanelState(featureId, true); - if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null && - mActionBar.isOverflowReserved() && + if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null && + mDecorContentParent.canShowOverflowMenu() && !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) { - if (mActionBar.getVisibility() == View.VISIBLE) { - if (!mActionBar.isOverflowMenuShowing()) { - if (!isDestroyed() && preparePanel(st, event)) { - playSoundEffect = mActionBar.showOverflowMenu(); - } - } else { - playSoundEffect = mActionBar.hideOverflowMenu(); + if (!mDecorContentParent.isOverflowMenuShowing()) { + if (!isDestroyed() && preparePanel(st, event)) { + playSoundEffect = mDecorContentParent.showOverflowMenu(); } + } else { + playSoundEffect = mDecorContentParent.hideOverflowMenu(); } } else { if (st.isOpen || st.isHandled) { @@ -980,7 +1043,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { st.isHandled = true; // Only close down the menu if we don't have an action bar keeping it open. - if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mActionBar == null) { + if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) { closePanel(st, true); } } @@ -1002,7 +1065,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean res = st.menu.performIdentifierAction(id, flags); // Only close down the menu if we don't have an action bar keeping it open. - if (mActionBar == null) { + if (mDecorContentParent == null) { closePanel(st, true); } @@ -1037,12 +1100,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } private void reopenMenu(boolean toggleMenuMode) { - if (mActionBar != null && mActionBar.isOverflowReserved() && + if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() && (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() || - mActionBar.isOverflowMenuShowPending())) { + mDecorContentParent.isOverflowMenuShowPending())) { final Callback cb = getCallback(); - if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) { - if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) { + if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) { + if (cb != null && !isDestroyed()) { // If we have a menu invalidation pending, do it now. if (mInvalidatePanelMenuPosted && (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) { @@ -1057,11 +1120,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (st.menu != null && !st.refreshMenuContent && cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) { cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu); - mActionBar.showOverflowMenu(); + mDecorContentParent.showOverflowMenu(); } } } else { - mActionBar.hideOverflowMenu(); + mDecorContentParent.hideOverflowMenu(); if (cb != null && !isDestroyed()) { final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true); cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu); @@ -1098,7 +1161,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // If we have an action bar, initialize the menu with a context themed for it. if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) && - mActionBar != null) { + mDecorContentParent != null) { TypedValue outValue = new TypedValue(); Resources.Theme currentTheme = context.getTheme(); currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme, @@ -1226,7 +1289,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (st.resid != resId) { st.resid = resId; st.uri = null; - st.local = getContext().getResources().getDrawable(resId); + st.local = getContext().getDrawable(resId); updateDrawable(featureId, st, false); } } else { @@ -1443,8 +1506,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mIconRes = resId; mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON; mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK; - if (mActionBar != null) { - mActionBar.setIcon(resId); + if (mDecorContentParent != null) { + mDecorContentParent.setIcon(resId); } } @@ -1454,13 +1517,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } mIconRes = resId; - if (mActionBar != null && (!mActionBar.hasIcon() || + if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() || (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) { if (resId != 0) { - mActionBar.setIcon(resId); + mDecorContentParent.setIcon(resId); mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK; } else { - mActionBar.setIcon(getContext().getPackageManager().getDefaultActivityIcon()); + mDecorContentParent.setIcon( + getContext().getPackageManager().getDefaultActivityIcon()); mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; } } @@ -1470,8 +1534,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setLogo(int resId) { mLogoRes = resId; mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO; - if (mActionBar != null) { - mActionBar.setLogo(resId); + if (mDecorContentParent != null) { + mDecorContentParent.setLogo(resId); } } @@ -1481,8 +1545,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } mLogoRes = resId; - if (mActionBar != null && !mActionBar.hasLogo()) { - mActionBar.setLogo(resId); + if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) { + mDecorContentParent.setLogo(resId); } } @@ -1739,9 +1803,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { outState.putSparseParcelableArray(PANELS_TAG, panelStates); } - if (mActionBar != null) { + if (mDecorContentParent != null) { SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>(); - mActionBar.saveHierarchyState(actionBarStates); + mDecorContentParent.saveToolbarHierarchyState(actionBarStates); outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates); } @@ -1780,11 +1844,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { restorePanelState(panelStates); } - if (mActionBar != null) { + if (mDecorContentParent != null) { SparseArray<Parcelable> actionBarStates = savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG); if (actionBarStates != null) { - mActionBar.restoreHierarchyState(actionBarStates); + mDecorContentParent.restoreToolbarHierarchyState(actionBarStates); } else { Log.w(TAG, "Missing saved instance states for action bar views! " + "State will not be restored."); @@ -1914,7 +1978,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } - private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { + private final class DecorView extends FrameLayout implements RootViewSurfaceTaker, + View.OnSystemUiVisibilityChangeListener { /* package */int mDefaultOpacity = PixelFormat.OPAQUE; /** The feature ID of the panel, or -1 if this is the application's DecorView */ @@ -1944,6 +2009,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // View added at runtime to draw under the navigation bar area private View mNavigationGuard; + private View mStatusColorView; + private View mNavigationColorView; + + private int mLastTopInset = 0; + private int mLastBottomInset = 0; + private int mLastSystemUiVisibility = 0; + + public DecorView(Context context, int featureId) { super(context); mFeatureId = featureId; @@ -2049,12 +2122,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } public boolean superDispatchKeyEvent(KeyEvent event) { - if (super.dispatchKeyEvent(event)) { - return true; - } - - // Not handled by the view hierarchy, does the action bar want it - // to cancel out of something special? + // Give priority to closing action modes if applicable. if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { final int action = event.getAction(); // Back cancels action modes first. @@ -2064,17 +2132,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } return true; } - - // Next collapse any expanded action views. - if (mActionBar != null && mActionBar.hasExpandedActionView()) { - if (action == KeyEvent.ACTION_UP) { - mActionBar.collapseActionView(); - } - return true; - } } - return false; + return super.dispatchKeyEvent(event); } public boolean superDispatchKeyShortcutEvent(KeyEvent event) { @@ -2242,7 +2302,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mMenuBackground == null && mFeatureId < 0 && getAttributes().height == WindowManager.LayoutParams.MATCH_PARENT) { - mMenuBackground = getContext().getResources().getDrawable( + mMenuBackground = getContext().getDrawable( com.android.internal.R.drawable.menu_background); } if (mMenuBackground != null) { @@ -2509,8 +2569,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public void onSystemUiVisibilityChange(int visible) { + mLastSystemUiVisibility = visible; + updateColorViews(null /* insets */); + } + + @Override protected boolean fitSystemWindows(Rect insets) { mFrameOffsets.set(insets); + updateColorViews(insets); updateStatusGuard(insets); updateNavigationGuard(insets); if (getForeground() != null) { @@ -2519,6 +2586,57 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return super.fitSystemWindows(insets); } + @Override + public boolean isTransitionGroup() { + return false; + } + + private void updateColorViews(Rect insets) { + if (mIsFloating || !ActivityManager.isHighEndGfx()) { + // No colors on floating windows or low end devices :( + return; + } + if (insets != null) { + mLastTopInset = insets.top; + mLastBottomInset = insets.bottom; + } + mStatusColorView = updateColorViewInt(mStatusColorView, + SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, + mStatusBarColor, mLastTopInset, Gravity.TOP); + mNavigationColorView = updateColorViewInt(mNavigationColorView, + SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, + mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM); + } + + private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag, + int color, int height, int verticalGravity) { + boolean show = height > 0 && (mLastSystemUiVisibility & systemUiHideFlag) == 0 + && (getAttributes().flags & translucentFlag) == 0 + && (color & Color.BLACK) != 0 + && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; + + if (view == null) { + if (show) { + view = new View(mContext); + view.setBackgroundColor(color); + addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height, + Gravity.START | verticalGravity)); + } + } else { + int vis = show ? VISIBLE : INVISIBLE; + view.setVisibility(vis); + if (show) { + LayoutParams lp = (LayoutParams) view.getLayoutParams(); + if (lp.height != height) { + lp.height = height; + view.setLayoutParams(lp); + } + view.setBackgroundColor(color); + } + } + return view; + } + private void updateStatusGuard(Rect insets) { boolean showStatusGuard = false; // Show the status guard when the non-overlay contextual action bar is showing @@ -2538,9 +2656,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mStatusGuard = new View(mContext); mStatusGuard.setBackgroundColor(mContext.getResources() .getColor(R.color.input_method_navigation_guard)); - addView(mStatusGuard, new LayoutParams( - LayoutParams.MATCH_PARENT, mlp.topMargin, - Gravity.START | Gravity.TOP)); + addView(mStatusGuard, indexOfChild(mStatusColorView), + new LayoutParams(LayoutParams.MATCH_PARENT, mlp.topMargin, + Gravity.START | Gravity.TOP)); } else { LayoutParams lp = (LayoutParams) mStatusGuard.getLayoutParams(); if (lp.height != mlp.topMargin) { @@ -2585,7 +2703,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mNavigationGuard = new View(mContext); mNavigationGuard.setBackgroundColor(mContext.getResources() .getColor(R.color.input_method_navigation_guard)); - addView(mNavigationGuard, new LayoutParams( + addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams( LayoutParams.MATCH_PARENT, insets.bottom, Gravity.START | Gravity.BOTTOM)); } else { @@ -2711,8 +2829,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { cb.onDetachedFromWindow(); } - if (mActionBar != null) { - mActionBar.dismissPopupMenus(); + if (mDecorContentParent != null) { + mDecorContentParent.dismissPopups(); } if (mActionModePopup != null) { @@ -2919,6 +3037,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor, mFixedHeightMinor); } + if (a.getBoolean(com.android.internal.R.styleable.Window_windowContentTransitions, false)) { + requestFeature(FEATURE_CONTENT_TRANSITIONS); + } if (a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) { if (mOutsetBottom == null) mOutsetBottom = new TypedValue(); a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, mOutsetBottom); @@ -2928,6 +3049,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final int targetSdk = context.getApplicationInfo().targetSdkVersion; final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB; final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; + final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.L; final boolean targetHcNeedsOptions = context.getResources().getBoolean( com.android.internal.R.bool.target_honeycomb_needs_options_menu); final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE); @@ -2937,7 +3059,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); } - + + // Non-floating windows on high end devices must put up decor beneath the system bars and + // therefore must know about visibility changes of those. + if (!mIsFloating && ActivityManager.isHighEndGfx()) { + if (!targetPreL && a.getBoolean( + com.android.internal.R.styleable.Window_windowDrawsSystemBarBackgrounds, + false)) { + setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags()); + } + decor.setOnSystemUiVisibilityChangeListener(decor); + } + if (!mForcedStatusBarColor) { + mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000); + } + if (!mForcedNavigationBarColor) { + mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000); + } + if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { if (a.getBoolean( @@ -3078,12 +3218,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (getContainer() == null) { Drawable drawable = mBackgroundDrawable; if (mBackgroundResource != 0) { - drawable = getContext().getResources().getDrawable(mBackgroundResource); + drawable = getContext().getDrawable(mBackgroundResource); } mDecor.setWindowBackground(drawable); drawable = null; if (mFrameResource != 0) { - drawable = getContext().getResources().getDrawable(mFrameResource); + drawable = getContext().getDrawable(mFrameResource); } mDecor.setWindowFrame(drawable); @@ -3126,105 +3266,127 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Set up decor part of UI to ignore fitsSystemWindows if appropriate. mDecor.makeOptionalFitsSystemWindows(); - mTitleView = (TextView)findViewById(com.android.internal.R.id.title); - if (mTitleView != null) { - mTitleView.setLayoutDirection(mDecor.getLayoutDirection()); - if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { - View titleContainer = findViewById(com.android.internal.R.id.title_container); - if (titleContainer != null) { - titleContainer.setVisibility(View.GONE); - } else { - mTitleView.setVisibility(View.GONE); - } - if (mContentParent instanceof FrameLayout) { - ((FrameLayout)mContentParent).setForeground(null); - } - } else { - mTitleView.setText(mTitle); + final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById( + com.android.internal.R.id.decor_content_parent); + + if (decorContentParent != null) { + mDecorContentParent = decorContentParent; + mDecorContentParent.setWindowCallback(getCallback()); + if (mDecorContentParent.getTitle() == null) { + mDecorContentParent.setWindowTitle(mTitle); } - } else { - mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar); - if (mActionBar != null) { - mActionBar.setWindowCallback(getCallback()); - if (mActionBar.getTitle() == null) { - mActionBar.setWindowTitle(mTitle); - } - final int localFeatures = getLocalFeatures(); - if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) { - mActionBar.initProgress(); - } - if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - mActionBar.initIndeterminateProgress(); - } - final ActionBarOverlayLayout abol = (ActionBarOverlayLayout) findViewById( - com.android.internal.R.id.action_bar_overlay_layout); - if (abol != null) { - abol.setOverlayMode( - (localFeatures & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0); + final int localFeatures = getLocalFeatures(); + for (int i = 0; i < FEATURE_MAX; i++) { + if ((localFeatures & (1 << i)) != 0) { + mDecorContentParent.initFeature(i); } + } - boolean splitActionBar = false; - final boolean splitWhenNarrow = - (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0; - if (splitWhenNarrow) { - splitActionBar = getContext().getResources().getBoolean( - com.android.internal.R.bool.split_action_bar_is_narrow); - } else { - splitActionBar = getWindowStyle().getBoolean( - com.android.internal.R.styleable.Window_windowSplitActionBar, false); + mDecorContentParent.setUiOptions(mUiOptions); + + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 || + (mIconRes != 0 && !mDecorContentParent.hasIcon())) { + mDecorContentParent.setIcon(mIconRes); + } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 && + mIconRes == 0 && !mDecorContentParent.hasIcon()) { + mDecorContentParent.setIcon( + getContext().getPackageManager().getDefaultActivityIcon()); + mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; + } + if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 || + (mLogoRes != 0 && !mDecorContentParent.hasLogo())) { + mDecorContentParent.setLogo(mLogoRes); + } + + // Post the panel invalidate for later; avoid application onCreateOptionsMenu + // being called in the middle of onCreate or similar. + mDecor.post(new Runnable() { + public void run() { + // Invalidate if the panel menu hasn't been created before this. + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); + if (!isDestroyed() && (st == null || st.menu == null)) { + invalidatePanelMenu(FEATURE_ACTION_BAR); + } } - final ActionBarContainer splitView = (ActionBarContainer) findViewById( - com.android.internal.R.id.split_action_bar); - if (splitView != null) { - mActionBar.setSplitView(splitView); - mActionBar.setSplitActionBar(splitActionBar); - mActionBar.setSplitWhenNarrow(splitWhenNarrow); - - final ActionBarContextView cab = (ActionBarContextView) findViewById( - com.android.internal.R.id.action_context_bar); - cab.setSplitView(splitView); - cab.setSplitActionBar(splitActionBar); - cab.setSplitWhenNarrow(splitWhenNarrow); - } else if (splitActionBar) { - Log.e(TAG, "Requested split action bar with " + - "incompatible window decor! Ignoring request."); + }); + } else { + mTitleView = (TextView)findViewById(com.android.internal.R.id.title); + if (mTitleView != null) { + mTitleView.setLayoutDirection(mDecor.getLayoutDirection()); + if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { + View titleContainer = findViewById( + com.android.internal.R.id.title_container); + if (titleContainer != null) { + titleContainer.setVisibility(View.GONE); + } else { + mTitleView.setVisibility(View.GONE); + } + if (mContentParent instanceof FrameLayout) { + ((FrameLayout)mContentParent).setForeground(null); + } + } else { + mTitleView.setText(mTitle); } + } + } - if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 || - (mIconRes != 0 && !mActionBar.hasIcon())) { - mActionBar.setIcon(mIconRes); - } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 && - mIconRes == 0 && !mActionBar.hasIcon()) { - mActionBar.setIcon( - getContext().getPackageManager().getDefaultActivityIcon()); - mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; - } - if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 || - (mLogoRes != 0 && !mActionBar.hasLogo())) { - mActionBar.setLogo(mLogoRes); + // Only inflate or create a new TransitionManager if the caller hasn't + // already set a custom one. + if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { + if (mTransitionManager == null) { + final int transitionRes = getWindowStyle().getResourceId( + com.android.internal.R.styleable.Window_windowContentTransitionManager, + 0); + if (transitionRes != 0) { + final TransitionInflater inflater = TransitionInflater.from(getContext()); + mTransitionManager = inflater.inflateTransitionManager(transitionRes, + mContentParent); + } else { + mTransitionManager = new TransitionManager(); } + } - // Post the panel invalidate for later; avoid application onCreateOptionsMenu - // being called in the middle of onCreate or similar. - mDecor.post(new Runnable() { - public void run() { - // Invalidate if the panel menu hasn't been created before this. - PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); - if (!isDestroyed() && (st == null || st.menu == null)) { - invalidatePanelMenu(FEATURE_ACTION_BAR); - } - } - }); + mEnterTransition = getTransition(mEnterTransition, + com.android.internal.R.styleable.Window_windowEnterTransition); + mExitTransition = getTransition(mExitTransition, + com.android.internal.R.styleable.Window_windowExitTransition); + mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, + com.android.internal.R.styleable.Window_windowSharedElementEnterTransition); + mSharedElementExitTransition = getTransition(mSharedElementExitTransition, + com.android.internal.R.styleable.Window_windowSharedElementExitTransition); + if (mAllowEnterTransitionOverlap == null) { + mAllowEnterTransitionOverlap = getWindowStyle().getBoolean( + com.android.internal.R.styleable. + Window_windowAllowEnterTransitionOverlap, true); + } + if (mAllowExitTransitionOverlap == null) { + mAllowExitTransitionOverlap = getWindowStyle().getBoolean( + com.android.internal.R.styleable. + Window_windowAllowExitTransitionOverlap, true); } } } } + private Transition getTransition(Transition currentValue, int id) { + if (currentValue != null) { + return currentValue; + } + int transitionId = getWindowStyle().getResourceId(id, -1); + Transition transition = null; + if (transitionId != -1 && transitionId != com.android.internal.R.transition.no_transition) { + TransitionInflater inflater = TransitionInflater.from(getContext()); + transition = inflater.inflateTransition(transitionId); + } + return transition; + } + private Drawable loadImageURI(Uri uri) { try { - return Drawable.createFromStream( - getContext().getContentResolver().openInputStream(uri), null); + final Context context = getContext(); + return Drawable.createFromStreamThemed( + context.getContentResolver().openInputStream(uri), null, context.getTheme()); } catch (Exception e) { Log.w(TAG, "Unable to open content: " + uri); } @@ -3391,6 +3553,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon)); } + @Override + protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) { + super.dispatchWindowAttributesChanged(attrs); + if (mDecor != null) { + mDecor.updateColorViews(null /* insets */); + } + } + private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) { if (mCircularProgressBar != null) { return mCircularProgressBar; @@ -3536,6 +3706,72 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return mVolumeControlStreamType; } + private boolean isTranslucent() { + TypedArray a = getWindowStyle(); + return a.getBoolean(a.getResourceId( + com.android.internal.R.styleable.Window_windowIsTranslucent, 0), false); + } + + @Override + public void setEnterTransition(Transition enterTransition) { + mEnterTransition = enterTransition; + } + + @Override + public void setExitTransition(Transition exitTransition) { + mExitTransition = exitTransition; + } + + @Override + public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) { + mSharedElementEnterTransition = sharedElementEnterTransition; + } + + @Override + public void setSharedElementExitTransition(Transition sharedElementExitTransition) { + mSharedElementExitTransition = sharedElementExitTransition; + } + + @Override + public Transition getEnterTransition() { + return mEnterTransition; + } + + @Override + public Transition getExitTransition() { + return mExitTransition; + } + + @Override + public Transition getSharedElementEnterTransition() { + return mSharedElementEnterTransition; + } + + @Override + public Transition getSharedElementExitTransition() { + return mSharedElementExitTransition; + } + + @Override + public void setAllowEnterTransitionOverlap(boolean allow) { + mAllowEnterTransitionOverlap = allow; + } + + @Override + public boolean getAllowEnterTransitionOverlap() { + return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap; + } + + @Override + public void setAllowExitTransitionOverlap(boolean allowExitTransitionOverlap) { + mAllowExitTransitionOverlap = allowExitTransitionOverlap; + } + + @Override + public boolean getAllowExitTransitionOverlap() { + return (mAllowExitTransitionOverlap == null) ? true : mAllowExitTransitionOverlap; + } + private static final class DrawableFeatureState { DrawableFeatureState(int _featureId) { featureId = _featureId; @@ -3969,4 +4205,32 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { void sendCloseSystemWindows(String reason) { PhoneWindowManager.sendCloseSystemWindows(getContext(), reason); } + + @Override + public int getStatusBarColor() { + return mStatusBarColor; + } + + @Override + public void setStatusBarColor(int color) { + mStatusBarColor = color; + mForcedStatusBarColor = true; + if (mDecor != null) { + mDecor.updateColorViews(null); + } + } + + @Override + public int getNavigationBarColor() { + return mNavigationBarColor; + } + + @Override + public void setNavigationBarColor(int color) { + mNavigationBarColor = color; + mForcedNavigationBarColor = true; + if (mDecor != null) { + mDecor.updateColorViews(null); + } + } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 524cf69..99dd2f4 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -46,6 +46,7 @@ import android.media.AudioSystem; import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; +import android.media.session.MediaSessionLegacyHelper; import android.os.Bundle; import android.os.FactoryTest; import android.os.Handler; @@ -91,10 +92,13 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.WindowManagerPolicy; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import com.android.internal.R; +import com.android.internal.policy.IKeyguardService; +import com.android.internal.policy.IKeyguardServiceConstants; import com.android.internal.policy.PolicyManager; import com.android.internal.policy.impl.keyguard.KeyguardServiceDelegate; import com.android.internal.statusbar.IStatusBarService; @@ -134,6 +138,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true; static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false; + // Whether to use the new Session APIs + static final boolean USE_SESSIONS = true; + static final int SHORT_PRESS_POWER_NOTHING = 0; static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2; @@ -172,12 +179,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_TRANSLUCENT - | View.NAVIGATION_BAR_TRANSLUCENT; + | View.NAVIGATION_BAR_TRANSLUCENT + | View.SYSTEM_UI_TRANSPARENT; /** * Keyguard stuff */ private WindowState mKeyguardScrim; + private boolean mKeyguardHidden; + private boolean mKeyguardDrawn; /* Table of Application Launch keys. Maps from key codes to intent categories. * @@ -218,6 +228,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Object mServiceAquireLock = new Object(); Vibrator mVibrator; // Vibrator for giving feedback of orientation changes SearchManager mSearchManager; + AccessibilityManager mAccessibilityManager; // Vibrator pattern for haptic feedback of a long press. long[] mLongPressVibePattern; @@ -228,6 +239,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Vibrator pattern for a short vibration. long[] mKeyboardTapVibePattern; + // Vibrator pattern for a short vibration when tapping on an hour/minute tick of a Clock. + long[] mClockTickVibePattern; + // Vibrator pattern for haptic feedback during boot when safe mode is disabled. long[] mSafeModeDisabledVibePattern; @@ -248,7 +262,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { int[] mNavigationBarHeightForRotation = new int[4]; int[] mNavigationBarWidthForRotation = new int[4]; - WindowState mKeyguard = null; KeyguardServiceDelegate mKeyguardDelegate; GlobalActions mGlobalActions; volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread @@ -257,13 +270,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mLastInputMethodWindow = null; WindowState mLastInputMethodTargetWindow = null; - static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0; - static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1; - static final int RECENT_APPS_BEHAVIOR_DISMISS = 2; - static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 3; - - RecentApplicationsDialog mRecentAppsDialog; - int mRecentAppsDialogHeldModifiers; + int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; int mLidState = LID_ABSENT; @@ -303,7 +310,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mOrientationSensorEnabled = false; int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; boolean mHasSoftInput = false; - boolean mTouchExplorationEnabled = false; boolean mTranslucentDecorEnabled = true; int mPointerLocationMode = 0; // guarded by mLock @@ -312,17 +318,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mFocusedWindow; IApplicationToken mFocusedApp; - private final class PointerLocationPointerEventListener implements PointerEventListener { - @Override - public void onPointerEvent(MotionEvent motionEvent) { - if (mPointerLocationView != null) { - mPointerLocationView.addPointerEvent(motionEvent); - } - } - } - - // Pointer location view state, only modified on the mHandler Looper. - PointerLocationPointerEventListener mPointerLocationPointerEventListener; PointerLocationView mPointerLocationView; // The current size of the screen; really; extends into the overscan area of @@ -540,9 +535,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD), false, this, UserHandle.USER_ALL); - resolver.registerContentObserver(Settings.System.getUriFor( + resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.POLICY_CONTROL), false, this, + UserHandle.USER_ALL); updateSettings(); } @@ -810,6 +808,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0; } + boolean isUserSetupComplete() { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; + } + private void handleLongPressOnHome() { if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { mHomeConsumed = true; @@ -840,52 +843,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - /** - * Create (if necessary) and show or dismiss the recent apps dialog according - * according to the requested behavior. - */ - void showOrHideRecentAppsDialog(final int behavior) { - mHandler.post(new Runnable() { - @Override - public void run() { - if (mRecentAppsDialog == null) { - mRecentAppsDialog = new RecentApplicationsDialog(mContext); - } - if (mRecentAppsDialog.isShowing()) { - switch (behavior) { - case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: - case RECENT_APPS_BEHAVIOR_DISMISS: - mRecentAppsDialog.dismiss(); - break; - case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: - mRecentAppsDialog.dismissAndSwitch(); - break; - case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: - default: - break; - } - } else { - switch (behavior) { - case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: - mRecentAppsDialog.show(); - break; - case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: - try { - mWindowManager.setInTouchMode(false); - } catch (RemoteException e) { - } - mRecentAppsDialog.show(); - break; - case RECENT_APPS_BEHAVIOR_DISMISS: - case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: - default: - break; - } - } - } - }); - } - /** {@inheritDoc} */ @Override public void init(Context context, IWindowManager windowManager, @@ -945,6 +902,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.bool.config_enableTranslucentDecor); readConfigurationDependentBehaviors(); + mAccessibilityManager = (AccessibilityManager) context.getSystemService( + Context.ACCESSIBILITY_SERVICE); + // register for dock events IntentFilter filter = new IntentFilter(); filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); @@ -1005,6 +965,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.array.config_virtualKeyVibePattern); mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_keyboardTapVibePattern); + mClockTickVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_clockTickVibePattern); mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), @@ -1019,7 +981,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { initializeHdmiState(); // Match current screen state. - if (mPowerManager.isScreenOn()) { + if (mPowerManager.isInteractive()) { wakingUp(null); } else { goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER); @@ -1143,7 +1105,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { * navigation bar and touch exploration is not enabled */ private boolean canHideNavigationBar() { - return mHasNavigationBar && !mTouchExplorationEnabled; + return mHasNavigationBar + && !mAccessibilityManager.isTouchExplorationEnabled(); } @Override @@ -1212,8 +1175,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation = true; } if (mImmersiveModeConfirmation != null) { - mImmersiveModeConfirmation.loadSetting(); + mImmersiveModeConfirmation.loadSetting(mCurrentUserId); } + PolicyControl.reloadFromSetting(mContext); } if (updateRotation) { updateRotation(true); @@ -1224,7 +1188,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mPointerLocationView == null) { mPointerLocationView = new PointerLocationView(mContext); mPointerLocationView.setPrintCoords(false); - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); @@ -1244,22 +1207,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.getSystemService(Context.WINDOW_SERVICE); lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; wm.addView(mPointerLocationView, lp); - - mPointerLocationPointerEventListener = new PointerLocationPointerEventListener(); - mWindowManagerFuncs.registerPointerEventListener(mPointerLocationPointerEventListener); + mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView); } } private void disablePointerLocation() { - if (mPointerLocationPointerEventListener != null) { - mWindowManagerFuncs.unregisterPointerEventListener( - mPointerLocationPointerEventListener); - mPointerLocationPointerEventListener = null; - } - if (mPointerLocationView != null) { - WindowManager wm = (WindowManager) - mContext.getSystemService(Context.WINDOW_SERVICE); + mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView); + WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.removeView(mPointerLocationView); mPointerLocationView = null; } @@ -1351,7 +1306,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_BOOT_PROGRESS: case TYPE_DISPLAY_OVERLAY: case TYPE_HIDDEN_NAV_CONSUMER: - case TYPE_KEYGUARD: case TYPE_KEYGUARD_SCRIM: case TYPE_KEYGUARD_DIALOG: case TYPE_MAGNIFICATION_OVERLAY: @@ -1388,13 +1342,36 @@ public class PhoneWindowManager implements WindowManagerPolicy { | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; break; + case TYPE_STATUS_BAR: + + // If the Keyguard is in a hidden state (occluded by another window), we force to + // remove the wallpaper and keyguard flag so that any change in-flight after setting + // the keyguard as occluded wouldn't set these flags again. + // See {@link #processKeyguardSetHiddenResultLw}. + if (mKeyguardHidden) { + attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + } + break; + } + + if (attrs.type != TYPE_STATUS_BAR) { + // The status bar is the only window allowed to exhibit keyguard behavior. + attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; + } + + if (ActivityManager.isHighEndGfx() + && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) { + attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; } } - + void readLidState() { mLidState = mWindowManagerFuncs.getLidState(); } - + private boolean isHidden(int accessibilityMode) { switch (accessibilityMode) { case 1: @@ -1474,54 +1451,50 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_KEYGUARD_SCRIM: // the safety window that shows behind keyguard while keyguard is starting return 12; - case TYPE_KEYGUARD: - // the keyguard; nothing on top of these can take focus, since they are - // responsible for power management when displayed. + case TYPE_STATUS_BAR_SUB_PANEL: return 13; - case TYPE_KEYGUARD_DIALOG: + case TYPE_STATUS_BAR: return 14; - case TYPE_STATUS_BAR_SUB_PANEL: + case TYPE_STATUS_BAR_PANEL: return 15; - case TYPE_STATUS_BAR: + case TYPE_KEYGUARD_DIALOG: return 16; - case TYPE_STATUS_BAR_PANEL: - return 17; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 18; + return 17; case TYPE_SYSTEM_OVERLAY: // the on-screen volume indicator and controller shown when the user // changes the device volume - return 19; + return 18; case TYPE_NAVIGATION_BAR: // the navigation bar, if available, shows atop most things - return 20; + return 19; case TYPE_NAVIGATION_BAR_PANEL: // some panels (e.g. search) need to show on top of the navigation bar - return 21; + return 20; case TYPE_SYSTEM_ERROR: // system-level error dialogs - return 22; + return 21; case TYPE_MAGNIFICATION_OVERLAY: // used to highlight the magnified portion of a display - return 23; + return 22; case TYPE_DISPLAY_OVERLAY: // used to simulate secondary display devices - return 24; + return 23; case TYPE_DRAG: // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows - return 25; + return 24; case TYPE_SECURE_SYSTEM_OVERLAY: - return 26; + return 25; case TYPE_BOOT_PROGRESS: - return 27; + return 26; case TYPE_POINTER: // the (mouse) pointer layer - return 28; + return 27; case TYPE_HIDDEN_NAV_CONSUMER: - return 29; + return 28; } Log.e(TAG, "Unknown window type: " + type); return 2; @@ -1591,7 +1564,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { - return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; + return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; } @Override @@ -1602,7 +1575,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: case TYPE_DREAM: case TYPE_UNIVERSE_BACKGROUND: - case TYPE_KEYGUARD: case TYPE_KEYGUARD_SCRIM: return false; default: @@ -1746,16 +1718,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** * Preflight adding a window to the system. - * + * * Currently enforces that three window types are singletons: * <ul> * <li>STATUS_BAR_TYPE</li> * <li>KEYGUARD_TYPE</li> * </ul> - * + * * @param win The window to be added * @param attrs Information about the window to be added - * + * * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, * WindowManagerImpl.ADD_MULTIPLE_SINGLETON */ @@ -1801,12 +1773,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { android.Manifest.permission.STATUS_BAR_SERVICE, "PhoneWindowManager"); break; - case TYPE_KEYGUARD: - if (mKeyguard != null) { - return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; - } - mKeyguard = win; - break; case TYPE_KEYGUARD_SCRIM: if (mKeyguardScrim != null) { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; @@ -1823,9 +1789,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar == win) { mStatusBar = null; mStatusBarController.setWindow(null); - } else if (mKeyguard == win) { - Log.v(TAG, "Removing keyguard window (Did it crash?)"); - mKeyguard = null; mKeyguardDelegate.showScrim(); } else if (mKeyguardScrim == win) { Log.v(TAG, "Removing keyguard scrim"); @@ -1837,19 +1800,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { } static final boolean PRINT_ANIM = false; - + /** {@inheritDoc} */ @Override public int selectAnimationLw(WindowState win, int transit) { if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + ": transit=" + transit); if (win == mStatusBar) { + boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { - return R.anim.dock_top_exit; + return isKeyguard ? -1 : R.anim.dock_top_exit; } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { - return R.anim.dock_top_enter; + return isKeyguard ? -1 : R.anim.dock_top_enter; } } else if (win == mNavigationBar) { // This can be on either the bottom or the right. @@ -2070,9 +2034,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; if (attrs != null) { final int type = attrs.type; - if (type == WindowManager.LayoutParams.TYPE_KEYGUARD - || type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM - || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { + if (type == WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM + || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG + || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { // the "app" is keyguard, so give it the key return 0; } @@ -2287,21 +2251,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Display task switcher for ALT-TAB or Meta-TAB. if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) { - if (mRecentAppsDialogHeldModifiers == 0 && !keyguardOn) { + if (mRecentAppsHeldModifiers == 0 && !keyguardOn) { final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) || KeyEvent.metaStateHasModifiers( shiftlessModifiers, KeyEvent.META_META_ON)) { - mRecentAppsDialogHeldModifiers = shiftlessModifiers; - showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW); + mRecentAppsHeldModifiers = shiftlessModifiers; + showRecentApps(true); return -1; } } - } else if (!down && mRecentAppsDialogHeldModifiers != 0 - && (metaState & mRecentAppsDialogHeldModifiers) == 0) { - mRecentAppsDialogHeldModifiers = 0; - showOrHideRecentAppsDialog(keyguardOn ? RECENT_APPS_BEHAVIOR_DISMISS : - RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH); + } else if (!down && mRecentAppsHeldModifiers != 0 + && (metaState & mRecentAppsHeldModifiers) == 0) { + mRecentAppsHeldModifiers = 0; + hideRecentApps(true); } // Handle keyboard language switching. @@ -2416,7 +2379,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - // TODO: This only stops the factory-installed search manager. + // TODO: This only stops the factory-installed search manager. // Need to formalize an API to handle others SearchManager searchManager = getSearchManager(); if (searchManager != null) { @@ -2474,7 +2437,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { statusbar.cancelPreloadRecentApps(); } } catch (RemoteException e) { - Slog.e(TAG, "RemoteException when showing recent apps", e); + Slog.e(TAG, "RemoteException when cancelling recent apps preload", e); // re-acquire status bar service next time it is needed. mStatusBarService = null; } @@ -2483,25 +2446,52 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void toggleRecentApps() { mPreloadedRecentApps = false; // preloading no longer needs to be canceled - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); try { IStatusBarService statusbar = getStatusBarService(); if (statusbar != null) { statusbar.toggleRecentApps(); } } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when toggling recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + + private void showRecentApps(boolean triggeredFromAltTab) { + mPreloadedRecentApps = false; // preloading no longer needs to be canceled + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.showRecentApps(triggeredFromAltTab); + } + } catch (RemoteException e) { Slog.e(TAG, "RemoteException when showing recent apps", e); // re-acquire status bar service next time it is needed. mStatusBarService = null; } } + private void hideRecentApps(boolean triggeredFromAltTab) { + mPreloadedRecentApps = false; // preloading no longer needs to be canceled + try { + IStatusBarService statusbar = getStatusBarService(); + if (statusbar != null) { + statusbar.hideRecentApps(triggeredFromAltTab); + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when closing recent apps", e); + // re-acquire status bar service next time it is needed. + mStatusBarService = null; + } + } + /** * A home key -> launch home action was detected. Take the appropriate action * given the situation with the keyguard. */ void launchHomeFromHotKey() { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotHidden()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowingAndNotOccluded()) { // don't launch home if keyguard showing } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) { // when in keyguard restricted mode, must first verify unlock @@ -2621,8 +2611,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { - final int fl = attrs.flags; - final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility); + final int fl = PolicyControl.getWindowFlags(null, attrs); + final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs); + final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility); if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { @@ -2741,7 +2732,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // drive nav being hidden only by whether it is requested. final int sysui = mLastSystemUiFlags; boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; - boolean navTranslucent = (sysui & View.NAVIGATION_BAR_TRANSLUCENT) != 0; + boolean navTranslucent = (sysui + & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0; boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0; boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; boolean navAllowedHidden = immersive || immersiveSticky; @@ -2794,7 +2786,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // We currently want to hide the navigation UI. mNavigationBarController.setBarShowingLw(false); } - if (navVisible && !navTranslucent && !mNavigationBar.isAnimatingLw() + if (navVisible && !navTranslucent && !navAllowedHidden + && !mNavigationBar.isAnimatingLw() && !mNavigationBarController.wasRecentlyTranslucent()) { // If the opaque nav bar is currently requested to be visible, // and not in the process of animating on or off, then @@ -2866,7 +2859,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStableTop = mUnrestrictedScreenTop + mStatusBarHeight; boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; - boolean statusBarTranslucent = (sysui & View.STATUS_BAR_TRANSLUCENT) != 0; + boolean statusBarTranslucent = (sysui + & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0; statusBarTranslucent &= areTranslucentBarsAllowed(); // If the status bar is hidden, we don't want to cause @@ -3003,9 +2997,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { offsetInputMethodWindowLw(mLastInputMethodWindow); } - final int fl = attrs.flags; + final int fl = PolicyControl.getWindowFlags(win, attrs); final int sim = attrs.softInputMode; - final int sysUiFl = win.getSystemUiVisibility(); + final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null); final Rect pf = mTmpParentFrame; final Rect df = mTmpDisplayFrame; @@ -3062,12 +3056,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isAppWindow && !inheritTranslucentDecor && !topAtRest) { if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0 && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0 - && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0) { + && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0 + && (fl & WindowManager.LayoutParams. + FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) { // Ensure policy decor includes status bar dcf.top = mStableTop; } if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0 - && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { + && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 + && (fl & WindowManager.LayoutParams. + FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) { // Ensure policy decor includes navigation bar dcf.bottom = mStableBottom; dcf.right = mStableRight; @@ -3076,7 +3074,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { - if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN, 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 @@ -3121,9 +3119,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { + mOverscanScreenHeight; } else if (canHideNavigationBar() && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 - && (attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD || ( - attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW - && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) { + && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { // Asking for layout as if the nav bar is hidden, lets the // application extend into the unrestricted overscan screen area. We // only do this for application windows to ensure no window that @@ -3361,7 +3358,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) - + " attach=" + attached + " type=" + attrs.type + + " attach=" + attached + " type=" + attrs.type + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " of=" + of.toShortString() @@ -3410,7 +3407,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mForceStatusBarFromKeyguard = false; mForcingShowNavBar = false; mForcingShowNavBarLayer = -1; - + mHideLockScreen = false; mAllowLockscreenWhenOn = false; mDismissKeyguard = DISMISS_KEYGUARD_NONE; @@ -3424,21 +3421,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManager.LayoutParams attrs) { if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw=" + win.isVisibleOrBehindKeyguardLw()); + final int fl = PolicyControl.getWindowFlags(win, attrs); if (mTopFullscreenOpaqueWindowState == null && win.isVisibleLw() && attrs.type == TYPE_INPUT_METHOD) { mForcingShowNavBar = true; mForcingShowNavBarLayer = win.getSurfaceLayer(); } + if (attrs.type == TYPE_STATUS_BAR && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { + mForceStatusBarFromKeyguard = true; + } if (mTopFullscreenOpaqueWindowState == null && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) { - if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { - if (attrs.type == TYPE_KEYGUARD) { + if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { + if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mForceStatusBarFromKeyguard = true; } else { mForceStatusBar = true; } } - if (attrs.type == TYPE_KEYGUARD) { + if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { mShowingLockscreen = true; } boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW @@ -3453,8 +3454,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - final boolean showWhenLocked = (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0; - final boolean dismissKeyguard = (attrs.flags & FLAG_DISMISS_KEYGUARD) != 0; + final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0; + final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0; if (appWindow) { if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) { mAppsToBeHidden.remove(win.getAppToken()); @@ -3474,14 +3475,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mForceStatusBarFromKeyguard = false; } if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win); + if (DEBUG_LAYOUT) Slog.v(TAG, + "Setting mDismissKeyguard true by win " + win); mDismissKeyguard = mWinDismissingKeyguard == win ? DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; mWinDismissingKeyguard = win; mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); } } - if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { + if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { mAllowLockscreenWhenOn = true; } } @@ -3524,13 +3526,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mLastSystemUiFlags, mLastSystemUiFlags); } } else if (mTopFullscreenOpaqueWindowState != null) { + final int fl = PolicyControl.getWindowFlags(null, lp); if (localLOGV) { Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() - + " lp.flags=0x" + Integer.toHexString(lp.flags)); + + " lp.flags=0x" + Integer.toHexString(fl)); } - topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0 + topIsFullscreen = (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; // The subtle difference between the window for mTopFullscreenOpaqueWindowState // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window @@ -3566,11 +3569,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Hide the key guard if a visible window explicitly specifies that it wants to be // displayed when the screen is locked. - if (mKeyguard != null) { + if (mKeyguardDelegate != null && mStatusBar != null) { if (localLOGV) Slog.v(TAG, "finishPostLayoutPolicyLw: mHideKeyguard=" + mHideLockScreen); if (mDismissKeyguard != DISMISS_KEYGUARD_NONE && !isKeyguardSecure()) { - if (mKeyguard.hideLw(true)) { + mKeyguardHidden = true; + if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; @@ -3584,24 +3588,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { }); } } else if (mHideLockScreen) { - if (mKeyguard.hideLw(true)) { + mKeyguardHidden = true; + if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(true))) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - if (!mShowingDream) { - mKeyguardDelegate.setHidden(true); - } } else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) { // This is the case of keyguard isSecure() and not mHideLockScreen. if (mDismissKeyguard == DISMISS_KEYGUARD_START) { // Only launch the next keyguard unlock window once per window. - if (mKeyguard.showLw(true)) { + mKeyguardHidden = false; + if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - mKeyguardDelegate.setHidden(false); mHandler.post(new Runnable() { @Override public void run() { @@ -3611,12 +3613,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } else { mWinDismissingKeyguard = null; - if (mKeyguard.showLw(true)) { + mKeyguardHidden = false; + if (processKeyguardSetHiddenResultLw(mKeyguardDelegate.setOccluded(false))) { changes |= FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG | FINISH_LAYOUT_REDO_WALLPAPER; } - mKeyguardDelegate.setHidden(false); } } @@ -3631,9 +3633,39 @@ public class PhoneWindowManager implements WindowManagerPolicy { return changes; } + /** + * Processes the result code of {@link IKeyguardService#setOccluded}. This is needed because we + * immediately need to put the wallpaper directly behind the Keyguard when a window with flag + * {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} gets dismissed. If we + * would wait for Keyguard to change the flags, that would be running asynchronously and thus be + * too late so the user might see the window behind. + * + * @param setHiddenResult The result code from {@link IKeyguardService#setOccluded}. + * @return Whether the flags have changed and we have to redo the layout. + */ + private boolean processKeyguardSetHiddenResultLw(int setHiddenResult) { + if (setHiddenResult + == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS) { + mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD; + mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + return true; + } else if (setHiddenResult + == IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS) { + mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD; + mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER; + return true; + } else { + return false; + } + } + + private boolean isStatusBarKeyguard() { + return mStatusBar != null + && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; + } + public boolean allowAppAnimationsLw() { - if (mKeyguard != null && mKeyguard.isVisibleLw() && !mKeyguard.isAnimatingLw() - || mShowingDream) { + if (isStatusBarKeyguard() || mShowingDream) { // If keyguard or dreams is currently visible, no reason to animate behind it. return false; } @@ -3855,15 +3887,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // when the keyguard is hidden by another activity. final boolean keyguardActive = (mKeyguardDelegate == null ? false : (interactive ? - mKeyguardDelegate.isShowingAndNotHidden() : + mKeyguardDelegate.isShowingAndNotOccluded() : mKeyguardDelegate.isShowing())); - if (keyCode == KeyEvent.KEYCODE_POWER - || keyCode == KeyEvent.KEYCODE_SLEEP - || keyCode == KeyEvent.KEYCODE_WAKEUP) { - policyFlags |= WindowManagerPolicy.FLAG_WAKE; - } - if (DEBUG_INPUT) { Log.d(TAG, "interceptKeyTq keycode=" + keyCode + " interactive=" + interactive + " keyguardActive=" + keyguardActive @@ -3877,8 +3903,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Basic policy based on interactive state. int result; - boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE - | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; + boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0 + || event.isWakeKey(); if (interactive || (isInjected && !isWakeKey)) { // When the screen is on or if the key is injected pass the key to the application. result = ACTION_PASS_TO_USER; @@ -4008,8 +4034,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; if (down) { - mImmersiveModeConfirmation.onPowerKeyDown(interactive, event.getDownTime(), - isImmersiveMode(mLastSystemUiFlags)); + boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, + event.getDownTime(), isImmersiveMode(mLastSystemUiFlags)); + if (panic) { + mHandler.post(mRequestTransientNav); + } if (interactive && !mPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { mPowerKeyTriggered = true; @@ -4027,7 +4056,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { telephonyService.silenceRinger(); } else if ((mIncallPowerBehavior & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 - && telephonyService.isOffhook() && isScreenOn) { + && telephonyService.isOffhook() && interactive) { // Otherwise, if "Power button ends call" is enabled, // the Power button will hang up any current active call. hungUp = telephonyService.endCall(); @@ -4222,12 +4251,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) { if (ActivityManagerNative.isSystemReady()) { - IAudioService audioService = getAudioService(); - if (audioService != null) { - try { - audioService.dispatchMediaKeyEventUnderWakelock(event); - } catch (RemoteException e) { - Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e); + if (USE_SESSIONS) { + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true); + } else { + IAudioService audioService = getAudioService(); + if (audioService != null) { + try { + audioService.dispatchMediaKeyEventUnderWakelock(event); + } catch (RemoteException e) { + Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e); + } } } } @@ -4290,8 +4323,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; + private final Runnable mRequestTransientNav = new Runnable() { + @Override + public void run() { + requestTransientBars(mNavigationBar); + } + }; + private void requestTransientBars(WindowState swipeTarget) { synchronized (mWindowManagerFuncs.getWindowManagerLock()) { + if (!isUserSetupComplete()) { + // Swipe-up for navigation bar is disabled during setup + return; + } boolean sb = mStatusBarController.checkShowTransientBarLw(); boolean nb = mNavigationBarController.checkShowTransientBarLw(); if (sb || nb) { @@ -4344,21 +4388,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { private void waitForKeyguard(final ScreenOnListener screenOnListener) { if (mKeyguardDelegate != null) { - if (screenOnListener != null) { - mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() { - @Override - public void onShown(IBinder windowToken) { - waitForKeyguardWindowDrawn(windowToken, screenOnListener); - } - }); - return; - } else { - mKeyguardDelegate.onScreenTurnedOn(null); - } + mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() { + @Override + public void onShown(IBinder windowToken) { + waitForKeyguardWindowDrawn(windowToken, screenOnListener); + } + }); } else { Slog.i(TAG, "No keyguard interface!"); + finishScreenTurningOn(screenOnListener); } - finishScreenTurningOn(screenOnListener); } private void waitForKeyguardWindowDrawn(IBinder windowToken, @@ -4371,6 +4410,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void sendResult(Bundle data) { Slog.i(TAG, "Lock screen displayed!"); finishScreenTurningOn(screenOnListener); + setKeyguardDrawn(); } })) { return; @@ -4384,6 +4424,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.i(TAG, "No lock screen! windowToken=" + windowToken); finishScreenTurningOn(screenOnListener); + setKeyguardDrawn(); } private void finishScreenTurningOn(ScreenOnListener screenOnListener) { @@ -4427,7 +4468,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean keyguardIsShowingTq() { if (mKeyguardDelegate == null) return false; - return mKeyguardDelegate.isShowingAndNotHidden(); + return mKeyguardDelegate.isShowingAndNotOccluded(); } @@ -4449,7 +4490,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } public void dismissKeyguardLw() { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { mHandler.post(new Runnable() { public void run() { if (mKeyguardDelegate.isDismissable()) { @@ -4464,6 +4505,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void setKeyguardDrawn() { + synchronized (mLock) { + mKeyguardDrawn = true; + } + try { + mWindowManager.enableScreenIfNeeded(); + } catch (RemoteException unhandled) { + } + } + + @Override + public boolean isKeyguardDrawnLw() { + synchronized (mLock) { + return mKeyguardDrawn; + } + } + void sendCloseSystemWindows() { sendCloseSystemWindows(mContext, null); } @@ -4747,6 +4805,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mSystemBooted = true; } + waitForKeyguard(null); } ProgressDialog mBootMsgDialog = null; @@ -4756,9 +4815,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.post(new Runnable() { @Override public void run() { if (mBootMsgDialog == null) { - int theme = mContext.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_WATCH) ? - com.android.internal.R.style.Theme_Micro_Dialog_Alert : 0; + int theme; + if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WATCH)) { + theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert; + } else if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEVISION)) { + theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert; + } else { + theme = 0; + } mBootMsgDialog = new ProgressDialog(mContext, theme) { // This dialog will consume all events coming in to @@ -5077,7 +5143,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; - if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotHidden())) { + if (!always && (hapticsDisabled || mKeyguardDelegate.isShowingAndNotOccluded())) { return false; } long[] pattern = null; @@ -5091,6 +5157,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.KEYBOARD_TAP: pattern = mKeyboardTapVibePattern; break; + case HapticFeedbackConstants.CLOCK_TICK: + pattern = mClockTickVibePattern; + break; case HapticFeedbackConstants.SAFE_MODE_DISABLED: pattern = mSafeModeDisabledVibePattern; break; @@ -5111,10 +5180,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (pattern.length == 1) { // One-shot vibration - mVibrator.vibrate(owningUid, owningPackage, pattern[0]); + mVibrator.vibrate(owningUid, owningPackage, pattern[0], AudioManager.STREAM_SYSTEM); } else { // Pattern vibration - mVibrator.vibrate(owningUid, owningPackage, pattern, -1); + mVibrator.vibrate(owningUid, owningPackage, pattern, -1, AudioManager.STREAM_SYSTEM); } return true; } @@ -5125,8 +5194,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void keepScreenOnStoppedLw() { - if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotHidden()) { - long curTime = SystemClock.uptimeMillis(); + if (mKeyguardDelegate != null && !mKeyguardDelegate.isShowingAndNotOccluded()) { mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } } @@ -5138,7 +5206,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (win == null) { return 0; } - if (win.getAttrs().type == TYPE_KEYGUARD && mHideLockScreen == true) { + if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) { // We are updating at a point where the keyguard has gotten // focus, but we were last in a state where the top window is // hiding it. This is probably because the keyguard as been @@ -5148,11 +5216,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 0; } - int tmpVisibility = win.getSystemUiVisibility() + int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null) & ~mResettingSystemUiFlags & ~mForceClearedSystemUiFlags; if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) { - tmpVisibility &= ~View.SYSTEM_UI_CLEARABLE_FLAGS; + tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS); } final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); final int diff = visibility ^ mLastSystemUiFlags; @@ -5184,8 +5252,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { // apply translucent bar vis flags - WindowState transWin = mKeyguard != null && mKeyguard.isVisibleLw() && !mHideLockScreen - ? mKeyguard + WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen + ? mStatusBar : mTopFullscreenOpaqueWindowState; vis = mStatusBarController.applyTranslucentFlagLw(transWin, vis, oldVis); vis = mNavigationBarController.applyTranslucentFlagLw(transWin, vis, oldVis); @@ -5196,14 +5264,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY - | View.STATUS_BAR_TRANSLUCENT - | View.NAVIGATION_BAR_TRANSLUCENT; + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + if (!isStatusBarKeyguard() || mHideLockScreen) { + flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT; + } vis = (vis & ~flags) | (oldVis & flags); } if (!areTranslucentBarsAllowed()) { - vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT); + vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT + | View.SYSTEM_UI_TRANSPARENT); } // update status bar @@ -5211,7 +5281,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; boolean hideStatusBarWM = mTopFullscreenOpaqueWindowState != null && - (mTopFullscreenOpaqueWindowState.getAttrs().flags + (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null) & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; boolean hideStatusBarSysui = (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; @@ -5244,7 +5314,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean newImmersiveMode = isImmersiveMode(vis); if (win != null && oldImmersiveMode != newImmersiveMode) { final String pkg = win.getOwningPackage(); - mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode); + mImmersiveModeConfirmation.immersiveModeChanged(pkg, newImmersiveMode, + isUserSetupComplete()); } vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); @@ -5275,7 +5346,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { * R.boolean.config_enableTranslucentDecor is false. */ private boolean areTranslucentBarsAllowed() { - return mTranslucentDecorEnabled && !mTouchExplorationEnabled; + return mTranslucentDecorEnabled + && !mAccessibilityManager.isTouchExplorationEnabled(); } // Use this instead of checking config_showNavigationBar so that it can be consistently @@ -5292,6 +5364,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public int getInputMethodWindowVisibleHeightLw() { + return mDockBottom - mCurBottom; + } + + @Override public void setCurrentUserLw(int newUserId) { mCurrentUserId = newUserId; if (mKeyguardDelegate != null) { @@ -5321,11 +5398,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void setTouchExplorationEnabled(boolean enabled) { - mTouchExplorationEnabled = enabled; - } - - @Override public boolean isTopLevelWindow(int windowType) { if (windowType >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && windowType <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { @@ -5443,15 +5515,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mStatusBar != null) { pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar); + pw.print(prefix); pw.print("isStatusBarKeyguard="); + pw.print(isStatusBarKeyguard()); } if (mNavigationBar != null) { pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar); } - if (mKeyguard != null) { - pw.print(prefix); pw.print("mKeyguard="); - pw.println(mKeyguard); - } if (mFocusedWindow != null) { pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow); @@ -5496,5 +5566,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation); mStatusBarController.dump(pw, prefix); mNavigationBarController.dump(pw, prefix); + PolicyControl.dump(prefix, pw); } } diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java new file mode 100644 index 0000000..ffdb520 --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.policy.impl; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.ArraySet; +import android.util.Slog; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerPolicy.WindowState; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Runtime adjustments applied to the global window policy. + * + * This includes forcing immersive mode behavior for one or both system bars (based on a package + * list) and permanently disabling immersive mode confirmations for specific packages. + * + * Control by setting {@link Settings.Global.POLICY_CONTROL} to one or more name-value pairs. + * e.g. + * to force immersive mode everywhere: + * "immersive.full=*" + * to force transient status for all apps except a specific package: + * "immersive.status=apps,-com.package" + * to disable the immersive mode confirmations for specific packages: + * "immersive.preconfirms=com.package.one,com.package.two" + * + * Separate multiple name-value pairs with ':' + * e.g. "immersive.status=apps:immersive.preconfirms=*" + */ +public class PolicyControl { + private static String TAG = "PolicyControl"; + private static boolean DEBUG = false; + + private static final String NAME_IMMERSIVE_FULL = "immersive.full"; + private static final String NAME_IMMERSIVE_STATUS = "immersive.status"; + private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation"; + private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms"; + + private static String sSettingValue; + private static Filter sImmersivePreconfirmationsFilter; + private static Filter sImmersiveStatusFilter; + private static Filter sImmersiveNavigationFilter; + + public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) { + attrs = attrs != null ? attrs : win.getAttrs(); + int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility; + if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) { + vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.STATUS_BAR_TRANSLUCENT); + } + if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) { + vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.NAVIGATION_BAR_TRANSLUCENT); + } + return vis; + } + + public static int getWindowFlags(WindowState win, LayoutParams attrs) { + attrs = attrs != null ? attrs : win.getAttrs(); + int flags = attrs.flags; + if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) { + flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; + flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + } + if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) { + flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; + } + return flags; + } + + public static int adjustClearableFlags(WindowState win, int clearableFlags) { + final LayoutParams attrs = win != null ? win.getAttrs() : null; + if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) { + clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN; + } + return clearableFlags; + } + + public static boolean disableImmersiveConfirmation(String pkg) { + return sImmersivePreconfirmationsFilter != null + && sImmersivePreconfirmationsFilter.matches(pkg); + } + + public static void reloadFromSetting(Context context) { + if (DEBUG) Slog.d(TAG, "reloadFromSetting()"); + String value = null; + try { + value = Settings.Global.getStringForUser(context.getContentResolver(), + Settings.Global.POLICY_CONTROL, + UserHandle.USER_CURRENT); + if (sSettingValue != null && sSettingValue.equals(value)) return; + setFilters(value); + sSettingValue = value; + } catch (Throwable t) { + Slog.w(TAG, "Error loading policy control, value=" + value, t); + } + } + + public static void dump(String prefix, PrintWriter pw) { + dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw); + dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw); + dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw); + } + + private static void dump(String name, Filter filter, String prefix, PrintWriter pw) { + pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('='); + if (filter == null) { + pw.println("null"); + } else { + filter.dump(pw); pw.println(); + } + } + + private static void setFilters(String value) { + if (DEBUG) Slog.d(TAG, "setFilters: " + value); + sImmersiveStatusFilter = null; + sImmersiveNavigationFilter = null; + sImmersivePreconfirmationsFilter = null; + if (value != null) { + String[] nvps = value.split(":"); + for (String nvp : nvps) { + int i = nvp.indexOf('='); + if (i == -1) continue; + String n = nvp.substring(0, i); + String v = nvp.substring(i + 1); + if (n.equals(NAME_IMMERSIVE_FULL)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = sImmersiveNavigationFilter = f; + if (sImmersivePreconfirmationsFilter == null) { + sImmersivePreconfirmationsFilter = f; + } + } else if (n.equals(NAME_IMMERSIVE_STATUS)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = f; + } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) { + Filter f = Filter.parse(v); + sImmersiveNavigationFilter = f; + if (sImmersivePreconfirmationsFilter == null) { + sImmersivePreconfirmationsFilter = f; + } + } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) { + Filter f = Filter.parse(v); + sImmersivePreconfirmationsFilter = f; + } + } + } + if (DEBUG) { + Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter); + Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter); + Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter); + } + } + + private static class Filter { + private static final String ALL = "*"; + private static final String APPS = "apps"; + + private final ArraySet<String> mWhitelist; + private final ArraySet<String> mBlacklist; + + private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) { + mWhitelist = whitelist; + mBlacklist = blacklist; + } + + boolean matches(LayoutParams attrs) { + if (attrs == null) return false; + boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW + && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + if (isApp && mBlacklist.contains(APPS)) return false; + if (onBlacklist(attrs.packageName)) return false; + if (isApp && mWhitelist.contains(APPS)) return true; + return onWhitelist(attrs.packageName); + } + + boolean matches(String packageName) { + return !onBlacklist(packageName) && onWhitelist(packageName); + } + + private boolean onBlacklist(String packageName) { + return mBlacklist.contains(packageName) || mBlacklist.contains(ALL); + } + + private boolean onWhitelist(String packageName) { + return mWhitelist.contains(ALL) || mWhitelist.contains(packageName); + } + + void dump(PrintWriter pw) { + pw.print("Filter["); + dump("whitelist", mWhitelist, pw); pw.print(','); + dump("blacklist", mBlacklist, pw); pw.print(']'); + } + + private void dump(String name, ArraySet<String> set, PrintWriter pw) { + pw.print(name); pw.print("=("); + final int n = set.size(); + for (int i = 0; i < n; i++) { + if (i > 0) pw.print(','); + pw.print(set.valueAt(i)); + } + pw.print(')'); + } + + @Override + public String toString() { + StringWriter sw = new StringWriter(); + dump(new PrintWriter(sw, true)); + return sw.toString(); + } + + // value = comma-delimited list of tokens, where token = (package name|apps|*) + // e.g. "com.package1", or "apps, com.android.keyguard" or "*" + static Filter parse(String value) { + if (value == null) return null; + ArraySet<String> whitelist = new ArraySet<String>(); + ArraySet<String> blacklist = new ArraySet<String>(); + for (String token : value.split(",")) { + token = token.trim(); + if (token.startsWith("-") && token.length() > 1) { + token = token.substring(1); + blacklist.add(token); + } else { + whitelist.add(token); + } + } + return new Filter(whitelist, blacklist); + } + } +} diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java index 8d87728..3490bd4 100644 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java +++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java @@ -21,7 +21,6 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java index 2f0d7d6..bc55ed1 100644 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java @@ -123,7 +123,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener } @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { + public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_TAB) { // Ignore all meta keys other than SHIFT. The app switch key could be a // fallback action chorded with ALT, META or even CTRL depending on the key map. diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/policy/src/com/android/internal/policy/impl/ShortcutManager.java index 75a1b01..bb898f7 100644 --- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java +++ b/policy/src/com/android/internal/policy/impl/ShortcutManager.java @@ -25,7 +25,6 @@ import android.provider.Settings; import android.util.Log; import android.util.SparseArray; import android.view.KeyCharacterMap; -import android.view.KeyEvent; import java.net.URISyntaxException; diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java index e5af716..966924b 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java @@ -12,7 +12,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.util.Slog; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -30,8 +29,8 @@ import com.android.internal.widget.LockPatternUtils; */ public class KeyguardServiceDelegate { // TODO: propagate changes to these to {@link KeyguardTouchDelegate} - public static final String KEYGUARD_PACKAGE = "com.android.keyguard"; - public static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService"; + public static final String KEYGUARD_PACKAGE = "com.android.systemui"; + public static final String KEYGUARD_CLASS = "com.android.systemui.keyguard.KeyguardService"; private static final String TAG = "KeyguardServiceDelegate"; private static final boolean DEBUG = true; @@ -45,13 +44,13 @@ public class KeyguardServiceDelegate { // the event something checks before the service is actually started. // KeyguardService itself should default to this state until the real state is known. showing = true; - showingAndNotHidden = true; + showingAndNotOccluded = true; secure = true; } boolean showing; - boolean showingAndNotHidden; + boolean showingAndNotOccluded; boolean inputRestricted; - boolean hidden; + boolean occluded; boolean secure; boolean dreaming; boolean systemIsReady; @@ -110,7 +109,7 @@ public class KeyguardServiceDelegate { Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS); mKeyguardState.showing = false; - mKeyguardState.showingAndNotHidden = false; + mKeyguardState.showingAndNotOccluded = false; mKeyguardState.secure = false; } else { if (DEBUG) Log.v(TAG, "*** Keyguard started"); @@ -149,11 +148,11 @@ public class KeyguardServiceDelegate { return mKeyguardState.showing; } - public boolean isShowingAndNotHidden() { + public boolean isShowingAndNotOccluded() { if (mKeyguardService != null) { - mKeyguardState.showingAndNotHidden = mKeyguardService.isShowingAndNotHidden(); + mKeyguardState.showingAndNotOccluded = mKeyguardService.isShowingAndNotOccluded(); } - return mKeyguardState.showingAndNotHidden; + return mKeyguardState.showingAndNotOccluded; } public boolean isInputRestricted() { @@ -175,11 +174,13 @@ public class KeyguardServiceDelegate { } } - public void setHidden(boolean isHidden) { + public int setOccluded(boolean isOccluded) { + int result = 0; if (mKeyguardService != null) { - mKeyguardService.setHidden(isHidden); + result = mKeyguardService.setOccluded(isOccluded); } - mKeyguardState.hidden = isHidden; + mKeyguardState.occluded = isOccluded; + return result; } public void dismiss() { diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java index 9fb2a50..7cb48fa 100644 --- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java +++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java @@ -22,6 +22,7 @@ import android.os.RemoteException; import android.util.Slog; import android.view.MotionEvent; +import com.android.internal.policy.IKeyguardServiceConstants; import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.policy.IKeyguardExitCallback; import com.android.internal.policy.IKeyguardService; @@ -57,9 +58,9 @@ public class KeyguardServiceWrapper implements IKeyguardService { return false; // TODO cache state } - public boolean isShowingAndNotHidden() { + public boolean isShowingAndNotOccluded() { try { - return mService.isShowingAndNotHidden(); + return mService.isShowingAndNotOccluded(); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); } @@ -100,11 +101,12 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } - public void setHidden(boolean isHidden) { + public int setOccluded(boolean isOccluded) { try { - mService.setHidden(isHidden); + return mService.setOccluded(isOccluded); } catch (RemoteException e) { Slog.w(TAG , "Remote Exception", e); + return IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE; } } |