diff options
Diffstat (limited to 'policy/src')
17 files changed, 2089 insertions, 886 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..56a8f7c 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -21,6 +21,7 @@ import com.android.internal.app.AlertController.AlertParams; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.R; +import com.android.internal.widget.LockPatternUtils; import android.app.ActivityManagerNative; import android.app.AlertDialog; @@ -35,6 +36,7 @@ import android.database.ContentObserver; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -51,6 +53,7 @@ import android.service.dreams.IDreamManager; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.TypedValue; @@ -62,6 +65,8 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.WindowManagerInternal; import android.view.WindowManagerPolicy.WindowManagerFuncs; import android.widget.AdapterView; import android.widget.BaseAdapter; @@ -92,6 +97,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac private static final String GLOBAL_ACTION_KEY_SILENT = "silent"; private static final String GLOBAL_ACTION_KEY_USERS = "users"; private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings"; + private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown"; private final Context mContext; private final WindowManagerFuncs mWindowManagerFuncs; @@ -185,7 +191,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac // If we only have 1 item and it's a simple press action, just do this action. if (mAdapter.getCount() == 1 - && mAdapter.getItem(0) instanceof SinglePressAction) { + && mAdapter.getItem(0) instanceof SinglePressAction + && !(mAdapter.getItem(0) instanceof LongPressAction)) { ((SinglePressAction) mAdapter.getItem(0)).onPress(); } else { WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes(); @@ -262,7 +269,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac continue; } if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) { - mItems.add(getPowerAction()); + mItems.add(new PowerAction()); } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) { mItems.add(mAirplaneModeOn); } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey) @@ -276,6 +283,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac addUsersToMenu(mItems); } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) { mItems.add(getSettingsAction()); + } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey) && hasTrustAgents()) { + mItems.add(getLockdownAction()); } else { Log.e(TAG, "Invalid global action key " + actionKey); } @@ -300,7 +309,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { - return mAdapter.getItem(position).onLongPress(); + final Action action = mAdapter.getItem(position); + if (action instanceof LongPressAction) { + return ((LongPressAction) action).onLongPress(); + } + return false; } }); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); @@ -310,34 +323,43 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac return dialog; } - private Action getPowerAction() { - return new SinglePressAction( - com.android.internal.R.drawable.ic_lock_power_off, - R.string.global_action_power_off) { + private boolean hasTrustAgents() { + // TODO: Add implementation. + return true; + } - public void onPress() { - // shutdown by making sure radio and power are handled accordingly. - mWindowManagerFuncs.shutdown(true); - } + private final class PowerAction extends SinglePressAction implements LongPressAction { + private PowerAction() { + super(com.android.internal.R.drawable.ic_lock_power_off, + R.string.global_action_power_off); + } - public boolean onLongPress() { - mWindowManagerFuncs.rebootSafeMode(true); - return true; - } + @Override + public boolean onLongPress() { + mWindowManagerFuncs.rebootSafeMode(true); + return true; + } - public boolean showDuringKeyguard() { - return true; - } + @Override + public boolean showDuringKeyguard() { + return true; + } - public boolean showBeforeProvisioning() { - return true; - } - }; + @Override + public boolean showBeforeProvisioning() { + return true; + } + + @Override + public void onPress() { + // shutdown by making sure radio and power are handled accordingly. + mWindowManagerFuncs.shutdown(false /* confirm */); + } } private Action getBugReportAction() { - return new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb, - R.string.global_action_bug_report) { + return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport, + R.string.bugreport_title) { public void onPress() { AlertDialog.Builder builder = new AlertDialog.Builder(mContext); @@ -367,10 +389,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac dialog.show(); } - public boolean onLongPress() { - return false; - } - public boolean showDuringKeyguard() { return true; } @@ -378,6 +396,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public boolean showBeforeProvisioning() { return false; } + + @Override + public String getStatus() { + return mContext.getString( + com.android.internal.R.string.bugreport_status, + Build.VERSION.RELEASE, + Build.ID); + } }; } @@ -393,8 +419,29 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } @Override - public boolean onLongPress() { - return false; + public boolean showDuringKeyguard() { + return true; + } + + @Override + public boolean showBeforeProvisioning() { + return true; + } + }; + } + + private Action getLockdownAction() { + return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, + R.string.global_action_lockdown) { + + @Override + public void onPress() { + new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL); + try { + WindowManagerGlobal.getWindowManagerService().lockNow(null); + } catch (RemoteException e) { + Log.e(TAG, "Error while trying to lock device.", e); + } } @Override @@ -404,7 +451,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac @Override public boolean showBeforeProvisioning() { - return true; + return false; } }; } @@ -423,36 +470,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); + } } } } @@ -581,8 +630,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac void onPress(); - public boolean onLongPress(); - /** * @return whether this action should appear in the dialog when the keygaurd * is showing. @@ -599,6 +646,13 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } /** + * An action that also supports long press. + */ + private interface LongPressAction extends Action { + boolean onLongPress(); + } + + /** * A single press action maintains no state, just responds to a press * and takes an action. */ @@ -633,12 +687,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac return true; } - abstract public void onPress(); - - public boolean onLongPress() { - return false; + public String getStatus() { + return null; } + abstract public void onPress(); + public View create( Context context, View convertView, ViewGroup parent, LayoutInflater inflater) { View v = inflater.inflate(R.layout.global_actions_item, parent, false); @@ -646,12 +700,18 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac ImageView icon = (ImageView) v.findViewById(R.id.icon); TextView messageView = (TextView) v.findViewById(R.id.message); - v.findViewById(R.id.status).setVisibility(View.GONE); + TextView statusView = (TextView) v.findViewById(R.id.status); + final String status = getStatus(); + if (!TextUtils.isEmpty(status)) { + statusView.setText(status); + } else { + statusView.setVisibility(View.GONE); + } if (mIcon != null) { 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 +801,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); } @@ -767,10 +827,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac changeStateFromPress(nowOn); } - public boolean onLongPress() { - return false; - } - public boolean isEnabled() { return !mState.inTransition(); } @@ -860,10 +916,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public void onPress() { } - public boolean onLongPress() { - return false; - } - public boolean showDuringKeyguard() { return true; } diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java index 3cf7e82..8c8209f 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java +++ b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java @@ -30,6 +30,7 @@ import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.io.PrintWriter; /** * Stores a mapping of global keys. @@ -123,4 +124,21 @@ final class GlobalKeyManager { } } } + + public void dump(String prefix, PrintWriter pw) { + final int numKeys = mKeyMapping.size(); + if (numKeys == 0) { + pw.print(prefix); pw.println("mKeyMapping.size=0"); + return; + } + pw.print(prefix); pw.println("mKeyMapping={"); + for (int i = 0; i < numKeys; ++i) { + pw.print(" "); + pw.print(prefix); + pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i))); + pw.print("="); + pw.println(mKeyMapping.valueAt(i).flattenToString()); + } + pw.print(prefix); pw.println("}"); + } } 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/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java index 417527c..f291e89 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -24,6 +24,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.media.AudioManager; import android.media.IAudioService; +import android.media.session.MediaSessionLegacyHelper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -70,19 +71,19 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { return onKeyUp(keyCode, event); } } - + boolean onKeyDown(int keyCode, KeyEvent event) { /* **************************************************************************** * HOW TO DECIDE WHERE YOUR KEY HANDLING GOES. * See the comment in PhoneWindow.onKeyDown * ****************************************************************************/ final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState(); - + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE); + MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); return true; } @@ -156,7 +157,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { if (event.getRepeatCount() == 0) { dispatcher.startTracking(event, this); } else if (event.isLongPress() && dispatcher.isTracking(event)) { - Configuration config = mContext.getResources().getConfiguration(); + Configuration config = mContext.getResources().getConfiguration(); if (config.keyboard == Configuration.KEYBOARD_NOKEYS || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) { // launch the search activity @@ -191,17 +192,13 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { if (dispatcher != null) { dispatcher.handleUpEvent(event); } - + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { if (!event.isCanceled()) { - AudioManager audioManager = (AudioManager)mContext.getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE); - } + MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); } return true; } @@ -277,30 +274,20 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { } return mKeyguardManager; } - + AudioManager getAudioManager() { if (mAudioManager == null) { mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); } return mAudioManager; } - + void sendCloseSystemWindows() { PhoneWindowManager.sendCloseSystemWindows(mContext, null); } private void handleMediaKeyEvent(KeyEvent keyEvent) { - IAudioService audioService = IAudioService.Stub.asInterface( - ServiceManager.checkService(Context.AUDIO_SERVICE)); - if (audioService != null) { - try { - audioService.dispatchMediaKeyEvent(keyEvent); - } catch (RemoteException e) { - Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e); - } - } else { - Slog.w(TAG, "Unable to find IAudioService for media key event."); - } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); } } 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 fe3021b..1e61236 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; @@ -34,37 +32,41 @@ import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; -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; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.content.res.Resources; +import android.content.res.Resources.Theme; 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.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.MediaSessionLegacyHelper; 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; @@ -83,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; @@ -116,6 +119,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static boolean SWEEP_OPEN_MENU = false; + private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300; + + private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES | + (1 << FEATURE_CUSTOM_TITLE) | + (1 << FEATURE_CONTENT_TRANSITIONS) | + (1 << FEATURE_ACTION_MODE_OVERLAY); + /** * Simple callback used by the context menu and its submenus. The options * menu submenus do not use this (their behavior is more complex). @@ -138,19 +148,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; @@ -196,21 +209,28 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private Drawable mBackgroundDrawable; + private float mElevation; + 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; private int mTitleColor = 0; private boolean mAlwaysReadCloseOnTouchAttr = false; - + private ContextMenuBuilder mContextMenu; private MenuDialogHelper mContextMenuHelper; private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; + private MediaController mMediaController; private AudioManager mAudioManager; private KeyguardManager mKeyguardManager; @@ -231,6 +251,14 @@ 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; + private long mBackgroundFadeDurationMillis = -1; + static class WindowManagerHolder { static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); @@ -254,16 +282,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { throw new AndroidRuntimeException("requestFeature() must be called before adding content"); } final int features = getFeatures(); - if ((features != DEFAULT_FEATURES) && (featureId == FEATURE_CUSTOM_TITLE)) { - - /* Another feature is enabled and the user is trying to enable the custom title feature */ - throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); - } - if (((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) && - (featureId != FEATURE_CUSTOM_TITLE) && (featureId != FEATURE_ACTION_MODE_OVERLAY)) { - - /* Custom title feature is enabled and the user is trying to enable another feature */ - throw new AndroidRuntimeException("You cannot combine custom titles with other title features"); + final int newFeatures = features | (1 << featureId); + if ((newFeatures & (1 << FEATURE_CUSTOM_TITLE)) != 0 && + (newFeatures & ~CUSTOM_TITLE_COMPATIBLE_FEATURES) != 0) { + // Another feature is enabled and the user is trying to enable the custom title feature + // or custom title feature is enabled and the user is trying to enable another feature + throw new AndroidRuntimeException( + "You cannot combine custom titles with other title features"); } if ((features & (1 << FEATURE_NO_TITLE)) != 0 && featureId == FEATURE_ACTION_BAR) { return false; // Ignore. No title dominates. @@ -300,13 +325,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(); @@ -320,12 +370,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(); @@ -337,6 +397,10 @@ 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. + Log.v(TAG, "addContentView does not support content transitions"); + } mContentParent.addView(view, params); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { @@ -344,6 +408,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; @@ -353,11 +426,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; @@ -378,13 +451,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); @@ -410,7 +484,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (st.isPrepared) { return true; } - + if ((mPreparedPanel != null) && (mPreparedPanel != st)) { // Another Panel is prepared and possibly open, so close it closePanel(mPreparedPanel, false); @@ -425,10 +499,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) { @@ -440,11 +514,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. @@ -456,14 +530,14 @@ 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; } - + st.refreshMenuContent = false; } @@ -481,10 +555,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; @@ -509,7 +583,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) { @@ -555,18 +629,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Causes the decor view to be recreated st.refreshDecorView = true; - + st.clearMenuPresenters(); } @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); } @@ -643,7 +715,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(); @@ -695,10 +767,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 { @@ -720,7 +792,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; } @@ -766,7 +838,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); @@ -809,10 +881,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } st.refreshMenuContent = true; st.refreshDecorView = true; - + // 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; @@ -820,7 +892,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } } - + /** * Called when the panel key is pushed down. * @param featureId The feature ID of the relevant panel (defaults to FEATURE_OPTIONS_PANEL}. @@ -829,7 +901,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public final boolean onKeyDownPanel(int featureId, KeyEvent event) { final int keyCode = event.getKeyCode(); - + if (event.getRepeatCount() == 0) { // The panel key was pushed, so set the chording key mPanelChordingKey = keyCode; @@ -856,20 +928,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (event.isCanceled() || (mDecor != null && mDecor.mActionMode != null)) { return; } - + 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) { @@ -982,7 +1052,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); } } @@ -1004,7 +1074,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); } @@ -1039,12 +1109,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) { @@ -1059,11 +1129,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,22 +1168,40 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { protected boolean initializePanelMenu(final PanelFeatureState st) { Context context = getContext(); - // If we have an action bar, initialize the menu with a context themed for it. + // If we have an action bar, initialize the menu with the right theme. if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) && - mActionBar != null) { - TypedValue outValue = new TypedValue(); - Resources.Theme currentTheme = context.getTheme(); - currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme, - outValue, true); - final int targetThemeRes = outValue.resourceId; + mDecorContentParent != null) { + final TypedValue outValue = new TypedValue(); + final Theme baseTheme = context.getTheme(); + baseTheme.resolveAttribute(com.android.internal.R.attr.actionBarTheme, outValue, true); + + Theme widgetTheme = null; + if (outValue.resourceId != 0) { + widgetTheme = context.getResources().newTheme(); + widgetTheme.setTo(baseTheme); + widgetTheme.applyStyle(outValue.resourceId, true); + widgetTheme.resolveAttribute( + com.android.internal.R.attr.actionBarWidgetTheme, outValue, true); + } else { + baseTheme.resolveAttribute( + com.android.internal.R.attr.actionBarWidgetTheme, outValue, true); + } - if (targetThemeRes != 0 && context.getThemeResId() != targetThemeRes) { - context = new ContextThemeWrapper(context, targetThemeRes); + if (outValue.resourceId != 0) { + if (widgetTheme == null) { + widgetTheme = context.getResources().newTheme(); + widgetTheme.setTo(baseTheme); + } + widgetTheme.applyStyle(outValue.resourceId, true); + } + + if (widgetTheme != null) { + context = new ContextThemeWrapper(context, 0); + context.getTheme().setTo(widgetTheme); } } final MenuBuilder menu = new MenuBuilder(context); - menu.setCallback(this); st.setMenu(menu); @@ -1228,7 +1316,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 { @@ -1373,30 +1461,58 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final int features = getLocalFeatures(); if (value == PROGRESS_VISIBILITY_ON) { if ((features & (1 << FEATURE_PROGRESS)) != 0) { - int level = horizontalProgressBar.getProgress(); - int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? - View.VISIBLE : View.INVISIBLE; - horizontalProgressBar.setVisibility(visibility); + if (horizontalProgressBar != null) { + int level = horizontalProgressBar.getProgress(); + int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? + View.VISIBLE : View.INVISIBLE; + horizontalProgressBar.setVisibility(visibility); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } } if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - circularProgressBar.setVisibility(View.VISIBLE); + if (circularProgressBar != null) { + circularProgressBar.setVisibility(View.VISIBLE); + } else { + Log.e(TAG, "Circular progress bar not located in current window decor"); + } } } else if (value == PROGRESS_VISIBILITY_OFF) { if ((features & (1 << FEATURE_PROGRESS)) != 0) { - horizontalProgressBar.setVisibility(View.GONE); + if (horizontalProgressBar != null) { + horizontalProgressBar.setVisibility(View.GONE); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } } if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) { - circularProgressBar.setVisibility(View.GONE); + if (circularProgressBar != null) { + circularProgressBar.setVisibility(View.GONE); + } else { + Log.e(TAG, "Circular progress bar not located in current window decor"); + } } } else if (value == PROGRESS_INDETERMINATE_ON) { - horizontalProgressBar.setIndeterminate(true); + if (horizontalProgressBar != null) { + horizontalProgressBar.setIndeterminate(true); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } } else if (value == PROGRESS_INDETERMINATE_OFF) { - horizontalProgressBar.setIndeterminate(false); + if (horizontalProgressBar != null) { + horizontalProgressBar.setIndeterminate(false); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } } else if (PROGRESS_START <= value && value <= PROGRESS_END) { // We want to set the progress value before testing for visibility // so that when the progress bar becomes visible again, it has the // correct level. - horizontalProgressBar.setProgress(value - PROGRESS_START); + if (horizontalProgressBar != null) { + horizontalProgressBar.setProgress(value - PROGRESS_START); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } if (value < PROGRESS_END) { showProgressBars(horizontalProgressBar, circularProgressBar); @@ -1404,7 +1520,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { hideProgressBars(horizontalProgressBar, circularProgressBar); } } else if (PROGRESS_SECONDARY_START <= value && value <= PROGRESS_SECONDARY_END) { - horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); + if (horizontalProgressBar != null) { + horizontalProgressBar.setSecondaryProgress(value - PROGRESS_SECONDARY_START); + } else { + Log.e(TAG, "Horizontal progress bar not located in current window decor"); + } showProgressBars(horizontalProgressBar, circularProgressBar); } @@ -1414,11 +1534,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private void showProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) { final int features = getLocalFeatures(); if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && - spinnyProgressBar.getVisibility() == View.INVISIBLE) { + spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.INVISIBLE) { spinnyProgressBar.setVisibility(View.VISIBLE); } // Only show the progress bars if the primary progress is not complete - if ((features & (1 << FEATURE_PROGRESS)) != 0 && + if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null && horizontalProgressBar.getProgress() < 10000) { horizontalProgressBar.setVisibility(View.VISIBLE); } @@ -1429,11 +1549,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out); anim.setDuration(1000); if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar != null && spinnyProgressBar.getVisibility() == View.VISIBLE) { spinnyProgressBar.startAnimation(anim); spinnyProgressBar.setVisibility(View.INVISIBLE); } - if ((features & (1 << FEATURE_PROGRESS)) != 0 && + if ((features & (1 << FEATURE_PROGRESS)) != 0 && horizontalProgressBar != null && horizontalProgressBar.getVisibility() == View.VISIBLE) { horizontalProgressBar.startAnimation(anim); horizontalProgressBar.setVisibility(View.INVISIBLE); @@ -1445,8 +1566,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); } } @@ -1456,13 +1577,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; } } @@ -1472,8 +1594,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); } } @@ -1483,8 +1605,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); } } @@ -1570,18 +1692,46 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mDecor != null ? mDecor.getKeyDispatcherState() : null; //Log.i(TAG, "Key down: repeat=" + event.getRepeatCount() // + " flags=0x" + Integer.toHexString(event.getFlags())); - + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + int direction = keyCode == KeyEvent.KEYCODE_VOLUME_UP ? AudioManager.ADJUST_RAISE + : AudioManager.ADJUST_LOWER; + // If we have a session send it the volume command, otherwise + // use the suggested stream. + if (mMediaController != null) { + mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI); + } else { + MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy( + mVolumeControlStreamType, direction, AudioManager.FLAG_SHOW_UI); + } + return true; + } case KeyEvent.KEYCODE_VOLUME_MUTE: { - // Similar code is in PhoneFallbackEventHandler in case the window - // doesn't have one of these. In this case, we execute it here and - // eat the event instead, because we have mVolumeControlStreamType - // and they don't. getAudioManager().handleKeyDown(event, mVolumeControlStreamType); return true; } + // These are all the recognized media key codes in + // KeyEvent.isMediaKey() + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + if (mMediaController != null) { + if (mMediaController.dispatchMediaButtonEvent(event)) { + return true; + } + } + return false; + } case KeyEvent.KEYCODE_MENU: { onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event); @@ -1632,10 +1782,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } //Log.i(TAG, "Key up: repeat=" + event.getRepeatCount() // + " flags=0x" + Integer.toHexString(event.getFlags())); - + switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_DOWN: { + // If we have a session send it the volume command, otherwise + // use the suggested stream. + if (mMediaController != null) { + mMediaController.adjustVolume(0, AudioManager.FLAG_PLAY_SOUND + | AudioManager.FLAG_VIBRATE); + } else { + MediaSessionLegacyHelper.getHelper(getContext()).sendAdjustVolumeBy( + mVolumeControlStreamType, 0, + AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE); + } + return true; + } case KeyEvent.KEYCODE_VOLUME_MUTE: { // Similar code is in PhoneFallbackEventHandler in case the window // doesn't have one of these. In this case, we execute it here and @@ -1644,6 +1806,26 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { getAudioManager().handleKeyUp(event, mVolumeControlStreamType); return true; } + // These are all the recognized media key codes in + // KeyEvent.isMediaKey() + case KeyEvent.KEYCODE_MEDIA_PLAY: + case KeyEvent.KEYCODE_MEDIA_PAUSE: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + case KeyEvent.KEYCODE_MUTE: + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_STOP: + case KeyEvent.KEYCODE_MEDIA_NEXT: + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + case KeyEvent.KEYCODE_MEDIA_REWIND: + case KeyEvent.KEYCODE_MEDIA_RECORD: + case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { + if (mMediaController != null) { + if (mMediaController.dispatchMediaButtonEvent(event)) { + return true; + } + } + return false; + } case KeyEvent.KEYCODE_MENU: { onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId, @@ -1741,9 +1923,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); } @@ -1782,11 +1964,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."); @@ -1916,7 +2098,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 */ @@ -1946,6 +2129,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; @@ -2051,12 +2242,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. @@ -2066,17 +2252,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) { @@ -2203,7 +2381,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (!AccessibilityManager.getInstance(mContext).isEnabled()) { return; } - + // if we are showing a feature that should be announced and one child // make this child the event source since this is the feature itself // otherwise the callback will take over and announce its client @@ -2260,7 +2438,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) { @@ -2277,6 +2455,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; + final int widthMode = getMode(widthMeasureSpec); final int heightMode = getMode(heightMeasureSpec); @@ -2323,17 +2502,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mOutsetBottom != null) { int mode = MeasureSpec.getMode(heightMeasureSpec); - if (mode != MeasureSpec.UNSPECIFIED && !isPortrait) { + if (mode != MeasureSpec.UNSPECIFIED) { int outset = (int) mOutsetBottom.getDimension(metrics); int height = MeasureSpec.getSize(heightMeasureSpec); heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode); } - mode = MeasureSpec.getMode(widthMeasureSpec); - if (mode != MeasureSpec.UNSPECIFIED && isPortrait) { - int outset = (int) mOutsetBottom.getDimension(metrics); - int width = MeasureSpec.getSize(widthMeasureSpec); - widthMeasureSpec = MeasureSpec.makeMeasureSpec(width + outset, mode); - } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -2532,17 +2705,80 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override - protected boolean fitSystemWindows(Rect insets) { - mFrameOffsets.set(insets); - updateStatusGuard(insets); + public void onSystemUiVisibilityChange(int visible) { + mLastSystemUiVisibility = visible; + updateColorViews(null /* insets */); + } + + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + mFrameOffsets.set(insets.getSystemWindowInsets()); + updateColorViews(insets); + insets = updateStatusGuard(insets); updateNavigationGuard(insets); if (getForeground() != null) { drawableChanged(); } - return super.fitSystemWindows(insets); + return insets; } - private void updateStatusGuard(Rect insets) { + @Override + public boolean isTransitionGroup() { + return false; + } + + private WindowInsets updateColorViews(WindowInsets insets) { + if (!mIsFloating && ActivityManager.isHighEndGfx()) { + if (insets != null) { + mLastTopInset = insets.getStableInsetTop(); + mLastBottomInset = insets.getStableInsetBottom(); + } + mStatusColorView = updateColorViewInt(mStatusColorView, + SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS, + mStatusBarColor, mLastTopInset, Gravity.TOP, + STATUS_BAR_BACKGROUND_TRANSITION_NAME); + mNavigationColorView = updateColorViewInt(mNavigationColorView, + SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION, + mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM, + NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME); + } + if (insets != null) { + insets = insets.consumeStableInsets(); + } + return insets; + } + + private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag, + int color, int height, int verticalGravity, String transitionName) { + 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); + view.setTransitionName(transitionName); + 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 WindowInsets updateStatusGuard(WindowInsets insets) { boolean showStatusGuard = false; // Show the status guard when the non-overlay contextual action bar is showing if (mActionModeView != null) { @@ -2554,16 +2790,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { && mActionModeView.isShown(); if (nonOverlayShown) { // set top margin to top insets, show status guard - if (mlp.topMargin != insets.top) { + if (mlp.topMargin != insets.getSystemWindowInsetTop()) { mlpChanged = true; - mlp.topMargin = insets.top; + mlp.topMargin = insets.getSystemWindowInsetTop(); if (mStatusGuard == null) { 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) { @@ -2572,7 +2808,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } } - insets.top = 0; // consume top insets + insets = insets.consumeSystemWindowInsets( + false, true /* top */, false, false); showStatusGuard = true; } else { // reset top margin @@ -2589,9 +2826,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mStatusGuard != null) { mStatusGuard.setVisibility(showStatusGuard ? View.VISIBLE : View.GONE); } + return insets; } - private void updateNavigationGuard(Rect insets) { + private void updateNavigationGuard(WindowInsets insets) { // IMEs lay out below the nav bar, but the content view must not (for back compat) if (getAttributes().type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) { // prevent the content view from including the nav bar height @@ -2599,7 +2837,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (mContentParent.getLayoutParams() instanceof MarginLayoutParams) { MarginLayoutParams mlp = (MarginLayoutParams) mContentParent.getLayoutParams(); - mlp.bottomMargin = insets.bottom; + mlp.bottomMargin = insets.getSystemWindowInsetBottom(); mContentParent.setLayoutParams(mlp); } } @@ -2608,12 +2846,12 @@ 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( - LayoutParams.MATCH_PARENT, insets.bottom, + addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams( + LayoutParams.MATCH_PARENT, insets.getSystemWindowInsetBottom(), Gravity.START | Gravity.BOTTOM)); } else { LayoutParams lp = (LayoutParams) mNavigationGuard.getLayoutParams(); - lp.height = insets.bottom; + lp.height = insets.getSystemWindowInsetBottom(); mNavigationGuard.setLayoutParams(lp); } } @@ -2701,13 +2939,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { hackTurnOffWindowResizeAnim(bg == null || bg.getOpacity() != PixelFormat.OPAQUE); } - + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - + updateWindowResizeState(); - + final Callback cb = getCallback(); if (cb != null && !isDestroyed() && mFeatureId < 0) { cb.onAttachedToWindow(); @@ -2728,14 +2966,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - + final Callback cb = getCallback(); if (cb != null && mFeatureId < 0) { cb.onDetachedFromWindow(); } - if (mActionBar != null) { - mActionBar.dismissPopupMenus(); + if (mDecorContentParent != null) { + mDecorContentParent.dismissPopups(); } if (mActionModePopup != null) { @@ -2762,19 +3000,19 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() { return mFeatureId < 0 ? mTakeSurfaceCallback : null; } - + public InputQueue.Callback willYouTakeTheInputQueue() { return mFeatureId < 0 ? mTakeInputQueueCallback : null; } - + public void setSurfaceType(int type) { PhoneWindow.this.setType(type); } - + public void setSurfaceFormat(int format) { PhoneWindow.this.setFormat(format); } - + public void setSurfaceKeepScreenOn(boolean keepOn) { if (keepOn) PhoneWindow.this.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); else PhoneWindow.this.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); @@ -2942,6 +3180,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); + } final WindowManager windowService = (WindowManager) getContext().getSystemService( Context.WINDOW_SERVICE); @@ -2959,6 +3200,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); @@ -2968,7 +3210,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( @@ -2977,7 +3237,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { setCloseOnTouchOutsideIfNotSet(true); } } - + WindowManager.LayoutParams params = getAttributes(); if (!hasSoftInputMode()) { @@ -3020,6 +3280,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { + Integer.toHexString(mFrameResource)); } } + mElevation = a.getDimension(com.android.internal.R.styleable.Window_windowElevation, 0); mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000); } @@ -3070,7 +3331,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { com.android.internal.R.attr.dialogTitleDecorLayout, res, true); layoutResource = res.resourceId; } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { - layoutResource = com.android.internal.R.layout.screen_action_bar; + layoutResource = a.getResourceId( + com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout, + com.android.internal.R.layout.screen_action_bar); } else { layoutResource = com.android.internal.R.layout.screen_title; } @@ -3107,28 +3370,31 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // Remaining setup -- of background and title -- that only applies // to top-level windows. if (getContainer() == null) { - Drawable drawable = mBackgroundDrawable; + final Drawable background; if (mBackgroundResource != 0) { - drawable = getContext().getResources().getDrawable(mBackgroundResource); + background = getContext().getDrawable(mBackgroundResource); + } else { + background = mBackgroundDrawable; } - mDecor.setWindowBackground(drawable); - drawable = null; + mDecor.setWindowBackground(background); + + final Drawable frame; if (mFrameResource != 0) { - drawable = getContext().getResources().getDrawable(mFrameResource); + frame = getContext().getDrawable(mFrameResource); + } else { + frame = null; } - mDecor.setWindowFrame(drawable); + mDecor.setWindowFrame(frame); - // System.out.println("Text=" + Integer.toHexString(mTextColor) + - // " Sel=" + Integer.toHexString(mTextSelectedColor) + - // " Title=" + Integer.toHexString(mTitleColor)); - - if (mTitleColor == 0) { - mTitleColor = mTextColor; - } + mDecor.setElevation(mElevation); if (mTitle != null) { setTitle(mTitle); } + + if (mTitleColor == 0) { + mTitleColor = mTextColor; + } setTitleColor(mTitleColor); } @@ -3157,101 +3423,128 @@ 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); + } + if (mBackgroundFadeDurationMillis < 0) { + mBackgroundFadeDurationMillis = getWindowStyle().getInteger( + com.android.internal.R.styleable. + Window_windowTransitionBackgroundFadeDuration, + DEFAULT_BACKGROUND_FADE_DURATION_MS); } } } } + 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( @@ -3422,6 +3715,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; @@ -3567,6 +3868,96 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return mVolumeControlStreamType; } + @Override + public void setMediaController(MediaController controller) { + mMediaController = controller; + } + + @Override + public MediaController getMediaController() { + return mMediaController; + } + + 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; + } + + @Override + public long getTransitionBackgroundFadeDuration() { + return (mBackgroundFadeDurationMillis < 0) ? DEFAULT_BACKGROUND_FADE_DURATION_MS + : mBackgroundFadeDurationMillis; + } + + @Override + public void setTransitionBackgroundFadeDuration(long fadeDurationMillis) { + if (fadeDurationMillis < 0) { + throw new IllegalArgumentException("negative durations are not allowed"); + } + mBackgroundFadeDurationMillis = fadeDurationMillis; + } + private static final class DrawableFeatureState { DrawableFeatureState(int _featureId) { featureId = _featureId; @@ -3658,11 +4049,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { boolean refreshDecorView; boolean refreshMenuContent; - + boolean wasLastOpen; - + boolean wasLastExpanded; - + /** * Contains the state of the menu when told to freeze. */ @@ -4000,4 +4391,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 44ea4f3..a3c84c6 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -42,15 +42,18 @@ import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; import android.media.AudioManager; -import android.media.AudioSystem; import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; +import android.media.session.MediaController; +import android.media.session.MediaSession; +import android.media.session.MediaSessionLegacyHelper; +import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; import android.os.Bundle; import android.os.FactoryTest; import android.os.Handler; import android.os.IBinder; -import android.os.IRemoteCallback; import android.os.Looper; import android.os.Message; import android.os.Messenger; @@ -63,8 +66,10 @@ import android.os.UEventObserver; import android.os.UserHandle; import android.os.Vibrator; import android.provider.Settings; +import android.service.dreams.DreamManagerInternal; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; +import android.telecomm.TelecommManager; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; @@ -92,15 +97,17 @@ import android.view.WindowManagerGlobal; import android.view.WindowManagerInternal; 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.policy.impl.keyguard.KeyguardServiceDelegate.ShowListener; import com.android.internal.statusbar.IStatusBarService; -import com.android.internal.telephony.ITelephony; import com.android.internal.widget.PointerLocationView; import com.android.server.LocalServices; @@ -110,6 +117,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; @@ -177,12 +185,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. * @@ -219,11 +230,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowManagerFuncs mWindowManagerFuncs; WindowManagerInternal mWindowManagerInternal; PowerManager mPowerManager; + DreamManagerInternal mDreamManagerInternal; IStatusBarService mStatusBarService; boolean mPreloadedRecentApps; 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; @@ -234,6 +247,12 @@ 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 a short vibration when tapping on a day/month/year date of a Calendar. + long[] mCalendarDateVibePattern; + // Vibrator pattern for haptic feedback during boot when safe mode is disabled. long[] mSafeModeDisabledVibePattern; @@ -254,15 +273,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { int[] mNavigationBarHeightForRotation = new int[4]; int[] mNavigationBarWidthForRotation = new int[4]; - WindowState mKeyguard = null; KeyguardServiceDelegate mKeyguardDelegate; // The following are only accessed on the mHandler thread. boolean mKeyguardDrawComplete; boolean mWindowManagerDrawComplete; - ArrayList<ScreenOnListener> mScreenOnListeners = new ArrayList<ScreenOnListener>(); - final IRemoteCallback mWindowManagerDrawCallback = new IRemoteCallback.Stub() { + ScreenOnListener mScreenOnListener; + final Runnable mWindowManagerDrawCallback = new Runnable() { @Override - public void sendResult(Bundle data) { + public void run() { if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!"); mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE); } @@ -282,13 +300,8 @@ 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; + boolean mRecentsVisible; + int mRecentAppsHeldModifiers; boolean mLanguageSwitchKeyPressed; int mLidState = LID_ABSENT; @@ -307,6 +320,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mDemoHdmiRotation; boolean mDemoHdmiRotationLock; + boolean mWakeGestureEnabledSetting; + MyWakeGestureListener mWakeGestureListener; + // Default display does not rotate, apps that require non-default orientation will have to // have the orientation emulated. private boolean mForceDefaultOrientation = false; @@ -329,7 +345,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 @@ -338,17 +353,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 @@ -385,6 +389,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the same as mCur*, but may be larger if the screen decor has supplied // content insets. int mContentLeft, mContentTop, mContentRight, mContentBottom; + // During layout, the frame in which voice content should be displayed + // to the user, accounting for all screen decoration except for any + // space they deem as available for other content. + int mVoiceContentLeft, mVoiceContentTop, mVoiceContentRight, mVoiceContentBottom; // During layout, the current screen borders along which input method // windows are placed. int mDockLeft, mDockTop, mDockRight, mDockBottom; @@ -411,6 +419,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final Rect mTmpContentFrame = new Rect(); static final Rect mTmpVisibleFrame = new Rect(); static final Rect mTmpDecorFrame = new Rect(); + static final Rect mTmpStableFrame = new Rect(); static final Rect mTmpNavigationFrame = new Rect(); WindowState mTopFullscreenOpaqueWindowState; @@ -432,6 +441,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { * be done once per window. */ private WindowState mWinDismissingKeyguard; + /** The window that is currently showing "over" the keyguard. If there is an app window + * belonging to another app on top of this the keyguard shows. If there is a fullscreen + * app window under this, still dismiss the keyguard but don't show the app underneath. Show + * the wallpaper. */ + private WindowState mWinShowWhenLocked; + boolean mShowingLockscreen; boolean mShowingDream; boolean mDreamingLockscreen; @@ -444,6 +459,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSearchKeyShortcutPending; boolean mConsumeSearchKeyUp; boolean mAssistKeyLongPressed; + boolean mPendingMetaAction; // support for activating the lock screen while the screen is on boolean mAllowLockscreenWhenOn; @@ -513,6 +529,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6; private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7; private static final int MSG_WAKING_UP = 8; + private static final int MSG_DISPATCH_SHOW_RECENTS = 9; + private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10; private class PolicyHandler extends Handler { @Override @@ -530,6 +548,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK: dispatchMediaKeyRepeatWithWakeLock((KeyEvent)msg.obj); break; + case MSG_DISPATCH_SHOW_RECENTS: + showRecentApps(false); + break; + case MSG_DISPATCH_SHOW_GLOBAL_ACTIONS: + showGlobalActionsInternal(); + break; case MSG_KEYGUARD_DRAWN_COMPLETE: if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mKeyguardDrawComplete"); mKeyguardDrawComplete = true; @@ -574,6 +598,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.WAKE_GESTURE_ENABLED), false, this, + UserHandle.USER_ALL); resolver.registerContentObserver(Settings.System.getUriFor( Settings.System.ACCELEROMETER_ROTATION), false, this, UserHandle.USER_ALL); @@ -589,9 +616,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(); } @@ -601,6 +631,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + class MyWakeGestureListener extends WakeGestureListener { + MyWakeGestureListener(Context context, Handler handler) { + super(context, handler); + } + + @Override + public void onWakeUp() { + synchronized (mLock) { + if (shouldEnableWakeGestureLp()) { + performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); + mPowerManager.wakeUp(SystemClock.uptimeMillis()); + } + } + } + } + class MyOrientationListener extends WindowOrientationListener { MyOrientationListener(Context context, Handler handler) { super(context, handler); @@ -820,8 +866,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { performAuditoryFeedbackForAccessibilityIfNeed(); } - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - showGlobalActionsDialog(); + showGlobalActionsInternal(); break; case LONG_PRESS_POWER_SHUT_OFF: case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: @@ -841,7 +886,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } }; - void showGlobalActionsDialog() { + @Override + public void showGlobalActions() { + mHandler.removeMessages(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS); + mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS); + } + + void showGlobalActionsInternal() { + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } @@ -859,6 +911,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; @@ -889,52 +946,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, @@ -943,8 +954,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManager = windowManager; mWindowManagerFuncs = windowManagerFuncs; mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class); mHandler = new PolicyHandler(); + mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mOrientationListener = new MyOrientationListener(mContext, mHandler); try { mOrientationListener.setCurrentRotation(windowManager.getRotation()); @@ -996,6 +1009,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); @@ -1056,6 +1072,10 @@ 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); + mCalendarDateVibePattern = getLongIntArray(mContext.getResources(), + com.android.internal.R.array.config_calendarDateVibePattern); mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), com.android.internal.R.array.config_safeModeDisabledVibePattern); mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), @@ -1194,7 +1214,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 @@ -1225,6 +1246,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT, UserHandle.USER_CURRENT); + // Configure wake gesture. + boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver, + Settings.Secure.WAKE_GESTURE_ENABLED, 0, + UserHandle.USER_CURRENT) != 0; + if (mWakeGestureEnabledSetting != wakeGestureEnabledSetting) { + mWakeGestureEnabledSetting = wakeGestureEnabledSetting; + updateWakeGestureListenerLp(); + } + // Configure rotation lock. int userRotation = Settings.System.getIntForUser(resolver, Settings.System.USER_ROTATION, Surface.ROTATION_0, @@ -1263,19 +1293,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation = true; } if (mImmersiveModeConfirmation != null) { - mImmersiveModeConfirmation.loadSetting(); + mImmersiveModeConfirmation.loadSetting(mCurrentUserId); } + PolicyControl.reloadFromSetting(mContext); } if (updateRotation) { updateRotation(true); } } + private void updateWakeGestureListenerLp() { + if (shouldEnableWakeGestureLp()) { + mWakeGestureListener.requestWakeUpTrigger(); + } else { + mWakeGestureListener.cancelWakeUpTrigger(); + } + } + + private boolean shouldEnableWakeGestureLp() { + return mWakeGestureEnabledSetting && !mScreenOnEarly + && (!mLidControlsSleep || mLidState != LID_CLOSED) + && mWakeGestureListener.isSupported(); + } + private void enablePointerLocation() { if (mPointerLocationView == null) { mPointerLocationView = new PointerLocationView(mContext); mPointerLocationView.setPrintCoords(false); - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); @@ -1295,22 +1339,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; } @@ -1352,11 +1388,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { // XXX right now the app process has complete control over // this... should introduce a token to let the system // monitor/control what they are doing. + outAppOp[0] = AppOpsManager.OP_TOAST_WINDOW; break; case TYPE_DREAM: case TYPE_INPUT_METHOD: case TYPE_WALLPAPER: case TYPE_PRIVATE_PRESENTATION: + case TYPE_VOICE_INTERACTION: // The window manager will check these. break; case TYPE_PHONE: @@ -1402,7 +1440,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: @@ -1439,13 +1476,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: @@ -1501,41 +1561,40 @@ public class PhoneWindowManager implements WindowManagerPolicy { return 3; case TYPE_SEARCH_BAR: return 4; + case TYPE_VOICE_INTERACTION: + // voice interaction layer is almost immediately above apps. + return 5; case TYPE_RECENTS_OVERLAY: case TYPE_SYSTEM_DIALOG: - return 5; + return 6; case TYPE_TOAST: // toasts and the plugged-in battery thing - return 6; + return 7; case TYPE_PRIORITY_PHONE: // SIM errors and unlock. Not sure if this really should be in a high layer. - return 7; + return 8; case TYPE_DREAM: // used for Dreams (screensavers with TYPE_DREAM windows) - return 8; + return 9; case TYPE_SYSTEM_ALERT: // like the ANR / app crashed dialogs - return 9; + return 10; case TYPE_INPUT_METHOD: // on-screen keyboards and other such input method user interfaces go here. - return 10; + return 11; case TYPE_INPUT_METHOD_DIALOG: // on-screen keyboards and other such input method user interfaces go here. - return 11; + return 12; 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. return 13; - case TYPE_KEYGUARD_DIALOG: - return 14; case TYPE_STATUS_BAR_SUB_PANEL: - return 15; + return 14; case TYPE_STATUS_BAR: - return 16; + return 15; case TYPE_STATUS_BAR_PANEL: + return 16; + case TYPE_KEYGUARD_DIALOG: return 17; case TYPE_VOLUME_OVERLAY: // the on-screen volume indicator and controller shown when the user @@ -1606,6 +1665,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return windowTypeToLayerLw(TYPE_SYSTEM_ERROR); } + @Override public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) { if (mHasNavigationBar) { // For a basic navigation bar, when we are in landscape mode we place @@ -1617,6 +1677,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return fullWidth; } + @Override public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) { if (mHasNavigationBar) { // For a basic navigation bar, when we are in portrait mode we place @@ -1628,10 +1689,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return fullHeight; } + @Override public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) { return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation); } + @Override public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) { // There is a separate status bar at the top of the display. We don't count that as part // of the fixed decor, since it can hide; however, for purposes of configurations, @@ -1641,8 +1704,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { - return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; + public boolean isForceHiding(WindowManager.LayoutParams attrs) { + return (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || + (isKeyguardHostWindow(attrs) && isKeyguardSecureIncludingHidden()) || + (attrs.type == TYPE_KEYGUARD_SCRIM); + } + + @Override + public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) { + return attrs.type == TYPE_STATUS_BAR; } @Override @@ -1653,7 +1723,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: @@ -1782,6 +1851,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void removeStartingWindow(IBinder appToken, View window) { if (DEBUG_STARTING_WINDOW) { RuntimeException e = new RuntimeException("here"); @@ -1797,19 +1867,20 @@ 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 */ + @Override public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { switch (attrs.type) { case TYPE_STATUS_BAR: @@ -1823,6 +1894,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mStatusBar = win; mStatusBarController.setWindow(win); + mKeyguardDelegate.hideScrim(); break; case TYPE_NAVIGATION_BAR: mContext.enforceCallingOrSelfPermission( @@ -1852,12 +1924,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; @@ -1870,13 +1936,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void removeWindowLw(WindowState win) { 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"); @@ -1888,19 +1952,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. @@ -1986,9 +2051,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public Animation createForceHideEnterAnimation(boolean onWallpaper) { - return AnimationUtils.loadAnimation(mContext, onWallpaper - ? com.android.internal.R.anim.lock_screen_wallpaper_behind_enter - : com.android.internal.R.anim.lock_screen_behind_enter); + return AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.lock_screen_behind_enter); } private static void awakenDreams() { @@ -2007,9 +2071,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { ServiceManager.checkService(DreamService.DREAM_SERVICE)); } - static ITelephony getTelephonyService() { - return ITelephony.Stub.asInterface( - ServiceManager.checkService(Context.TELEPHONY_SERVICE)); + TelecommManager getTelecommService() { + return (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE); } static IAudioService getAudioService() { @@ -2067,6 +2130,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + // Cancel any pending meta actions if we see any other keys being pressed between the down + // of the meta key and its corresponding up. + if (mPendingMetaAction && keyCode != KeyEvent.KEYCODE_META_LEFT) { + mPendingMetaAction = false; + } + // First we always handle the home key here, so applications // can never break it, although if keyguard is on, we do let // it handle it, because that gives us the correct 5 second @@ -2090,16 +2159,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallScreen at this point, + // (The user is already on the InCallUI at this point, // and his ONLY options are to answer or reject the call.) - try { - ITelephony telephonyService = getTelephonyService(); - if (telephonyService != null && telephonyService.isRinging()) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); - return -1; - } - } catch (RemoteException ex) { - Log.w(TAG, "RemoteException from getPhoneInterface()", ex); + TelecommManager telecommManager = getTelecommService(); + if (telecommManager != null && telecommManager.isRinging()) { + Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); + return -1; } // Delay handling home if a double-tap is possible. @@ -2111,6 +2176,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } + // If there's a dream running then use home to escape the dream + // but don't actually go home. + if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) { + mDreamManagerInternal.stopDream(); + return -1; + } + // Go home! launchHomeFromHotKey(); return -1; @@ -2121,9 +2193,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; } @@ -2265,6 +2337,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF); } return -1; + } else if (keyCode == KeyEvent.KEYCODE_META_LEFT) { + if (down) { + mPendingMetaAction = true; + } else if (mPendingMetaAction) { + mPendingMetaAction = false; + launchAssistAction(); + } + return -1; } // Shortcuts are invoked through Search+key, so intercept those here @@ -2338,21 +2418,18 @@ 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); + if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) { + 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. @@ -2375,6 +2452,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } + // Reserve all the META modifier combos for system behavior + if ((metaState & KeyEvent.META_META_LEFT_ON) != 0) { + return -1; + } + // Let the application handle the key. return 0; } @@ -2467,7 +2549,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) { @@ -2525,7 +2607,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; } @@ -2534,30 +2616,64 @@ 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; + } + } + + @Override + public void showRecentApps() { + mHandler.removeMessages(MSG_DISPATCH_SHOW_RECENTS); + mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_RECENTS); + } + + 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 // before launching home mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() { + @Override public void onKeyguardExitResult(boolean success) { if (success) { try { @@ -2575,8 +2691,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); - startDockOrHome(); + if (mRecentsVisible) { + // Hide Recents and notify it to launch Home + awakenDreams(); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); + hideRecentApps(false); + } else { + // Otherwise, just launch Home + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); + startDockOrHome(); + } } } @@ -2660,6 +2784,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public int adjustSystemUiVisibilityLw(int visibility) { mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); + mRecentsVisible = (visibility & View.RECENT_APPS_VISIBLE) > 0; // Reset any bits in mForceClearingStatusBarVisibility that // are now clear. @@ -2672,8 +2797,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)) { @@ -2764,13 +2890,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { mRestrictedScreenTop = mUnrestrictedScreenTop; mRestrictedScreenWidth = mSystemGestures.screenWidth = mUnrestrictedScreenWidth; mRestrictedScreenHeight = mSystemGestures.screenHeight = mUnrestrictedScreenHeight; - mDockLeft = mContentLeft = mStableLeft = mStableFullscreenLeft + mDockLeft = mContentLeft = mVoiceContentLeft = mStableLeft = mStableFullscreenLeft = mCurLeft = mUnrestrictedScreenLeft; - mDockTop = mContentTop = mStableTop = mStableFullscreenTop + mDockTop = mContentTop = mVoiceContentTop = mStableTop = mStableFullscreenTop = mCurTop = mUnrestrictedScreenTop; - mDockRight = mContentRight = mStableRight = mStableFullscreenRight + mDockRight = mContentRight = mVoiceContentRight = mStableRight = mStableFullscreenRight = mCurRight = displayWidth - overscanRight; - mDockBottom = mContentBottom = mStableBottom = mStableFullscreenBottom + mDockBottom = mContentBottom = mVoiceContentBottom = mStableBottom = mStableFullscreenBottom = mCurBottom = displayHeight - overscanBottom; mDockLayer = 0x10000000; mStatusBarLayer = -1; @@ -2792,7 +2918,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; @@ -2845,7 +2972,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 @@ -2879,14 +3007,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // Make sure the content and current rectangles are updated to // account for the restrictions from the navigation bar. - mContentTop = mCurTop = mDockTop; - mContentBottom = mCurBottom = mDockBottom; - mContentLeft = mCurLeft = mDockLeft; - mContentRight = mCurRight = mDockRight; + mContentTop = mVoiceContentTop = mCurTop = mDockTop; + mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; + mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; + mContentRight = mVoiceContentRight = mCurRight = mDockRight; mStatusBarLayer = mNavigationBar.getSurfaceLayer(); // And compute the final frame. mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, - mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf); + mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf, + mTmpNavigationFrame); if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); if (mNavigationBarController.checkHiddenLw()) { updateSysUiVisibility = true; @@ -2911,13 +3040,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarLayer = mStatusBar.getSurfaceLayer(); // Let the status bar determine its size. - mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf); + mStatusBar.computeFrameLw(pf, df, vf, vf, vf, dcf, vf); // For layout, the status bar is always at the top with our fixed height. 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 @@ -2928,10 +3058,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // status bar is visible. mDockTop = mUnrestrictedScreenTop + mStatusBarHeight; - mContentTop = mCurTop = mDockTop; - mContentBottom = mCurBottom = mDockBottom; - mContentLeft = mCurLeft = mDockLeft; - mContentRight = mCurRight = mDockRight; + mContentTop = mVoiceContentTop = mCurTop = mDockTop; + mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom; + mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft; + mContentRight = mVoiceContentRight = mCurRight = mDockRight; if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format( @@ -3002,7 +3132,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Ungh. So to deal with that, make sure the content frame // we end up using is not covering the IM dock. cf.set(attached.getContentFrameLw()); - if (attached.getSurfaceLayer() < mDockLayer) { + if (attached.isVoiceInteraction()) { + if (cf.left < mVoiceContentLeft) cf.left = mVoiceContentLeft; + if (cf.top < mVoiceContentTop) cf.top = mVoiceContentTop; + if (cf.right > mVoiceContentRight) cf.right = mVoiceContentRight; + if (cf.bottom > mVoiceContentBottom) cf.bottom = mVoiceContentBottom; + } else if (attached.getSurfaceLayer() < mDockLayer) { if (cf.left < mContentLeft) cf.left = mContentLeft; if (cf.top < mContentTop) cf.top = mContentTop; if (cf.right > mContentRight) cf.right = mContentRight; @@ -3040,10 +3175,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override - public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, - WindowState attached) { + public void layoutWindowLw(WindowState win, WindowState attached) { // we've already done the status bar - if (win == mStatusBar || win == mNavigationBar) { + final WindowManager.LayoutParams attrs = win.getAttrs(); + if ((win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) == 0) || + win == mNavigationBar) { return; } final boolean isDefaultDisplay = win.isDefaultDisplay(); @@ -3054,9 +3190,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; @@ -3064,6 +3200,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Rect cf = mTmpContentFrame; final Rect vf = mTmpVisibleFrame; final Rect dcf = mTmpDecorFrame; + final Rect sf = mTmpStableFrame; dcf.setEmpty(); final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar @@ -3071,6 +3208,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { final int adjust = sim & SOFT_INPUT_MASK_ADJUST; + if (isDefaultDisplay) { + sf.set(mStableLeft, mStableTop, mStableRight, mStableBottom); + } else { + sf.set(mOverscanLeft, mOverscanTop, mOverscanRight, mOverscanBottom); + } + if (!isDefaultDisplay) { if (attached != null) { // If this window is attached to another, our display @@ -3113,12 +3256,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; @@ -3127,7 +3274,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 @@ -3172,9 +3319,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 @@ -3207,16 +3353,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if ((fl & FLAG_FULLSCREEN) == 0) { - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - cf.left = mDockLeft; - cf.top = mDockTop; - cf.right = mDockRight; - cf.bottom = mDockBottom; + if (win.isVoiceInteraction()) { + cf.left = mVoiceContentLeft; + cf.top = mVoiceContentTop; + cf.right = mVoiceContentRight; + cf.bottom = mVoiceContentBottom; } else { - cf.left = mContentLeft; - cf.top = mContentTop; - cf.right = mContentRight; - cf.bottom = mContentBottom; + if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + cf.left = mDockLeft; + cf.top = mDockTop; + cf.right = mDockRight; + cf.bottom = mDockBottom; + } else { + cf.left = mContentLeft; + cf.top = mContentTop; + cf.right = mContentRight; + cf.bottom = mContentBottom; + } } } else { // Full screen windows are always given a layout that is as if the @@ -3311,7 +3464,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { = mOverscanScreenTop + mOverscanScreenHeight; } else if (canHideNavigationBar() && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 - && (attrs.type == TYPE_TOAST + && (attrs.type == TYPE_STATUS_BAR + || attrs.type == TYPE_TOAST || (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 @@ -3380,7 +3534,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { pf.top = mContentTop; pf.right = mContentRight; pf.bottom = mContentBottom; - if (adjust != SOFT_INPUT_ADJUST_RESIZE) { + if (win.isVoiceInteraction()) { + df.left = of.left = cf.left = mVoiceContentLeft; + df.top = of.top = cf.top = mVoiceContentTop; + df.right = of.right = cf.right = mVoiceContentRight; + df.bottom = of.bottom = cf.bottom = mVoiceContentBottom; + } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) { df.left = of.left = cf.left = mDockLeft; df.top = of.top = cf.top = mDockTop; df.right = of.right = cf.right = mDockRight; @@ -3412,14 +3571,15 @@ 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() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString() - + " dcf=" + dcf.toShortString()); + + " dcf=" + dcf.toShortString() + + " sf=" + sf.toShortString()); - win.computeFrameLw(pf, df, of, cf, vf, dcf); + win.computeFrameLw(pf, df, of, cf, vf, dcf, sf); // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. @@ -3428,6 +3588,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { setLastInputMethodWindowLw(null, null); offsetInputMethodWindowLw(win); } + if (attrs.type == TYPE_VOICE_INTERACTION && win.isVisibleOrBehindKeyguardLw() + && !win.getGivenInsetsPendingLw()) { + offsetVoiceInputWindowLw(win); + } } private void offsetInputMethodWindowLw(WindowState win) { @@ -3436,6 +3600,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mContentBottom > top) { mContentBottom = top; } + if (mVoiceContentBottom > top) { + mVoiceContentBottom = top; + } top = win.getVisibleFrameLw().top; top += win.getGivenVisibleInsetsLw().top; if (mCurBottom > top) { @@ -3446,6 +3613,40 @@ public class PhoneWindowManager implements WindowManagerPolicy { + mContentBottom + " mCurBottom=" + mCurBottom); } + private void offsetVoiceInputWindowLw(WindowState win) { + final int gravity = win.getAttrs().gravity; + switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER) + << Gravity.AXIS_X_SHIFT)) { + case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_X_SHIFT: { + int right = win.getContentFrameLw().right - win.getGivenContentInsetsLw().right; + if (mVoiceContentLeft < right) { + mVoiceContentLeft = right; + } + } break; + case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_X_SHIFT: { + int left = win.getContentFrameLw().left - win.getGivenContentInsetsLw().left; + if (mVoiceContentRight < left) { + mVoiceContentRight = left; + } + } break; + } + switch (gravity&((Gravity.AXIS_PULL_BEFORE|Gravity.AXIS_PULL_AFTER) + << Gravity.AXIS_Y_SHIFT)) { + case Gravity.AXIS_PULL_BEFORE<<Gravity.AXIS_Y_SHIFT: { + int bottom = win.getContentFrameLw().bottom - win.getGivenContentInsetsLw().bottom; + if (mVoiceContentTop < bottom) { + mVoiceContentTop = bottom; + } + } break; + case Gravity.AXIS_PULL_AFTER<<Gravity.AXIS_Y_SHIFT: { + int top = win.getContentFrameLw().top - win.getGivenContentInsetsLw().top; + if (mVoiceContentBottom < top) { + mVoiceContentBottom = top; + } + } break; + } + } + /** {@inheritDoc} */ @Override public void finishLayoutLw() { @@ -3461,35 +3662,39 @@ public class PhoneWindowManager implements WindowManagerPolicy { mForceStatusBarFromKeyguard = false; mForcingShowNavBar = false; mForcingShowNavBarLayer = -1; - + mHideLockScreen = false; mAllowLockscreenWhenOn = false; mDismissKeyguard = DISMISS_KEYGUARD_NONE; mShowingLockscreen = false; mShowingDream = false; + mWinShowWhenLocked = null; } /** {@inheritDoc} */ @Override - public void applyPostLayoutPolicyLw(WindowState win, - WindowManager.LayoutParams attrs) { + public void applyPostLayoutPolicyLw(WindowState win, 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 @@ -3504,11 +3709,19 @@ 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; + final boolean secureKeyguard = isKeyguardSecure(); if (appWindow) { - if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) { + if (showWhenLocked || (dismissKeyguard && !secureKeyguard)) { + // Remove any previous windows with the same appToken. mAppsToBeHidden.remove(win.getAppToken()); + if (mAppsToBeHidden.isEmpty() && showWhenLocked && + isKeyguardSecureIncludingHidden()) { + mWinShowWhenLocked = win; + mHideLockScreen = true; + mForceStatusBarFromKeyguard = false; + } } else { mAppsToBeHidden.add(win.getAppToken()); } @@ -3525,17 +3738,23 @@ 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(); + mForceStatusBarFromKeyguard = mShowingLockscreen && secureKeyguard; } } - if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { + if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { mAllowLockscreenWhenOn = true; } } + + if (mWinShowWhenLocked != null && + mWinShowWhenLocked.getAppToken() != win.getAppToken()) { + win.hideLw(false); + } } } } @@ -3543,6 +3762,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public int finishPostLayoutPolicyLw() { + if (mWinShowWhenLocked != null && + mWinShowWhenLocked != mTopFullscreenOpaqueWindowState) { + // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the + // fullscreen window. + // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not. + mWinShowWhenLocked.getAttrs().flags |= FLAG_SHOW_WALLPAPER; + mTopFullscreenOpaqueWindowState.hideLw(false); + mTopFullscreenOpaqueWindowState = mWinShowWhenLocked; + } + int changes = 0; boolean topIsFullscreen = false; @@ -3575,13 +3804,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 @@ -3617,11 +3847,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; @@ -3635,24 +3866,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() { @@ -3662,12 +3891,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); } } @@ -3682,15 +3911,47 @@ 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; + } + + @Override 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; } return true; } + @Override public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { mFocusedWindow = newFocus; if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) { @@ -3702,6 +3963,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { // lid changed state final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED; @@ -3765,57 +4027,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { setHdmiPlugged(!mHdmiPlugged); } - /** - * @return Whether music is being played right now "locally" (e.g. on the device's speakers - * or wired headphones) or "remotely" (e.g. on a device using the Cast protocol and - * controlled by this device, or through remote submix). - */ - boolean isMusicActive() { - final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); - if (am == null) { - Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); - return false; - } - return am.isLocalOrRemoteMusicActive(); - } - - /** - * Tell the audio service to adjust the volume appropriate to the event. - * @param keycode - */ - void handleVolumeKey(int stream, int keycode) { - IAudioService audioService = getAudioService(); - if (audioService == null) { - return; - } - try { - // when audio is playing locally, we shouldn't have to hold a wake lock - // during the call, but we do it as a precaution for the rare possibility - // that the music stops right before we call this. - // Otherwise we might also be in a remote playback case. - // TODO: Actually handle MUTE. - mBroadcastWakeLock.acquire(); - if (stream == AudioSystem.STREAM_MUSIC) { - audioService.adjustLocalOrRemoteStreamVolume(stream, - keycode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - mContext.getOpPackageName()); - } else { - audioService.adjustStreamVolume(stream, - keycode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0, - mContext.getOpPackageName()); - } - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.adjust*StreamVolume() threw RemoteException " + e); - } finally { - mBroadcastWakeLock.release(); - } - } - final Object mScreenshotLock = new Object(); ServiceConnection mScreenshotConnection = null; @@ -3906,15 +4117,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 @@ -3923,11 +4128,12 @@ 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; + isWakeKey = false; } else { // When the screen is off and the key is not injected, determine whether // to wake the device but don't pass the key to the application. @@ -3940,6 +4146,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the key would be handled globally, just return the result, don't worry about special // key processing. if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { + if (isWakeKey) { + mPowerManager.wakeUp(event.getEventTime()); + } return result; } @@ -3980,44 +4189,44 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } if (down) { - ITelephony telephonyService = getTelephonyService(); - if (telephonyService != null) { - try { - if (telephonyService.isRinging()) { - // If an incoming call is ringing, either VOLUME key means - // "silence ringer". We handle these keys here, rather than - // in the InCallScreen, to make sure we'll respond to them - // even if the InCallScreen hasn't come to the foreground yet. - // Look for the DOWN event here, to agree with the "fallback" - // behavior in the InCallScreen. - Log.i(TAG, "interceptKeyBeforeQueueing:" - + " VOLUME key-down while ringing: Silence ringer!"); - - // Silence the ringer. (It's safe to call this - // even if the ringer has already been silenced.) - telephonyService.silenceRinger(); - - // And *don't* pass this key thru to the current activity - // (which is probably the InCallScreen.) - result &= ~ACTION_PASS_TO_USER; - break; - } - if (telephonyService.isOffhook() - && (result & ACTION_PASS_TO_USER) == 0) { - // If we are in call but we decided not to pass the key to - // the application, handle the volume change here. - handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode); - break; - } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); + TelecommManager telecommManager = getTelecommService(); + if (telecommManager != null) { + if (telecommManager.isRinging()) { + // If an incoming call is ringing, either VOLUME key means + // "silence ringer". We handle these keys here, rather than + // in the InCallScreen, to make sure we'll respond to them + // even if the InCallScreen hasn't come to the foreground yet. + // Look for the DOWN event here, to agree with the "fallback" + // behavior in the InCallScreen. + Log.i(TAG, "interceptKeyBeforeQueueing:" + + " VOLUME key-down while ringing: Silence ringer!"); + + // Silence the ringer. (It's safe to call this + // even if the ringer has already been silenced.) + telecommManager.silenceRinger(); + + // And *don't* pass this key thru to the current activity + // (which is probably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; + break; + } + if (telecommManager.isInAPhoneCall() + && (result & ACTION_PASS_TO_USER) == 0) { + // If we are in call but we decided not to pass the key to + // the application, just pass it to the session service. + + MediaSessionLegacyHelper.getHelper(mContext) + .sendVolumeKeyEvent(event, false); + break; } } - if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) { - // If music is playing but we decided not to pass the key to the - // application, handle the volume change here. - handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode); + if ((result & ACTION_PASS_TO_USER) == 0) { + // If we aren't passing to the user and no one else + // handled it send it to the session manager to figure + // out. + MediaSessionLegacyHelper.getHelper(mContext) + .sendVolumeKeyEvent(event, true); break; } } @@ -4027,14 +4236,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_ENDCALL: { result &= ~ACTION_PASS_TO_USER; if (down) { - ITelephony telephonyService = getTelephonyService(); + TelecommManager telecommManager = getTelecommService(); boolean hungUp = false; - if (telephonyService != null) { - try { - hungUp = telephonyService.endCall(); - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); - } + if (telecommManager != null) { + hungUp = telecommManager.endCall(); } interceptPowerKeyDown(!interactive || hungUp); } else { @@ -4058,8 +4263,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; @@ -4067,23 +4275,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { interceptScreenshotChord(); } - ITelephony telephonyService = getTelephonyService(); + TelecommManager telecommManager = getTelecommService(); boolean hungUp = false; - if (telephonyService != null) { - try { - if (telephonyService.isRinging()) { - // Pressing Power while there's a ringing incoming - // call should silence the ringer. - telephonyService.silenceRinger(); - } else if ((mIncallPowerBehavior - & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 - && telephonyService.isOffhook() && interactive) { - // Otherwise, if "Power button ends call" is enabled, - // the Power button will hang up any current active call. - hungUp = telephonyService.endCall(); - } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); + if (telecommManager != null) { + if (telecommManager.isRinging()) { + // Pressing Power while there's a ringing incoming + // call should silence the ringer. + telecommManager.silenceRinger(); + } else if ((mIncallPowerBehavior + & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 + && telecommManager.isInAPhoneCall() && interactive) { + // Otherwise, if "Power button ends call" is enabled, + // the Power button will hang up any current active call. + hungUp = telecommManager.endCall(); } } interceptPowerKeyDown(!interactive || hungUp @@ -4112,6 +4316,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_WAKEUP: { result &= ~ACTION_PASS_TO_USER; + isWakeKey = true; break; } @@ -4119,16 +4324,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_MEDIA_PAUSE: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (down) { - ITelephony telephonyService = getTelephonyService(); - if (telephonyService != null) { - try { - if (!telephonyService.isIdle()) { - // Suppress PLAY/PAUSE toggle when phone is ringing or in-call - // to avoid music playback. - break; - } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); + TelecommManager telecommManager = getTelecommService(); + if (telecommManager != null) { + if (telecommManager.isInAPhoneCall()) { + // Suppress PLAY/PAUSE toggle when phone is ringing or in-call + // to avoid music playback. + break; } } } @@ -4158,20 +4359,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_CALL: { if (down) { - ITelephony telephonyService = getTelephonyService(); - if (telephonyService != null) { - try { - if (telephonyService.isRinging()) { - Log.i(TAG, "interceptKeyBeforeQueueing:" - + " CALL key-down while ringing: Answer the call!"); - telephonyService.answerRingingCall(); - - // And *don't* pass this key thru to the current activity - // (which is presumably the InCallScreen.) - result &= ~ACTION_PASS_TO_USER; - } - } catch (RemoteException ex) { - Log.w(TAG, "ITelephony threw RemoteException", ex); + TelecommManager telecommManager = getTelecommService(); + if (telecommManager != null) { + if (telecommManager.isRinging()) { + Log.i(TAG, "interceptKeyBeforeQueueing:" + + " CALL key-down while ringing: Answer the call!"); + telecommManager.acceptRingingCall(); + + // And *don't* pass this key thru to the current activity + // (which is presumably the InCallScreen.) + result &= ~ACTION_PASS_TO_USER; } } } @@ -4279,14 +4476,7 @@ 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); - } - } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true); } } @@ -4347,8 +4537,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) { @@ -4376,6 +4577,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mKeyguardDelegate.onScreenTurnedOff(why); } synchronized (mLock) { + updateWakeGestureListenerLp(); updateOrientationListenerLp(); updateLockScreenTimeout(); } @@ -4392,11 +4594,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Called on the mHandler thread. private void handleWakingUp(final ScreenOnListener screenOnListener) { if (screenOnListener != null) { - mScreenOnListeners.add(screenOnListener); + mScreenOnListener = screenOnListener; } synchronized (mLock) { mScreenOnEarly = true; + updateWakeGestureListenerLp(); updateOrientationListenerLp(); updateLockScreenTimeout(); } @@ -4423,8 +4626,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return; } + ScreenOnListener screenOnListener; synchronized (mLock) { mScreenOnFully = true; + screenOnListener = mScreenOnListener; + mScreenOnListener = null; } try { @@ -4432,9 +4638,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } catch (RemoteException unhandled) { } - for (int i = mScreenOnListeners.size() - 1; i >=0; --i) { - mScreenOnListeners.remove(i).onScreenOn(); + if (screenOnListener != null) { + screenOnListener.onScreenOn(); } + + setKeyguardDrawn(); } @Override @@ -4448,6 +4656,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void enableKeyguard(boolean enabled) { if (mKeyguardDelegate != null) { mKeyguardDelegate.setKeyguardEnabled(enabled); @@ -4455,6 +4664,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void exitKeyguardSecurely(OnKeyguardExitResult callback) { if (mKeyguardDelegate != null) { mKeyguardDelegate.verifyUnlock(callback); @@ -4463,30 +4673,40 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean keyguardIsShowingTq() { if (mKeyguardDelegate == null) return false; - return mKeyguardDelegate.isShowingAndNotHidden(); + return mKeyguardDelegate.isShowingAndNotOccluded(); } /** {@inheritDoc} */ + @Override public boolean isKeyguardLocked() { return keyguardOn(); } /** {@inheritDoc} */ + @Override public boolean isKeyguardSecure() { if (mKeyguardDelegate == null) return false; return mKeyguardDelegate.isSecure(); } + // Returns true if keyguard is currently locked whether or not it is currently hidden. + private boolean isKeyguardSecureIncludingHidden() { + return mKeyguardDelegate.isSecure() && mKeyguardDelegate.isShowing(); + } + /** {@inheritDoc} */ + @Override public boolean inKeyguardRestrictedKeyInputMode() { if (mKeyguardDelegate == null) return false; return mKeyguardDelegate.isInputRestricted(); } + @Override public void dismissKeyguardLw() { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { + if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { mHandler.post(new Runnable() { + @Override public void run() { if (mKeyguardDelegate.isDismissable()) { // Can we just finish the keyguard straight away? @@ -4500,6 +4720,30 @@ 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; + } + } + + @Override + public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + if (mKeyguardDelegate != null) { + mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration); + } + } + void sendCloseSystemWindows() { sendCloseSystemWindows(mContext, null); } @@ -4709,6 +4953,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { return rotation == mPortraitRotation || rotation == mUpsideDownRotation; } + @Override public int getUserRotationMode() { return Settings.System.getIntForUser(mContext.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 ? @@ -4717,6 +4962,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // User rotation: to be used when all else fails in assigning an orientation to the device + @Override public void setUserRotationMode(int mode, int rot) { ContentResolver res = mContext.getContentResolver(); @@ -4738,6 +4984,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + @Override public void setSafeMode(boolean safeMode) { mSafeMode = safeMode; performHapticFeedbackLw(null, safeMode @@ -4777,6 +5024,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void systemBooted() { if (mKeyguardDelegate != null) { mKeyguardDelegate.onBootCompleted(); @@ -4784,18 +5032,27 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { mSystemBooted = true; } + wakingUp(null); } ProgressDialog mBootMsgDialog = null; /** {@inheritDoc} */ + @Override public void showBootMessage(final CharSequence msg, final boolean always) { 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 @@ -4841,6 +5098,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void hideBootMessages() { mHandler.post(new Runnable() { @Override public void run() { @@ -4853,6 +5111,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } /** {@inheritDoc} */ + @Override public void userActivity() { // *************************************** // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE @@ -4896,6 +5155,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { ScreenLockTimeout mScreenLockTimeout = new ScreenLockTimeout(); + @Override public void lockNow(Bundle options) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); mHandler.removeCallbacks(mScreenLockTimeout); @@ -4938,6 +5198,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.GO_TO_SLEEP_REASON_USER, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); } + + synchronized (mLock) { + updateWakeGestureListenerLp(); + } } void updateUiMode() { @@ -5131,7 +5395,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; @@ -5145,6 +5409,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.KEYBOARD_TAP: pattern = mKeyboardTapVibePattern; break; + case HapticFeedbackConstants.CLOCK_TICK: + pattern = mClockTickVibePattern; + break; + case HapticFeedbackConstants.CALENDAR_DATE: + pattern = mCalendarDateVibePattern; + break; case HapticFeedbackConstants.SAFE_MODE_DISABLED: pattern = mSafeModeDisabledVibePattern; break; @@ -5165,10 +5435,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; } @@ -5179,8 +5449,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); } } @@ -5192,7 +5461,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 @@ -5202,11 +5471,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; @@ -5238,26 +5507,28 @@ 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); // prevent status bar interaction from clearing certain flags boolean statusBarHasFocus = win.getAttrs().type == TYPE_STATUS_BAR; - if (statusBarHasFocus) { + if (statusBarHasFocus && !isStatusBarKeyguard()) { 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 (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 @@ -5265,7 +5536,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; @@ -5298,7 +5569,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); @@ -5329,7 +5601,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 @@ -5346,6 +5619,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + public int getInputMethodWindowVisibleHeightLw() { + return mDockBottom - mCurBottom; + } + + @Override public void setCurrentUserLw(int newUserId) { mCurrentUserId = newUserId; if (mKeyguardDelegate != null) { @@ -5375,11 +5653,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) { @@ -5409,6 +5682,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); } + pw.print(prefix); pw.print("mWakeGestureEnabledSetting="); + pw.println(mWakeGestureEnabledSetting); + pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation); pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); pw.print(" mDockMode="); pw.print(mDockMode); @@ -5477,6 +5753,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(","); pw.print(mContentTop); pw.print(")-("); pw.print(mContentRight); pw.print(","); pw.print(mContentBottom); pw.println(")"); + pw.print(prefix); pw.print("mVoiceContent=("); pw.print(mVoiceContentLeft); + pw.print(","); pw.print(mVoiceContentTop); + pw.print(")-("); pw.print(mVoiceContentRight); + pw.print(","); pw.print(mVoiceContentBottom); pw.println(")"); pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft); pw.print(","); pw.print(mDockTop); pw.print(")-("); pw.print(mDockRight); @@ -5497,15 +5777,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); @@ -5548,7 +5826,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation); pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock); pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation); + + mGlobalKeyManager.dump(prefix, pw); mStatusBarController.dump(pw, prefix); mNavigationBarController.dump(pw, prefix); + PolicyControl.dump(prefix, pw); + + if (mWakeGestureListener != null) { + mWakeGestureListener.dump(pw, prefix); + } + if (mOrientationListener != null) { + mOrientationListener.dump(pw, prefix); + } } } 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/WakeGestureListener.java b/policy/src/com/android/internal/policy/impl/WakeGestureListener.java new file mode 100644 index 0000000..9396c2c --- /dev/null +++ b/policy/src/com/android/internal/policy/impl/WakeGestureListener.java @@ -0,0 +1,100 @@ +/* + * 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.os.Handler; +import android.content.Context; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.hardware.TriggerEvent; +import android.hardware.TriggerEventListener; + +import java.io.PrintWriter; + +/** + * Watches for wake gesture sensor events then invokes the listener. + */ +public abstract class WakeGestureListener { + private static final String TAG = "WakeGestureListener"; + + private final SensorManager mSensorManager; + private final Handler mHandler; + + private final Object mLock = new Object(); + + private boolean mTriggerRequested; + private Sensor mSensor; + + public WakeGestureListener(Context context, Handler handler) { + mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE); + mHandler = handler; + + mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_WAKE_GESTURE); + } + + public abstract void onWakeUp(); + + public boolean isSupported() { + synchronized (mLock) { + return mSensor != null; + } + } + + public void requestWakeUpTrigger() { + synchronized (mLock) { + if (mSensor != null && !mTriggerRequested) { + mTriggerRequested = true; + mSensorManager.requestTriggerSensor(mListener, mSensor); + } + } + } + + public void cancelWakeUpTrigger() { + synchronized (mLock) { + if (mSensor != null && mTriggerRequested) { + mTriggerRequested = false; + mSensorManager.cancelTriggerSensor(mListener, mSensor); + } + } + } + + public void dump(PrintWriter pw, String prefix) { + synchronized (mLock) { + pw.println(prefix + TAG); + prefix += " "; + pw.println(prefix + "mTriggerRequested=" + mTriggerRequested); + pw.println(prefix + "mSensor=" + mSensor); + } + } + + private final TriggerEventListener mListener = new TriggerEventListener() { + @Override + public void onTrigger(TriggerEvent event) { + synchronized (mLock) { + mTriggerRequested = false; + mHandler.post(mWakeUpRunnable); + } + } + }; + + private final Runnable mWakeUpRunnable = new Runnable() { + @Override + public void run() { + onWakeUp(); + } + }; +} diff --git a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java index 0c77556..704da33 100644 --- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java +++ b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java @@ -26,6 +26,9 @@ import android.os.SystemProperties; import android.util.FloatMath; import android.util.Log; import android.util.Slog; +import android.util.TimeUtils; + +import java.io.PrintWriter; /** * A special helper class used by the WindowManager @@ -181,6 +184,21 @@ public abstract class WindowOrientationListener { */ public abstract void onProposedRotationChanged(int rotation); + public void dump(PrintWriter pw, String prefix) { + synchronized (mLock) { + pw.println(prefix + TAG); + prefix += " "; + pw.println(prefix + "mEnabled=" + mEnabled); + pw.println(prefix + "mCurrentRotation=" + mCurrentRotation); + pw.println(prefix + "mSensor=" + mSensor); + pw.println(prefix + "mRate=" + mRate); + + if (mSensorEventListener != null) { + mSensorEventListener.dumpLocked(pw, prefix); + } + } + } + /** * This class filters the raw accelerometer data and tries to detect actual changes in * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters, @@ -342,6 +360,14 @@ public abstract class WindowOrientationListener { /* ROTATION_270 */ { -25, 65 } }; + // The tilt angle below which we conclude that the user is holding the device + // overhead reading in bed and lock into that state. + private final int TILT_OVERHEAD_ENTER = -40; + + // The tilt angle above which we conclude that the user would like a rotation + // change to occur and unlock from the overhead state. + private final int TILT_OVERHEAD_EXIT = -15; + // The gap angle in degrees between adjacent orientation angles for hysteresis. // This creates a "dead zone" between the current orientation and a proposed // adjacent orientation. No orientation proposal is made when the orientation @@ -364,12 +390,18 @@ public abstract class WindowOrientationListener { // Timestamp when the device last appeared to be flat for sure (the flat delay elapsed). private long mFlatTimestampNanos; + private boolean mFlat; // Timestamp when the device last appeared to be swinging. private long mSwingTimestampNanos; + private boolean mSwinging; // Timestamp when the device last appeared to be undergoing external acceleration. private long mAccelerationTimestampNanos; + private boolean mAccelerating; + + // Whether we are locked into an overhead usage mode. + private boolean mOverhead; // History of observed tilt angles. private static final int TILT_HISTORY_SIZE = 40; @@ -381,6 +413,19 @@ public abstract class WindowOrientationListener { return mProposedRotation; } + public void dumpLocked(PrintWriter pw, String prefix) { + pw.println(prefix + "mProposedRotation=" + mProposedRotation); + pw.println(prefix + "mPredictedRotation=" + mPredictedRotation); + pw.println(prefix + "mLastFilteredX=" + mLastFilteredX); + pw.println(prefix + "mLastFilteredY=" + mLastFilteredY); + pw.println(prefix + "mLastFilteredZ=" + mLastFilteredZ); + pw.println(prefix + "mTiltHistory={last: " + getLastTiltLocked() + "}"); + pw.println(prefix + "mFlat=" + mFlat); + pw.println(prefix + "mSwinging=" + mSwinging); + pw.println(prefix + "mAccelerating=" + mAccelerating); + pw.println(prefix + "mOverhead=" + mOverhead); + } + @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @@ -478,7 +523,18 @@ public abstract class WindowOrientationListener { // If the tilt angle is too close to horizontal then we cannot determine // the orientation angle of the screen. - if (Math.abs(tiltAngle) > MAX_TILT) { + if (tiltAngle <= TILT_OVERHEAD_ENTER) { + mOverhead = true; + } else if (tiltAngle >= TILT_OVERHEAD_EXIT) { + mOverhead = false; + } + if (mOverhead) { + if (LOG) { + Slog.v(TAG, "Ignoring sensor data, device is overhead: " + + "tiltAngle=" + tiltAngle); + } + clearPredictedRotationLocked(); + } else if (Math.abs(tiltAngle) > MAX_TILT) { if (LOG) { Slog.v(TAG, "Ignoring sensor data, tilt angle too high: " + "tiltAngle=" + tiltAngle); @@ -526,6 +582,9 @@ public abstract class WindowOrientationListener { } } } + mFlat = isFlat; + mSwinging = isSwinging; + mAccelerating = isAccelerating; // Determine new proposed rotation. oldProposedRotation = mProposedRotation; @@ -543,6 +602,7 @@ public abstract class WindowOrientationListener { + ", isAccelerating=" + isAccelerating + ", isFlat=" + isFlat + ", isSwinging=" + isSwinging + + ", isOverhead=" + mOverhead + ", timeUntilSettledMS=" + remainingMS(now, mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) + ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now, @@ -660,8 +720,12 @@ public abstract class WindowOrientationListener { mLastFilteredTimestampNanos = Long.MIN_VALUE; mProposedRotation = -1; mFlatTimestampNanos = Long.MIN_VALUE; + mFlat = false; mSwingTimestampNanos = Long.MIN_VALUE; + mSwinging = false; mAccelerationTimestampNanos = Long.MIN_VALUE; + mAccelerating = false; + mOverhead = false; clearPredictedRotationLocked(); clearTiltHistoryLocked(); } @@ -726,6 +790,11 @@ public abstract class WindowOrientationListener { return mTiltHistoryTimestampNanos[index] != Long.MIN_VALUE ? index : -1; } + private float getLastTiltLocked() { + int index = nextTiltHistoryIndexLocked(mTiltHistoryIndex); + return index >= 0 ? mTiltHistory[index] : Float.NaN; + } + private float remainingMS(long now, long until) { return now >= until ? 0 : (until - now) * 0.000001f; } 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..63a5850 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() { @@ -273,6 +274,12 @@ public class KeyguardServiceDelegate { mKeyguardState.currentUser = newUserId; } + public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + if (mKeyguardService != null) { + mKeyguardService.startKeyguardExitAnimation(startTime, fadeoutDuration); + } + } + private static final View createScrim(Context context) { View view = new View(context); 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..5096bd3 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; } } @@ -188,6 +190,14 @@ public class KeyguardServiceWrapper implements IKeyguardService { } } + public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) { + try { + mService.startKeyguardExitAnimation(startTime, fadeoutDuration); + } catch (RemoteException e) { + Slog.w(TAG , "Remote Exception", e); + } + } + public void showAssistant() { // Not used by PhoneWindowManager } |