summaryrefslogtreecommitdiffstats
path: root/policy
diff options
context:
space:
mode:
Diffstat (limited to 'policy')
-rw-r--r--policy/src/com/android/internal/policy/impl/BarController.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java6
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java418
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalKeyManager.java18
-rw-r--r--policy/src/com/android/internal/policy/impl/IconUtilities.java9
-rw-r--r--policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java127
-rw-r--r--policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java42
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java33
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java5
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java1429
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindowManager.java1831
-rw-r--r--policy/src/com/android/internal/policy/impl/PolicyControl.java258
-rw-r--r--policy/src/com/android/internal/policy/impl/RecentApplicationsBackground.java1
-rw-r--r--policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/ShortcutManager.java1
-rw-r--r--policy/src/com/android/internal/policy/impl/WakeGestureListener.java100
-rw-r--r--policy/src/com/android/internal/policy/impl/WindowOrientationListener.java71
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java46
-rw-r--r--policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceWrapper.java26
19 files changed, 3238 insertions, 1197 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/EnableAccessibilityController.java b/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
index 71b0d53..6f79f58 100644
--- a/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
+++ b/policy/src/com/android/internal/policy/impl/EnableAccessibilityController.java
@@ -83,6 +83,7 @@ public class EnableAccessibilityController {
private final Context mContext;
+ private final Runnable mOnAccessibilityEnabledCallback;
private final UserManager mUserManager;
private final TextToSpeech mTts;
private final Ringtone mTone;
@@ -97,8 +98,9 @@ public class EnableAccessibilityController {
private float mSecondPointerDownX;
private float mSecondPointerDownY;
- public EnableAccessibilityController(Context context) {
+ public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
mContext = context;
+ mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
@Override
@@ -275,5 +277,7 @@ public class EnableAccessibilityController {
/* ignore */
}
}
+
+ mOnAccessibilityEnabledCallback.run();
}
}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 4db7d4d..dfcdaa0 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,8 @@ 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;
import android.view.InputDevice;
@@ -61,7 +65,10 @@ 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.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
@@ -83,6 +90,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private static final boolean SHOW_SILENT_TOGGLE = true;
+ /* Valid settings for global actions keys.
+ * see config.xml config_globalActionList */
+ private static final String GLOBAL_ACTION_KEY_POWER = "power";
+ private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+ private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+ 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;
private final AudioManager mAudioManager;
@@ -173,11 +190,18 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mDialog = createDialog();
prepareDialog();
- WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
- attrs.setTitle("GlobalActions");
- mDialog.getWindow().setAttributes(attrs);
- mDialog.show();
- mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ // 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 LongPressAction)) {
+ ((SinglePressAction) mAdapter.getItem(0)).onPress();
+ } else {
+ WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+ attrs.setTitle("GlobalActions");
+ mDialog.getWindow().setAttributes(attrs);
+ mDialog.show();
+ mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+ }
}
/**
@@ -235,92 +259,42 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
onAirplaneModeChanged();
mItems = new ArrayList<Action>();
-
- // first: power off
- mItems.add(
- new SinglePressAction(
- com.android.internal.R.drawable.ic_lock_power_off,
- R.string.global_action_power_off) {
-
- public void onPress() {
- // shutdown by making sure radio and power are handled accordingly.
- mWindowManagerFuncs.shutdown(true);
+ String[] defaultActions = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_globalActionsList);
+
+ ArraySet<String> addedKeys = new ArraySet<String>();
+ for (int i = 0; i < defaultActions.length; i++) {
+ String actionKey = defaultActions[i];
+ if (addedKeys.contains(actionKey)) {
+ // If we already have added this, don't add it again.
+ continue;
+ }
+ if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+ mItems.add(new PowerAction());
+ } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+ mItems.add(mAirplaneModeOn);
+ } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
+ if (Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
+ mItems.add(getBugReportAction());
}
-
- public boolean onLongPress() {
- mWindowManagerFuncs.rebootSafeMode(true);
- return true;
+ } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
+ if (mShowSilentToggle) {
+ mItems.add(mSilentModeAction);
}
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return true;
+ } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
+ if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+ addUsersToMenu(mItems);
}
- });
-
- // next: airplane mode
- mItems.add(mAirplaneModeOn);
-
- // next: bug report, if enabled
- if (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
- mItems.add(
- new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
- R.string.global_action_bug_report) {
-
- public void onPress() {
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(com.android.internal.R.string.bugreport_title);
- builder.setMessage(com.android.internal.R.string.bugreport_message);
- builder.setNegativeButton(com.android.internal.R.string.cancel, null);
- builder.setPositiveButton(com.android.internal.R.string.report,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // Add a little delay before executing, to give the
- // dialog a chance to go away before it takes a
- // screenshot.
- mHandler.postDelayed(new Runnable() {
- @Override public void run() {
- try {
- ActivityManagerNative.getDefault()
- .requestBugReport();
- } catch (RemoteException e) {
- }
- }
- }, 500);
- }
- });
- AlertDialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.show();
- }
-
- public boolean onLongPress() {
- return false;
- }
-
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
- return false;
- }
- });
- }
-
- // last: silent mode
- if (mShowSilentToggle) {
- mItems.add(mSilentModeAction);
- }
-
- // one more thing: optionally add a list of users to switch to
- if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
- addUsersToMenu(mItems);
+ } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+ mItems.add(getSettingsAction());
+ } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
+ mItems.add(getLockdownAction());
+ } else {
+ Log.e(TAG, "Invalid global action key " + actionKey);
+ }
+ // Add here so we don't add more than one.
+ addedKeys.add(actionKey);
}
mAdapter = new MyAdapter();
@@ -340,7 +314,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);
@@ -350,6 +328,134 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
return dialog;
}
+ 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);
+ }
+
+ @Override
+ public boolean onLongPress() {
+ mWindowManagerFuncs.rebootSafeMode(true);
+ return true;
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ 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.ic_lock_bugreport,
+ R.string.bugreport_title) {
+
+ public void onPress() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(com.android.internal.R.string.bugreport_title);
+ builder.setMessage(com.android.internal.R.string.bugreport_message);
+ builder.setNegativeButton(com.android.internal.R.string.cancel, null);
+ builder.setPositiveButton(com.android.internal.R.string.report,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Add a little delay before executing, to give the
+ // dialog a chance to go away before it takes a
+ // screenshot.
+ mHandler.postDelayed(new Runnable() {
+ @Override public void run() {
+ try {
+ ActivityManagerNative.getDefault()
+ .requestBugReport();
+ } catch (RemoteException e) {
+ }
+ }
+ }, 500);
+ }
+ });
+ AlertDialog dialog = builder.create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ dialog.show();
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+
+ @Override
+ public String getStatus() {
+ return mContext.getString(
+ com.android.internal.R.string.bugreport_status,
+ Build.VERSION.RELEASE,
+ Build.ID);
+ }
+ };
+ }
+
+ private Action getSettingsAction() {
+ return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+ R.string.global_action_settings) {
+
+ @Override
+ public void onPress() {
+ Intent intent = new Intent(Settings.ACTION_SETTINGS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivity(intent);
+ }
+
+ @Override
+ 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
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+ };
+ }
+
private UserInfo getCurrentUser() {
try {
return ActivityManagerNative.getDefault().getCurrentUser();
@@ -364,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);
+ }
}
}
}
@@ -518,12 +626,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
* What each item in the global actions dialog must be able to support.
*/
private interface Action {
+ /**
+ * @return Text that will be announced when dialog is created. null
+ * for none.
+ */
+ CharSequence getLabelForAccessibility(Context context);
+
View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
void onPress();
- public boolean onLongPress();
-
/**
* @return whether this action should appear in the dialog when the keygaurd
* is showing.
@@ -540,6 +652,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.
*/
@@ -574,10 +693,18 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
return true;
}
+ public String getStatus() {
+ return null;
+ }
+
abstract public void onPress();
- public boolean onLongPress() {
- return false;
+ public CharSequence getLabelForAccessibility(Context context) {
+ if (mMessage != null) {
+ return mMessage;
+ } else {
+ return context.getString(mMessageResId);
+ }
}
public View create(
@@ -587,12 +714,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);
@@ -663,6 +796,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
+ @Override
+ public CharSequence getLabelForAccessibility(Context context) {
+ return context.getString(mMessageResId);
+ }
+
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
willCreate();
@@ -682,7 +820,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);
}
@@ -708,10 +846,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
changeStateFromPress(nowOn);
}
- public boolean onLongPress() {
- return false;
- }
-
public boolean isEnabled() {
return !mState.inTransition();
}
@@ -783,6 +917,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
return index;
}
+ @Override
+ public CharSequence getLabelForAccessibility(Context context) {
+ return null;
+ }
+
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
@@ -801,10 +940,6 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public void onPress() {
}
- public boolean onLongPress() {
- return false;
- }
-
public boolean showDuringKeyguard() {
return true;
}
@@ -935,6 +1070,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private final Context mContext;
private final int mWindowTouchSlop;
private final AlertController mAlert;
+ private final MyAdapter mAdapter;
private EnableAccessibilityController mEnableAccessibilityController;
@@ -945,6 +1081,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
super(context, getDialogTheme(context));
mContext = context;
mAlert = new AlertController(mContext, this, getWindow());
+ mAdapter = (MyAdapter) params.mAdapter;
mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
params.apply(mAlert);
}
@@ -963,12 +1100,19 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
// is dismissed on the first down while the global gesture is a long press
// with two fingers anywhere on the screen.
if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
- mEnableAccessibilityController = new EnableAccessibilityController(mContext);
+ mEnableAccessibilityController = new EnableAccessibilityController(mContext,
+ new Runnable() {
+ @Override
+ public void run() {
+ dismiss();
+ }
+ });
super.setCanceledOnTouchOutside(false);
} else {
mEnableAccessibilityController = null;
super.setCanceledOnTouchOutside(true);
}
+
super.onStart();
}
@@ -1032,6 +1176,20 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
@Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+ for (int i = 0; i < mAdapter.getCount(); ++i) {
+ CharSequence label =
+ mAdapter.getItem(i).getLabelForAccessibility(getContext());
+ if (label != null) {
+ event.getText().add(label);
+ }
+ }
+ }
+ return super.dispatchPopulateAccessibilityEvent(event);
+ }
+
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (mAlert.onKeyDown(keyCode, event)) {
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..8fc4647 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;
}
@@ -292,16 +293,14 @@ public class ImmersiveModeConfirmation {
@Override
public boolean onTouchEvent(MotionEvent motion) {
- Slog.v(TAG, "ClingWindowView.onTouchEvent");
return true;
}
}
- 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 +312,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/LogDecelerateInterpolator.java b/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
new file mode 100644
index 0000000..1f3e1de
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/LogDecelerateInterpolator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.view.animation.Interpolator;
+
+public class LogDecelerateInterpolator implements Interpolator {
+
+ private int mBase;
+ private int mDrift;
+ private final float mLogScale;
+
+ public LogDecelerateInterpolator(int base, int drift) {
+ mBase = base;
+ mDrift = drift;
+
+ mLogScale = 1f / computeLog(1, mBase, mDrift);
+ }
+
+ private static float computeLog(float t, int base, int drift) {
+ return (float) -Math.pow(base, -t) + 1 + (drift * t);
+ }
+
+ @Override
+ public float getInterpolation(float t) {
+ return computeLog(t, mBase, mDrift) * mLogScale;
+ }
+}
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 6bf4beb..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;
@@ -26,7 +24,8 @@ import android.view.LayoutInflater;
public class PhoneLayoutInflater extends LayoutInflater {
private static final String[] sClassPrefixList = {
"android.widget.",
- "android.webkit."
+ "android.webkit.",
+ "android.app."
};
/**
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 44fc1f8..5f3b877 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,39 +32,47 @@ 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.BackgroundFallback;
+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.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.transition.TransitionSet;
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;
import android.view.ContextThemeWrapper;
+import android.view.Display;
import android.view.Gravity;
import android.view.IRotationWatcher;
import android.view.IWindowManager;
@@ -80,12 +86,14 @@ 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;
import android.view.ViewRootImpl;
import android.view.ViewStub;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -112,6 +120,16 @@ 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_ACTIVITY_TRANSITIONS) |
+ (1 << FEATURE_ACTION_MODE_OVERLAY);
+
+ private static final Transition USE_DEFAULT_TRANSITION = new TransitionSet();
+
/**
* Simple callback used by the context menu and its submenus. The options
* menu submenus do not use this (their behavior is more complex).
@@ -124,6 +142,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
TypedValue mFixedWidthMinor;
TypedValue mFixedHeightMajor;
TypedValue mFixedHeightMinor;
+ TypedValue mOutsetBottom;
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
@@ -132,20 +151,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// mDecor itself, or a child of mDecor where the contents go.
private ViewGroup mContentParent;
+ private ViewGroup mContentRoot;
+
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;
@@ -188,24 +212,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private ProgressBar mHorizontalProgressBar;
private int mBackgroundResource = 0;
+ private int mBackgroundFallbackResource = 0;
private Drawable mBackgroundDrawable;
+ private float mElevation;
+
+ /** Whether window content should be clipped to the background outline. */
+ private boolean mClipToOutline;
+
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;
@@ -226,6 +261,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
};
+ private Transition mEnterTransition = null;
+ private Transition mReturnTransition = USE_DEFAULT_TRANSITION;
+ private Transition mExitTransition = null;
+ private Transition mReenterTransition = USE_DEFAULT_TRANSITION;
+ private Transition mSharedElementEnterTransition = null;
+ private Transition mSharedElementReturnTransition = USE_DEFAULT_TRANSITION;
+ private Transition mSharedElementExitTransition = null;
+ private Transition mSharedElementReenterTransition = USE_DEFAULT_TRANSITION;
+ private Boolean mAllowReturnTransitionOverlap;
+ private Boolean mAllowEnterTransitionOverlap;
+ private long mBackgroundFadeDurationMillis = -1;
+ private Boolean mSharedElementsUseOverlay;
+
+ private Rect mTempRect;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -249,16 +299,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.
@@ -267,6 +314,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// Remove the action bar feature if we have no title. No title dominates.
removeFeature(FEATURE_ACTION_BAR);
}
+
+ if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
+ throw new AndroidRuntimeException(
+ "You cannot combine swipe dismissal and the action bar.");
+ }
+ if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
+ throw new AndroidRuntimeException(
+ "You cannot combine swipe dismissal and the action bar.");
+ }
+
+ if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
+ getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
+ }
return super.requestFeature(featureId);
}
@@ -281,13 +342,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();
@@ -301,12 +387,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();
@@ -318,6 +414,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()) {
@@ -325,6 +425,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;
@@ -334,11 +443,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;
@@ -359,13 +468,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);
@@ -391,7 +501,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);
@@ -406,10 +516,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) {
@@ -421,11 +531,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.
@@ -437,14 +547,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;
}
@@ -462,10 +572,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;
@@ -490,7 +600,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) {
@@ -536,18 +646,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);
}
@@ -624,7 +732,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();
@@ -676,10 +784,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 {
@@ -701,7 +809,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;
}
@@ -747,7 +855,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);
@@ -775,6 +883,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ void doPendingInvalidatePanelMenu() {
+ if (mInvalidatePanelMenuPosted) {
+ mDecor.removeCallbacks(mInvalidatePanelMenuRunnable);
+ mInvalidatePanelMenuRunnable.run();
+ }
+ }
+
void doInvalidatePanelMenu(int featureId) {
PanelFeatureState st = getPanelState(featureId, true);
Bundle savedActionViewStates = null;
@@ -790,10 +905,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;
@@ -801,7 +916,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}.
@@ -810,7 +925,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;
@@ -837,20 +952,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) {
@@ -963,7 +1076,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);
}
}
@@ -985,7 +1098,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);
}
@@ -1020,12 +1133,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) {
@@ -1040,11 +1153,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);
@@ -1079,22 +1192,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(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(
+ R.attr.actionBarWidgetTheme, outValue, true);
+ } else {
+ baseTheme.resolveAttribute(
+ R.attr.actionBarWidgetTheme, outValue, true);
+ }
+
+ if (outValue.resourceId != 0) {
+ if (widgetTheme == null) {
+ widgetTheme = context.getResources().newTheme();
+ widgetTheme.setTo(baseTheme);
+ }
+ widgetTheme.applyStyle(outValue.resourceId, true);
+ }
- if (targetThemeRes != 0 && context.getThemeResId() != targetThemeRes) {
- context = new ContextThemeWrapper(context, targetThemeRes);
+ if (widgetTheme != null) {
+ context = new ContextThemeWrapper(context, 0);
+ context.getTheme().setTo(widgetTheme);
}
}
final MenuBuilder menu = new MenuBuilder(context);
-
menu.setCallback(this);
st.setMenu(menu);
@@ -1112,6 +1243,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
st.decorView = new DecorView(getContext(), st.featureId);
st.gravity = Gravity.CENTER | Gravity.BOTTOM;
st.setStyle(getContext());
+ TypedArray a = getContext().obtainStyledAttributes(null,
+ R.styleable.Window, 0, st.listPresenterTheme);
+ final float elevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+ if (elevation != 0) {
+ st.decorView.setElevation(elevation);
+ }
+ a.recycle();
return true;
}
@@ -1199,6 +1337,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mDecor != null) {
mDecor.setWindowBackground(drawable);
}
+ if (mBackgroundFallbackResource != 0) {
+ mDecor.setBackgroundFallback(drawable != null ? 0 : mBackgroundFallbackResource);
+ }
}
}
@@ -1209,7 +1350,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 {
@@ -1321,7 +1462,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (featureId == FEATURE_PROGRESS || featureId == FEATURE_INDETERMINATE_PROGRESS) {
updateProgressBars(value);
} else if (featureId == FEATURE_CUSTOM_TITLE) {
- FrameLayout titleContainer = (FrameLayout) findViewById(com.android.internal.R.id.title_container);
+ FrameLayout titleContainer = (FrameLayout) findViewById(R.id.title_container);
if (titleContainer != null) {
mLayoutInflater.inflate(value, titleContainer);
}
@@ -1354,30 +1495,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);
@@ -1385,7 +1554,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);
}
@@ -1395,11 +1568,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);
}
@@ -1407,14 +1580,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void hideProgressBars(ProgressBar horizontalProgressBar, ProgressBar spinnyProgressBar) {
final int features = getLocalFeatures();
- Animation anim = AnimationUtils.loadAnimation(getContext(), com.android.internal.R.anim.fade_out);
+ Animation anim = AnimationUtils.loadAnimation(getContext(), 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);
@@ -1426,8 +1600,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);
}
}
@@ -1437,13 +1611,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;
}
}
@@ -1453,8 +1628,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);
}
}
@@ -1464,8 +1639,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);
}
}
@@ -1551,18 +1726,47 @@ 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 | 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
- // 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);
@@ -1613,10 +1817,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
@@ -1625,6 +1841,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,
@@ -1722,9 +1958,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);
}
@@ -1763,11 +1999,12 @@ 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);
+ doPendingInvalidatePanelMenu();
+ mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
} else {
Log.w(TAG, "Missing saved instance states for action bar views! " +
"State will not be restored.");
@@ -1927,11 +2164,31 @@ 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 final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
+
+ private int mLastTopInset = 0;
+ private int mLastBottomInset = 0;
+ private int mLastRightInset = 0;
+
+
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
}
+ public void setBackgroundFallback(int resId) {
+ mBackgroundFallback.setDrawable(resId != 0 ? getContext().getDrawable(resId) : null);
+ setWillNotDraw(getBackground() == null && !mBackgroundFallback.hasFallback());
+ }
+
+ @Override
+ public void onDraw(Canvas c) {
+ super.onDraw(c);
+ mBackgroundFallback.draw(mContentRoot, c, mContentParent);
+ }
+
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
@@ -2032,12 +2289,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.
@@ -2047,17 +2299,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) {
@@ -2077,6 +2321,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
+ public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+ if (mOutsetBottom != null) {
+ final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+ int bottom = (int) mOutsetBottom.getDimension(metrics);
+ WindowInsets newInsets = insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetRight(), bottom);
+ return super.dispatchApplyWindowInsets(newInsets);
+ } else {
+ return super.dispatchApplyWindowInsets(insets);
+ }
+ }
+
+
+ @Override
public boolean onTouchEvent(MotionEvent event) {
return onInterceptTouchEvent(event);
}
@@ -2168,7 +2427,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
@@ -2225,8 +2484,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mMenuBackground == null && mFeatureId < 0
&& getAttributes().height
== WindowManager.LayoutParams.MATCH_PARENT) {
- mMenuBackground = getContext().getResources().getDrawable(
- com.android.internal.R.drawable.menu_background);
+ mMenuBackground = getContext().getDrawable(
+ R.drawable.menu_background);
}
if (mMenuBackground != null) {
mMenuBackground.setBounds(drawingBounds.left,
@@ -2279,7 +2538,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
} else {
h = 0;
}
-
if (h > 0) {
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2288,6 +2546,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ if (mOutsetBottom != null) {
+ int mode = MeasureSpec.getMode(heightMeasureSpec);
+ if (mode != MeasureSpec.UNSPECIFIED) {
+ int outset = (int) mOutsetBottom.getDimension(metrics);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+ }
+ }
+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
@@ -2382,19 +2649,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
} else {
if (mActionModeView == null) {
if (isFloating()) {
- mActionModeView = new ActionBarContextView(mContext);
- mActionModePopup = new PopupWindow(mContext, null,
- com.android.internal.R.attr.actionModePopupWindowStyle);
+ // Use the action bar theme.
+ final TypedValue outValue = new TypedValue();
+ final Theme baseTheme = mContext.getTheme();
+ baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
+
+ final Context actionBarContext;
+ if (outValue.resourceId != 0) {
+ final Theme actionBarTheme = mContext.getResources().newTheme();
+ actionBarTheme.setTo(baseTheme);
+ actionBarTheme.applyStyle(outValue.resourceId, true);
+
+ actionBarContext = new ContextThemeWrapper(mContext, 0);
+ actionBarContext.getTheme().setTo(actionBarTheme);
+ } else {
+ actionBarContext = mContext;
+ }
+
+ mActionModeView = new ActionBarContextView(actionBarContext);
+ mActionModePopup = new PopupWindow(actionBarContext, null,
+ R.attr.actionModePopupWindowStyle);
mActionModePopup.setWindowLayoutType(
WindowManager.LayoutParams.TYPE_APPLICATION);
mActionModePopup.setContentView(mActionModeView);
mActionModePopup.setWidth(MATCH_PARENT);
- TypedValue heightValue = new TypedValue();
- mContext.getTheme().resolveAttribute(
- com.android.internal.R.attr.actionBarSize, heightValue, true);
- final int height = TypedValue.complexToDimensionPixelSize(heightValue.data,
- mContext.getResources().getDisplayMetrics());
+ actionBarContext.getTheme().resolveAttribute(
+ R.attr.actionBarSize, outValue, true);
+ final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
+ actionBarContext.getResources().getDisplayMetrics());
mActionModeView.setContentHeight(height);
mActionModePopup.setHeight(WRAP_CONTENT);
mShowActionModePopup = new Runnable() {
@@ -2406,7 +2689,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
};
} else {
ViewStub stub = (ViewStub) findViewById(
- com.android.internal.R.id.action_mode_bar_stub);
+ R.id.action_mode_bar_stub);
if (stub != null) {
mActionModeView = (ActionBarContextView) stub.inflate();
}
@@ -2415,8 +2698,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mActionModeView != null) {
mActionModeView.killMode();
- mode = new StandaloneActionMode(getContext(), mActionModeView, wrappedCallback,
- mActionModePopup == null);
+ mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView,
+ wrappedCallback, mActionModePopup == null);
if (callback.onCreateActionMode(mode, mode.getMenu())) {
mode.invalidate();
mActionModeView.initForMode(mode);
@@ -2484,48 +2767,180 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
@Override
- protected boolean fitSystemWindows(Rect insets) {
- mFrameOffsets.set(insets);
- updateStatusGuard(insets);
+ public void onWindowSystemUiVisibilityChanged(int visible) {
+ updateColorViews(null /* insets */);
+ }
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mFrameOffsets.set(insets.getSystemWindowInsets());
+ insets = updateColorViews(insets);
+ insets = updateStatusGuard(insets);
updateNavigationGuard(insets);
if (getForeground() != null) {
drawableChanged();
}
- return super.fitSystemWindows(insets);
+ return insets;
+ }
+
+ @Override
+ public boolean isTransitionGroup() {
+ return false;
+ }
+
+ private WindowInsets updateColorViews(WindowInsets insets) {
+ WindowManager.LayoutParams attrs = getAttributes();
+ int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
+
+ if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+ if (insets != null) {
+ mLastTopInset = Math.min(insets.getStableInsetTop(),
+ insets.getSystemWindowInsetTop());
+ mLastBottomInset = Math.min(insets.getStableInsetBottom(),
+ insets.getSystemWindowInsetBottom());
+ mLastRightInset = Math.min(insets.getStableInsetRight(),
+ insets.getSystemWindowInsetRight());
+ }
+ mStatusColorView = updateColorViewInt(mStatusColorView, sysUiVisibility,
+ SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+ mStatusBarColor, mLastTopInset, Gravity.TOP,
+ STATUS_BAR_BACKGROUND_TRANSITION_NAME,
+ com.android.internal.R.id.statusBarBackground,
+ (getAttributes().flags & FLAG_FULLSCREEN) != 0);
+ mNavigationColorView = updateColorViewInt(mNavigationColorView, sysUiVisibility,
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+ mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM,
+ NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME,
+ com.android.internal.R.id.navigationBarBackground,
+ false /* hiddenByWindowFlag */);
+ }
+
+ // When we expand the window with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, we still need
+ // to ensure that the rest of the view hierarchy doesn't notice it, unless they've
+ // explicitly asked for it.
+
+ boolean consumingNavBar =
+ (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+ && (sysUiVisibility & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0
+ && (sysUiVisibility & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+
+ int consumedRight = consumingNavBar ? mLastRightInset : 0;
+ int consumedBottom = consumingNavBar ? mLastBottomInset : 0;
+
+ if (mContentRoot != null
+ && mContentRoot.getLayoutParams() instanceof MarginLayoutParams) {
+ MarginLayoutParams lp = (MarginLayoutParams) mContentRoot.getLayoutParams();
+ if (lp.rightMargin != consumedRight || lp.bottomMargin != consumedBottom) {
+ lp.rightMargin = consumedRight;
+ lp.bottomMargin = consumedBottom;
+ mContentRoot.setLayoutParams(lp);
+
+ if (insets == null) {
+ // The insets have changed, but we're not currently in the process
+ // of dispatching them.
+ requestApplyInsets();
+ }
+ }
+ if (insets != null) {
+ insets = insets.replaceSystemWindowInsets(
+ insets.getSystemWindowInsetLeft(),
+ insets.getSystemWindowInsetTop(),
+ insets.getSystemWindowInsetRight() - consumedRight,
+ insets.getSystemWindowInsetBottom() - consumedBottom);
+ }
+ }
+
+ if (insets != null) {
+ insets = insets.consumeStableInsets();
+ }
+ return insets;
}
- private void updateStatusGuard(Rect insets) {
+ private View updateColorViewInt(View view, int sysUiVis, int systemUiHideFlag,
+ int translucentFlag, int color, int height, int verticalGravity,
+ String transitionName, int id, boolean hiddenByWindowFlag) {
+ boolean show = height > 0 && (sysUiVis & systemUiHideFlag) == 0
+ && !hiddenByWindowFlag
+ && (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);
+ view.setId(id);
+ 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) {
if (mActionModeView.getLayoutParams() instanceof MarginLayoutParams) {
- MarginLayoutParams mlp = (MarginLayoutParams) mActionModeView.getLayoutParams();
+ // Insets are magic!
+ final MarginLayoutParams mlp = (MarginLayoutParams)
+ mActionModeView.getLayoutParams();
boolean mlpChanged = false;
- final boolean nonOverlayShown =
- (getLocalFeatures() & (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0
- && mActionModeView.isShown();
- if (nonOverlayShown) {
- // set top margin to top insets, show status guard
- if (mlp.topMargin != insets.top) {
+ if (mActionModeView.isShown()) {
+ if (mTempRect == null) {
+ mTempRect = new Rect();
+ }
+ final Rect rect = mTempRect;
+
+ // If the parent doesn't consume the insets, manually
+ // apply the default system window insets.
+ mContentParent.computeSystemWindowInsets(insets, rect);
+ final int newMargin = rect.top == 0 ? insets.getSystemWindowInsetTop() : 0;
+ if (mlp.topMargin != newMargin) {
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();
+ final LayoutParams lp = (LayoutParams)
+ mStatusGuard.getLayoutParams();
if (lp.height != mlp.topMargin) {
lp.height = mlp.topMargin;
mStatusGuard.setLayoutParams(lp);
}
}
}
- insets.top = 0; // consume top insets
- showStatusGuard = true;
+
+ // The action mode's theme may differ from the app, so
+ // always show the status guard above it if we have one.
+ showStatusGuard = mStatusGuard != null;
+
+ // We only need to consume the insets if the action
+ // mode is overlaid on the app content (e.g. it's
+ // sitting in a FrameLayout, see
+ // screen_simple_overlay_action_mode.xml).
+ final boolean nonOverlay = (getLocalFeatures()
+ & (1 << FEATURE_ACTION_MODE_OVERLAY)) == 0;
+ insets = insets.consumeSystemWindowInsets(
+ false, nonOverlay && showStatusGuard /* top */, false, false);
} else {
// reset top margin
if (mlp.topMargin != 0) {
@@ -2541,9 +2956,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
@@ -2551,7 +2967,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);
}
}
@@ -2560,12 +2976,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);
}
}
@@ -2583,7 +2999,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
invalidate();
int opacity = PixelFormat.OPAQUE;
-
// Note: if there is no background, we will assume opaque. The
// common case seems to be that an application sets there to be
// no background so it can draw everything itself. For that,
@@ -2653,13 +3068,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();
@@ -2680,14 +3095,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) {
@@ -2714,19 +3129,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);
@@ -2806,14 +3221,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (false) {
System.out.println("From style:");
String s = "Attrs:";
- for (int i = 0; i < com.android.internal.R.styleable.Window.length; i++) {
- s = s + " " + Integer.toHexString(com.android.internal.R.styleable.Window[i]) + "="
+ for (int i = 0; i < R.styleable.Window.length; i++) {
+ s = s + " " + Integer.toHexString(R.styleable.Window[i]) + "="
+ a.getString(i);
}
System.out.println(s);
}
- mIsFloating = a.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false);
+ mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
@@ -2823,80 +3238,105 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
+ if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
- } else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) {
+ } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
+ if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) {
+ if (a.getBoolean(R.styleable.Window_windowActionModeOverlay, false)) {
requestFeature(FEATURE_ACTION_MODE_OVERLAY);
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
+ if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
+ requestFeature(FEATURE_SWIPE_TO_DISMISS);
+ }
+
+ if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentStatus,
+ if (a.getBoolean(R.styleable.Window_windowTranslucentStatus,
false)) {
setFlags(FLAG_TRANSLUCENT_STATUS, FLAG_TRANSLUCENT_STATUS
& (~getForcedWindowFlags()));
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowTranslucentNavigation,
+ if (a.getBoolean(R.styleable.Window_windowTranslucentNavigation,
false)) {
setFlags(FLAG_TRANSLUCENT_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION
& (~getForcedWindowFlags()));
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowOverscan, false)) {
+ if (a.getBoolean(R.styleable.Window_windowOverscan, false)) {
setFlags(FLAG_LAYOUT_IN_OVERSCAN, FLAG_LAYOUT_IN_OVERSCAN&(~getForcedWindowFlags()));
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
+ if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_windowEnableSplitTouch,
+ if (a.getBoolean(R.styleable.Window_windowEnableSplitTouch,
getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB)) {
setFlags(FLAG_SPLIT_TOUCH, FLAG_SPLIT_TOUCH&(~getForcedWindowFlags()));
}
- a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
- a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
- if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor)) {
+ a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
+ a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+ if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
- a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor,
+ a.getValue(R.styleable.Window_windowFixedWidthMajor,
mFixedWidthMajor);
}
- if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor)) {
+ if (a.hasValue(R.styleable.Window_windowFixedWidthMinor)) {
if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
- a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor,
+ a.getValue(R.styleable.Window_windowFixedWidthMinor,
mFixedWidthMinor);
}
- if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor)) {
+ if (a.hasValue(R.styleable.Window_windowFixedHeightMajor)) {
if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
- a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor,
+ a.getValue(R.styleable.Window_windowFixedHeightMajor,
mFixedHeightMajor);
}
- if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor)) {
+ if (a.hasValue(R.styleable.Window_windowFixedHeightMinor)) {
if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
- a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor,
+ a.getValue(R.styleable.Window_windowFixedHeightMinor,
mFixedHeightMinor);
}
+ if (a.getBoolean(R.styleable.Window_windowContentTransitions, false)) {
+ requestFeature(FEATURE_CONTENT_TRANSITIONS);
+ }
+ if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
+ requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
+ }
+
+ final WindowManager windowService = (WindowManager) getContext().getSystemService(
+ Context.WINDOW_SERVICE);
+ if (windowService != null) {
+ final Display display = windowService.getDefaultDisplay();
+ final boolean shouldUseBottomOutset =
+ display.getDisplayId() == Display.DEFAULT_DISPLAY
+ || (getForcedWindowFlags() & FLAG_FULLSCREEN) != 0;
+ if (shouldUseBottomOutset && a.hasValue(R.styleable.Window_windowOutsetBottom)) {
+ if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+ a.getValue(R.styleable.Window_windowOutsetBottom,
+ mOutsetBottom);
+ }
+ }
final Context context = getContext();
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);
+ R.bool.target_honeycomb_needs_options_menu);
final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) {
@@ -2904,25 +3344,42 @@ 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(
+ R.styleable.Window_windowDrawsSystemBarBackgrounds,
+ false)) {
+ setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
+ }
+ }
+ 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(
- com.android.internal.R.styleable.Window_windowCloseOnTouchOutside,
+ R.styleable.Window_windowCloseOnTouchOutside,
false)) {
setCloseOnTouchOutsideIfNotSet(true);
}
}
-
+
WindowManager.LayoutParams params = getAttributes();
if (!hasSoftInputMode()) {
params.softInputMode = a.getInt(
- com.android.internal.R.styleable.Window_windowSoftInputMode,
+ R.styleable.Window_windowSoftInputMode,
params.softInputMode);
}
- if (a.getBoolean(com.android.internal.R.styleable.Window_backgroundDimEnabled,
+ if (a.getBoolean(R.styleable.Window_backgroundDimEnabled,
mIsFloating)) {
/* All dialogs should have the window dimmed */
if ((getForcedWindowFlags()&WindowManager.LayoutParams.FLAG_DIM_BEHIND) == 0) {
@@ -2936,7 +3393,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(
- com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+ R.styleable.Window_windowAnimationStyle, 0);
}
// The rest are only done if this window is not embedded; otherwise,
@@ -2945,18 +3402,22 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mBackgroundDrawable == null) {
if (mBackgroundResource == 0) {
mBackgroundResource = a.getResourceId(
- com.android.internal.R.styleable.Window_windowBackground, 0);
+ R.styleable.Window_windowBackground, 0);
}
if (mFrameResource == 0) {
- mFrameResource = a.getResourceId(com.android.internal.R.styleable.Window_windowFrame, 0);
+ mFrameResource = a.getResourceId(R.styleable.Window_windowFrame, 0);
}
+ mBackgroundFallbackResource = a.getResourceId(
+ R.styleable.Window_windowBackgroundFallback, 0);
if (false) {
System.out.println("Background: "
+ Integer.toHexString(mBackgroundResource) + " Frame: "
+ Integer.toHexString(mFrameResource));
}
}
- mTextColor = a.getColor(com.android.internal.R.styleable.Window_textColor, 0xFF000000);
+ mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
+ mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
+ mTextColor = a.getColor(R.styleable.Window_textColor, Color.TRANSPARENT);
}
// Inflate the window decor.
@@ -2964,14 +3425,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
- if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
+ if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+ layoutResource = R.layout.screen_swipe_dismiss;
+ } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
- com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
+ R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
- layoutResource = com.android.internal.R.layout.screen_title_icons;
+ layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
@@ -2980,7 +3443,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
- layoutResource = com.android.internal.R.layout.screen_progress;
+ layoutResource = R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
@@ -2988,10 +3451,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
- com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);
+ R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
- layoutResource = com.android.internal.R.layout.screen_custom_title;
+ layoutResource = R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
@@ -3001,19 +3464,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
- com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
+ 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(
+ R.styleable.Window_windowActionBarFullscreenDecorLayout,
+ R.layout.screen_action_bar);
} else {
- layoutResource = com.android.internal.R.layout.screen_title;
+ layoutResource = R.layout.screen_title;
}
// System.out.println("Title!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
- layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
+ layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
- layoutResource = com.android.internal.R.layout.screen_simple;
+ layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
@@ -3021,6 +3486,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
@@ -3034,31 +3500,39 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+ registerSwipeCallbacks();
+ }
+
// 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);
+ mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
+
+ if (mTitleColor == 0) {
+ mTitleColor = mTextColor;
+ }
setTitleColor(mTitleColor);
}
@@ -3087,101 +3561,145 @@ 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(
+ 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);
}
+ }
+
+ mDecorContentParent.setUiOptions(mUiOptions);
- 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);
+ 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);
+ }
+
+ // Invalidate if the panel menu hasn't been created before this.
+ // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu
+ // being called in the middle of onCreate or similar.
+ // A pending invalidation will typically be resolved before the posted message
+ // would run normally in order to satisfy instance state restoration.
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (!isDestroyed() && (st == null || st.menu == null)) {
+ invalidatePanelMenu(FEATURE_ACTION_BAR);
+ }
+ } else {
+ mTitleView = (TextView)findViewById(R.id.title);
+ if (mTitleView != null) {
+ mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
+ if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
+ View titleContainer = findViewById(
+ 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 {
- splitActionBar = getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowSplitActionBar, false);
- }
- 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.");
+ 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);
+ if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
+ mDecor.setBackgroundFallback(mBackgroundFallbackResource);
+ }
+
+ // Only inflate or create a new TransitionManager if the caller hasn't
+ // already set a custom one.
+ if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
+ if (mTransitionManager == null) {
+ final int transitionRes = getWindowStyle().getResourceId(
+ 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, null,
+ R.styleable.Window_windowEnterTransition);
+ mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
+ R.styleable.Window_windowReturnTransition);
+ mExitTransition = getTransition(mExitTransition, null,
+ R.styleable.Window_windowExitTransition);
+ mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
+ R.styleable.Window_windowReenterTransition);
+ mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
+ R.styleable.Window_windowSharedElementEnterTransition);
+ mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
+ USE_DEFAULT_TRANSITION,
+ R.styleable.Window_windowSharedElementReturnTransition);
+ mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
+ R.styleable.Window_windowSharedElementExitTransition);
+ mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
+ USE_DEFAULT_TRANSITION,
+ R.styleable.Window_windowSharedElementReenterTransition);
+ if (mAllowEnterTransitionOverlap == null) {
+ mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
+ R.styleable.Window_windowAllowEnterTransitionOverlap, true);
+ }
+ if (mAllowReturnTransitionOverlap == null) {
+ mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
+ R.styleable.Window_windowAllowReturnTransitionOverlap, true);
+ }
+ if (mBackgroundFadeDurationMillis < 0) {
+ mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
+ R.styleable.Window_windowTransitionBackgroundFadeDuration,
+ DEFAULT_BACKGROUND_FADE_DURATION_MS);
+ }
+ if (mSharedElementsUseOverlay == null) {
+ mSharedElementsUseOverlay = getWindowStyle().getBoolean(
+ R.styleable.Window_windowSharedElementsUseOverlay, true);
}
}
}
}
+ private Transition getTransition(Transition currentValue, Transition defaultValue, int id) {
+ if (currentValue != defaultValue) {
+ return currentValue;
+ }
+ int transitionId = getWindowStyle().getResourceId(id, -1);
+ Transition transition = defaultValue;
+ if (transitionId != -1 && transitionId != R.transition.no_transition) {
+ TransitionInflater inflater = TransitionInflater.from(getContext());
+ transition = inflater.inflateTransition(transitionId);
+ if (transition instanceof TransitionSet &&
+ ((TransitionSet)transition).getTransitionCount() == 0) {
+ transition = null;
+ }
+ }
+ return transition;
+ }
+
private Drawable loadImageURI(Uri uri) {
try {
return Drawable.createFromStream(
@@ -3349,7 +3867,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mContentParent == null) {
installDecor();
}
- return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
+ return (mLeftIconView = (ImageView)findViewById(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) {
@@ -3359,7 +3885,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mContentParent == null && shouldInstallDecor) {
installDecor();
}
- mCircularProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_circular);
+ mCircularProgressBar = (ProgressBar) findViewById(R.id.progress_circular);
if (mCircularProgressBar != null) {
mCircularProgressBar.setVisibility(View.INVISIBLE);
}
@@ -3373,7 +3899,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mContentParent == null && shouldInstallDecor) {
installDecor();
}
- mHorizontalProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress_horizontal);
+ mHorizontalProgressBar = (ProgressBar) findViewById(R.id.progress_horizontal);
if (mHorizontalProgressBar != null) {
mHorizontalProgressBar.setVisibility(View.INVISIBLE);
}
@@ -3387,7 +3913,48 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (mContentParent == null) {
installDecor();
}
- return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
+ return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
+ }
+
+ private void registerSwipeCallbacks() {
+ SwipeDismissLayout swipeDismiss =
+ (SwipeDismissLayout) findViewById(R.id.content);
+ swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
+ @Override
+ public void onDismissed(SwipeDismissLayout layout) {
+ dispatchOnWindowDismissed();
+ }
+ });
+ swipeDismiss.setOnSwipeProgressChangedListener(
+ new SwipeDismissLayout.OnSwipeProgressChangedListener() {
+ private static final float ALPHA_DECREASE = 0.5f;
+ private boolean mIsTranslucent = false;
+ @Override
+ public void onSwipeProgressChanged(
+ SwipeDismissLayout layout, float progress, float translate) {
+ WindowManager.LayoutParams newParams = getAttributes();
+ newParams.x = (int) translate;
+ newParams.alpha = 1 - (progress * ALPHA_DECREASE);
+ setAttributes(newParams);
+
+ int flags = 0;
+ if (newParams.x == 0) {
+ flags = FLAG_FULLSCREEN;
+ } else {
+ flags = FLAG_LAYOUT_NO_LIMITS;
+ }
+ setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+ }
+
+ @Override
+ public void onSwipeCancelled(SwipeDismissLayout layout) {
+ WindowManager.LayoutParams newParams = getAttributes();
+ newParams.x = 0;
+ newParams.alpha = 1;
+ setAttributes(newParams);
+ setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+ }
+ });
}
/**
@@ -3456,6 +4023,150 @@ 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(
+ R.styleable.Window_windowIsTranslucent, 0), false);
+ }
+
+ @Override
+ public void setEnterTransition(Transition enterTransition) {
+ mEnterTransition = enterTransition;
+ }
+
+ @Override
+ public void setReturnTransition(Transition transition) {
+ mReturnTransition = transition;
+ }
+
+ @Override
+ public void setExitTransition(Transition exitTransition) {
+ mExitTransition = exitTransition;
+ }
+
+ @Override
+ public void setReenterTransition(Transition transition) {
+ mReenterTransition = transition;
+ }
+
+ @Override
+ public void setSharedElementEnterTransition(Transition sharedElementEnterTransition) {
+ mSharedElementEnterTransition = sharedElementEnterTransition;
+ }
+
+ @Override
+ public void setSharedElementReturnTransition(Transition transition) {
+ mSharedElementReturnTransition = transition;
+ }
+
+ @Override
+ public void setSharedElementExitTransition(Transition sharedElementExitTransition) {
+ mSharedElementExitTransition = sharedElementExitTransition;
+ }
+
+ @Override
+ public void setSharedElementReenterTransition(Transition transition) {
+ mSharedElementReenterTransition = transition;
+ }
+
+ @Override
+ public Transition getEnterTransition() {
+ return mEnterTransition;
+ }
+
+ @Override
+ public Transition getReturnTransition() {
+ return mReturnTransition == USE_DEFAULT_TRANSITION ? getEnterTransition()
+ : mReturnTransition;
+ }
+
+ @Override
+ public Transition getExitTransition() {
+ return mExitTransition;
+ }
+
+ @Override
+ public Transition getReenterTransition() {
+ return mReenterTransition == USE_DEFAULT_TRANSITION ? getExitTransition()
+ : mReenterTransition;
+ }
+
+ @Override
+ public Transition getSharedElementEnterTransition() {
+ return mSharedElementEnterTransition;
+ }
+
+ @Override
+ public Transition getSharedElementReturnTransition() {
+ return mSharedElementReturnTransition == USE_DEFAULT_TRANSITION
+ ? getSharedElementEnterTransition() : mSharedElementReturnTransition;
+ }
+
+ @Override
+ public Transition getSharedElementExitTransition() {
+ return mSharedElementExitTransition;
+ }
+
+ @Override
+ public Transition getSharedElementReenterTransition() {
+ return mSharedElementReenterTransition == USE_DEFAULT_TRANSITION
+ ? getSharedElementExitTransition() : mSharedElementReenterTransition;
+ }
+
+ @Override
+ public void setAllowEnterTransitionOverlap(boolean allow) {
+ mAllowEnterTransitionOverlap = allow;
+ }
+
+ @Override
+ public boolean getAllowEnterTransitionOverlap() {
+ return (mAllowEnterTransitionOverlap == null) ? true : mAllowEnterTransitionOverlap;
+ }
+
+ @Override
+ public void setAllowReturnTransitionOverlap(boolean allowExitTransitionOverlap) {
+ mAllowReturnTransitionOverlap = allowExitTransitionOverlap;
+ }
+
+ @Override
+ public boolean getAllowReturnTransitionOverlap() {
+ return (mAllowReturnTransitionOverlap == null) ? true : mAllowReturnTransitionOverlap;
+ }
+
+ @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;
+ }
+
+ @Override
+ public void setSharedElementsUseOverlay(boolean sharedElementsUseOverlay) {
+ mSharedElementsUseOverlay = sharedElementsUseOverlay;
+ }
+
+ @Override
+ public boolean getSharedElementsUseOverlay() {
+ return (mSharedElementsUseOverlay == null) ? true : mSharedElementsUseOverlay;
+ }
+
private static final class DrawableFeatureState {
DrawableFeatureState(int _featureId) {
featureId = _featureId;
@@ -3547,11 +4258,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.
*/
@@ -3597,18 +4308,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
void setStyle(Context context) {
- TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+ TypedArray a = context.obtainStyledAttributes(R.styleable.Theme);
background = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelBackground, 0);
+ R.styleable.Theme_panelBackground, 0);
fullBackground = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelFullBackground, 0);
+ R.styleable.Theme_panelFullBackground, 0);
windowAnimations = a.getResourceId(
- com.android.internal.R.styleable.Theme_windowAnimationStyle, 0);
+ R.styleable.Theme_windowAnimationStyle, 0);
isCompact = a.getBoolean(
- com.android.internal.R.styleable.Theme_panelMenuIsCompact, false);
+ R.styleable.Theme_panelMenuIsCompact, false);
listPresenterTheme = a.getResourceId(
- com.android.internal.R.styleable.Theme_panelMenuListTheme,
- com.android.internal.R.style.Theme_ExpandedMenu);
+ R.styleable.Theme_panelMenuListTheme,
+ R.style.Theme_ExpandedMenu);
a.recycle();
}
@@ -3635,9 +4346,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (listMenuPresenter == null) {
listMenuPresenter = new ListMenuPresenter(
- com.android.internal.R.layout.list_menu_item_layout, listPresenterTheme);
+ R.layout.list_menu_item_layout, listPresenterTheme);
listMenuPresenter.setCallback(cb);
- listMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
+ listMenuPresenter.setId(R.id.list_menu_presenter);
menu.addMenuPresenter(listMenuPresenter);
}
@@ -3656,7 +4367,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (iconMenuPresenter == null) {
iconMenuPresenter = new IconMenuPresenter(context);
iconMenuPresenter.setCallback(cb);
- iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter);
+ iconMenuPresenter.setId(R.id.icon_menu_presenter);
menu.addMenuPresenter(iconMenuPresenter);
}
@@ -3889,4 +4600,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 07f5490..35e5dab 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -41,16 +41,16 @@ import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.media.AudioAttributes;
import android.media.AudioManager;
-import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
+import android.media.session.MediaSessionLegacyHelper;
import android.os.Bundle;
import android.os.FactoryTest;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
@@ -62,9 +62,13 @@ import android.os.SystemProperties;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.os.Vibrator;
+import android.provider.MediaStore;
import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
+import android.speech.RecognizerIntent;
+import android.telecom.TelecomManager;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -89,17 +93,23 @@ import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;
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.AnimationSet;
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;
import java.io.File;
import java.io.FileReader;
@@ -111,6 +121,9 @@ import static android.view.WindowManager.LayoutParams.*;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static android.view.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
/**
* WindowManagerPolicy implementation for the Android phone UI. This
@@ -126,6 +139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_STARTING_WINDOW = false;
+ static final boolean DEBUG_WAKEUP = false;
static final boolean SHOW_STARTING_ANIMATIONS = true;
static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
@@ -134,6 +148,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+ static final int SHORT_PRESS_POWER_NOTHING = 0;
+ static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
+ static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
+ static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME = 3;
+
static final int LONG_PRESS_POWER_NOTHING = 0;
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1;
static final int LONG_PRESS_POWER_SHUT_OFF = 2;
@@ -167,12 +186,20 @@ 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;
+
+ private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build();
/**
* Keyguard stuff
*/
private WindowState mKeyguardScrim;
+ private boolean mKeyguardHidden;
+ private boolean mKeyguardDrawnOnce;
/* Table of Application Launch keys. Maps from key codes to intent categories.
*
@@ -197,6 +224,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
}
+ /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
+ static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
+
/**
* Lock protecting internal state. Must not call out into window
* manager with lock held. (This lock will be acquired in places
@@ -207,12 +237,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Context mContext;
IWindowManager mWindowManager;
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;
@@ -223,6 +256,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;
@@ -232,7 +271,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
boolean mEnableShiftMenuBugReports = false;
- boolean mHeadless;
boolean mSafeMode;
WindowState mStatusBar = null;
int mStatusBarHeight;
@@ -244,8 +282,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int[] mNavigationBarHeightForRotation = new int[4];
int[] mNavigationBarWidthForRotation = new int[4];
- WindowState mKeyguard = null;
+ boolean mBootMessageNeedsHiding;
KeyguardServiceDelegate mKeyguardDelegate;
+ final Runnable mWindowManagerDrawCallback = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG_WAKEUP) Slog.i(TAG, "All windows ready for display!");
+ mHandler.sendEmptyMessage(MSG_WINDOW_MANAGER_DRAWN_COMPLETE);
+ }
+ };
+ final ShowListener mKeyguardDelegateCallback = new ShowListener() {
+ @Override
+ public void onShown(IBinder windowToken) {
+ if (DEBUG_WAKEUP) Slog.d(TAG, "mKeyguardDelegate.ShowListener.onShown.");
+ mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
+ }
+ };
+
GlobalActions mGlobalActions;
volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
boolean mPendingPowerKeyUpCanceled;
@@ -253,21 +306,18 @@ 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;
+ int mCameraLensCoverState = CAMERA_LENS_COVER_ABSENT;
boolean mHaveBuiltInKeyboard;
boolean mSystemReady;
boolean mSystemBooted;
boolean mHdmiPlugged;
+ IUiModeManager mUiModeManager;
int mUiMode;
int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
int mLidOpenRotation;
@@ -277,6 +327,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;
@@ -285,19 +338,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mUserRotation = Surface.ROTATION_0;
boolean mAccelerometerDefault;
+ boolean mSupportAutoRotation;
int mAllowAllRotations = -1;
boolean mCarDockEnablesAccelerometer;
boolean mDeskDockEnablesAccelerometer;
int mLidKeyboardAccessibility;
int mLidNavigationAccessibility;
boolean mLidControlsSleep;
+ int mShortPressOnPowerBehavior = -1;
int mLongPressOnPowerBehavior = -1;
- boolean mScreenOnEarly = false;
- boolean mScreenOnFully = false;
+ boolean mAwake;
+ boolean mScreenOnEarly;
+ boolean mScreenOnFully;
+ ScreenOnListener mScreenOnListener;
+ boolean mKeyguardDrawComplete;
+ boolean mWindowManagerDrawComplete;
boolean mOrientationSensorEnabled = false;
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mHasSoftInput = false;
- boolean mTouchExplorationEnabled = false;
boolean mTranslucentDecorEnabled = true;
int mPointerLocationMode = 0; // guarded by mLock
@@ -306,17 +364,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
@@ -353,6 +400,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;
@@ -379,10 +430,12 @@ 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;
HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
+ HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
boolean mTopIsFullscreen;
boolean mForceStatusBar;
boolean mForceStatusBarFromKeyguard;
@@ -400,6 +453,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;
@@ -412,6 +471,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;
@@ -473,10 +533,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions =
new SparseArray<KeyCharacterMap.FallbackAction>();
+ private final LogDecelerateInterpolator mLogDecelerateInterpolator
+ = new LogDecelerateInterpolator(100, 0);
+
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
+ private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
+ private static final int MSG_KEYGUARD_DRAWN_TIMEOUT = 6;
+ private static final int MSG_WINDOW_MANAGER_DRAWN_COMPLETE = 7;
+ private static final int MSG_DISPATCH_SHOW_RECENTS = 9;
+ private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
+ private static final int MSG_HIDE_BOOT_MESSAGE = 11;
+ private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
private class PolicyHandler extends Handler {
@Override
@@ -494,6 +564,30 @@ 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");
+ finishKeyguardDrawn();
+ break;
+ case MSG_KEYGUARD_DRAWN_TIMEOUT:
+ Slog.w(TAG, "Keyguard drawn timeout. Setting mKeyguardDrawComplete");
+ finishKeyguardDrawn();
+ break;
+ case MSG_WINDOW_MANAGER_DRAWN_COMPLETE:
+ if (DEBUG_WAKEUP) Slog.w(TAG, "Setting mWindowManagerDrawComplete");
+ finishWindowsDrawn();
+ break;
+ case MSG_HIDE_BOOT_MESSAGE:
+ handleHideBootMessage();
+ break;
+ case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
+ launchVoiceAssistWithWakeLock(msg.arg1 != 0);
+ break;
}
}
}
@@ -519,6 +613,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);
@@ -534,9 +631,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();
}
@@ -546,6 +646,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);
@@ -593,13 +709,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* screen is switched off.
*/
boolean needSensorRunningLp() {
- if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
- || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
- || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
- || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
- // If the application has explicitly requested to follow the
- // orientation, then we need to turn the sensor or.
- return true;
+ if (mSupportAutoRotation) {
+ if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+ || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+ || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
+ || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
+ // If the application has explicitly requested to follow the
+ // orientation, then we need to turn the sensor on.
+ return true;
+ }
}
if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
(mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
@@ -620,7 +738,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// still be turned off when the screen is off.)
return false;
}
- return true;
+ return mSupportAutoRotation;
}
/*
@@ -640,11 +758,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
//Could have been invoked due to screen turning on or off or
//change of the currently visible window's orientation
- if (localLOGV) Slog.v(TAG, "Screen status="+mScreenOnEarly+
- ", current orientation="+mCurrentAppOrientation+
- ", SensorEnabled="+mOrientationSensorEnabled);
+ if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly
+ + ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation
+ + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled);
boolean disable = true;
- if (mScreenOnEarly) {
+ if (mScreenOnEarly && mAwake) {
if (needSensorRunningLp()) {
disable = false;
//enable listener if not already enabled
@@ -666,7 +784,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void interceptPowerKeyDown(boolean handled) {
mPowerKeyHandled = handled;
if (!handled) {
- mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+ mHandler.postDelayed(mPowerLongPress,
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
}
@@ -705,15 +824,42 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mKeyguardDelegate.isShowing()) {
// Double the time it takes to take a screenshot from the keyguard
return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
- ViewConfiguration.getGlobalActionKeyTimeout());
+ ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
- return ViewConfiguration.getGlobalActionKeyTimeout();
+ return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
}
private void cancelPendingScreenshotChordAction() {
mHandler.removeCallbacks(mScreenshotRunnable);
}
+ private void powerShortPress(long eventTime) {
+ if (mShortPressOnPowerBehavior < 0) {
+ mShortPressOnPowerBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortPressOnPowerBehavior);
+ }
+
+ switch (mShortPressOnPowerBehavior) {
+ case SHORT_PRESS_POWER_NOTHING:
+ break;
+ case SHORT_PRESS_POWER_GO_TO_SLEEP:
+ mPowerManager.goToSleep(eventTime,
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ break;
+ case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
+ mPowerManager.goToSleep(eventTime,
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ break;
+ case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
+ mPowerManager.goToSleep(eventTime,
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ launchHomeFromHotKey();
+ break;
+ }
+ }
+
private final Runnable mPowerLongPress = new Runnable() {
@Override
public void run() {
@@ -735,8 +881,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:
@@ -756,7 +901,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);
}
@@ -774,6 +926,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;
@@ -804,52 +961,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,
@@ -857,8 +968,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mContext = context;
mWindowManager = windowManager;
mWindowManagerFuncs = windowManagerFuncs;
- mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
+ 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());
@@ -886,6 +1000,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mBroadcastWakeLock");
mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
+ mSupportAutoRotation = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_supportAutoRotation);
mLidOpenRotation = readRotation(
com.android.internal.R.integer.config_lidOpenRotation);
mCarDockRotation = readRotation(
@@ -908,6 +1024,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);
@@ -968,6 +1087,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(),
@@ -982,10 +1105,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
initializeHdmiState();
// Match current screen state.
- if (mPowerManager.isScreenOn()) {
- screenTurningOn(null);
- } else {
- screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+ if (!mPowerManager.isInteractive()) {
+ goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
}
}
@@ -1106,7 +1227,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
@@ -1137,6 +1259,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,
@@ -1175,19 +1306,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 && !mAwake
+ && (!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);
@@ -1207,22 +1352,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;
}
@@ -1264,11 +1401,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:
@@ -1314,7 +1453,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:
@@ -1351,13 +1489,39 @@ 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_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
}
-
+
void readLidState() {
mLidState = mWindowManagerFuncs.getLidState();
}
-
+
+ private void readCameraLensCoverState() {
+ mCameraLensCoverState = mWindowManagerFuncs.getCameraLensCoverState();
+ }
+
private boolean isHidden(int accessibilityMode) {
switch (accessibilityMode) {
case 1:
@@ -1413,41 +1577,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
@@ -1518,6 +1681,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
@@ -1529,6 +1693,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
@@ -1540,10 +1705,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,
@@ -1553,8 +1720,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
@@ -1565,7 +1739,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:
@@ -1573,6 +1746,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ @Override
+ public WindowState getWinShowWhenLockedLw() {
+ return mWinShowWhenLocked;
+ }
+
/** {@inheritDoc} */
@Override
public View addStartingWindow(IBinder appToken, String packageName, int theme,
@@ -1676,7 +1854,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return view.getParent() != null ? view : null;
} catch (WindowManager.BadTokenException e) {
// ignore
- Log.w(TAG, appToken + " already running, starting window not displayed");
+ Log.w(TAG, appToken + " already running, starting window not displayed. " +
+ e.getMessage());
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
@@ -1693,6 +1872,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void removeStartingWindow(IBinder appToken, View window) {
if (DEBUG_STARTING_WINDOW) {
RuntimeException e = new RuntimeException("here");
@@ -1708,19 +1888,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:
@@ -1734,6 +1915,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
mStatusBar = win;
mStatusBarController.setWindow(win);
+ mKeyguardDelegate.hideScrim();
break;
case TYPE_NAVIGATION_BAR:
mContext.enforceCallingOrSelfPermission(
@@ -1763,12 +1945,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;
@@ -1781,13 +1957,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");
@@ -1799,19 +1973,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.
@@ -1896,10 +2071,38 @@ 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);
+ public Animation createForceHideEnterAnimation(boolean onWallpaper,
+ boolean goingToNotificationShade) {
+ if (goingToNotificationShade) {
+ return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_behind_enter_fade_in);
+ } else if (onWallpaper) {
+ Animation a = AnimationUtils.loadAnimation(mContext,
+ R.anim.lock_screen_behind_enter_wallpaper);
+ AnimationSet set = (AnimationSet) a;
+
+ // TODO: Use XML interpolators when we have log interpolators available in XML.
+ set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
+ set.getAnimations().get(1).setInterpolator(mLogDecelerateInterpolator);
+ return set;
+ } else {
+ Animation a = AnimationUtils.loadAnimation(mContext,
+ R.anim.lock_screen_behind_enter);
+ AnimationSet set = (AnimationSet) a;
+
+ // TODO: Use XML interpolators when we have log interpolators available in XML.
+ set.getAnimations().get(0).setInterpolator(mLogDecelerateInterpolator);
+ return set;
+ }
+ }
+
+
+ @Override
+ public Animation createForceHideWallpaperExitAnimation(boolean goingToNotificationShade) {
+ if (goingToNotificationShade) {
+ return null;
+ } else {
+ return AnimationUtils.loadAnimation(mContext, R.anim.lock_screen_wallpaper_exit);
+ }
}
private static void awakenDreams() {
@@ -1918,9 +2121,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ServiceManager.checkService(DreamService.DREAM_SERVICE));
}
- static ITelephony getTelephonyService() {
- return ITelephony.Stub.asInterface(
- ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+ TelecomManager getTelecommService() {
+ return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
}
static IAudioService getAudioService() {
@@ -1978,6 +2180,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 && !KeyEvent.isMetaKey(keyCode)) {
+ 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
@@ -2001,16 +2209,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);
+ TelecomManager telecomManager = getTelecommService();
+ if (telecomManager != null && telecomManager.isRinging()) {
+ Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+ return -1;
}
// Delay handling home if a double-tap is possible.
@@ -2022,6 +2226,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(false /*immediate*/);
+ return -1;
+ }
+
// Go home!
launchHomeFromHotKey();
return -1;
@@ -2032,9 +2243,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;
}
@@ -2134,6 +2345,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
return -1;
+ } else if (keyCode == KeyEvent.KEYCODE_VOICE_ASSIST) {
+ if (!down) {
+ Intent voiceIntent;
+ if (!keyguardOn) {
+ voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
+ } else {
+ voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, true);
+ }
+ mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
+ }
} else if (keyCode == KeyEvent.KEYCODE_SYSRQ) {
if (down && repeatCount == 0) {
mHandler.post(mScreenshotRunnable);
@@ -2172,8 +2394,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, brightness,
UserHandle.USER_CURRENT_OR_SELF);
- Intent intent = new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG);
- mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ mContext.startActivityAsUser(new Intent(Intent.ACTION_SHOW_BRIGHTNESS_DIALOG),
+ UserHandle.CURRENT_OR_SELF);
+ }
+ return -1;
+ } else if (KeyEvent.isMetaKey(keyCode)) {
+ if (down) {
+ mPendingMetaAction = true;
+ } else if (mPendingMetaAction) {
+ launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD);
}
return -1;
}
@@ -2247,23 +2476,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- // Display task switcher for ALT-TAB or Meta-TAB.
+ // Display task switcher for ALT-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, false);
}
// Handle keyboard language switching.
@@ -2286,6 +2512,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return -1;
}
+ // Reserve all the META modifier combos for system behavior
+ if ((metaState & KeyEvent.META_META_ON) != 0) {
+ return -1;
+ }
+
// Let the application handle the key.
return 0;
}
@@ -2359,7 +2590,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
- int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+ int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
win, fallbackEvent, policyFlags);
@@ -2378,7 +2609,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) {
@@ -2391,10 +2622,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void launchAssistAction() {
+ launchAssistAction(null);
+ }
+
+ private void launchAssistAction(String hint) {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
.getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
if (intent != null) {
+ if (hint != null) {
+ intent.putExtra(hint, true);
+ }
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -2436,7 +2674,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;
}
@@ -2445,30 +2683,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, boolean triggeredFromHome) {
+ mPreloadedRecentApps = false; // preloading no longer needs to be canceled
+ try {
+ IStatusBarService statusbar = getStatusBarService();
+ if (statusbar != null) {
+ statusbar.hideRecentApps(triggeredFromAltTab, triggeredFromHome);
+ }
+ } 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 {
@@ -2486,8 +2758,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, true);
+ } else {
+ // Otherwise, just launch Home
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+ startDockOrHome();
+ }
}
}
@@ -2571,6 +2851,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.
@@ -2583,8 +2864,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)) {
@@ -2675,13 +2957,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;
@@ -2703,12 +2985,16 @@ 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;
navTranslucent &= !immersiveSticky; // transient trumps translucent
- navTranslucent &= areTranslucentBarsAllowed();
+ boolean isKeyguardShowing = isStatusBarKeyguard() && !mHideLockScreen;
+ if (!isKeyguardShowing) {
+ navTranslucent &= areTranslucentBarsAllowed();
+ }
// When the navigation bar isn't visible, we put up a fake
// input window to catch all touch events. This way we can
@@ -2756,7 +3042,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
@@ -2790,14 +3077,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;
@@ -2822,14 +3110,17 @@ 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;
- statusBarTranslucent &= areTranslucentBarsAllowed();
+ boolean statusBarTranslucent = (sysui
+ & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
+ if (!isKeyguardShowing) {
+ statusBarTranslucent &= areTranslucentBarsAllowed();
+ }
// If the status bar is hidden, we don't want to cause
// windows behind it to scroll.
@@ -2839,10 +3130,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(
@@ -2913,7 +3204,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;
@@ -2951,10 +3247,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();
@@ -2965,9 +3262,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;
@@ -2975,6 +3272,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
@@ -2982,6 +3280,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
@@ -3007,6 +3311,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// IM dock windows always go to the bottom of the screen.
attrs.gravity = Gravity.BOTTOM;
mDockLayer = win.getSurfaceLayer();
+ } else if (win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+ pf.left = df.left = of.left = mUnrestrictedScreenLeft;
+ pf.top = df.top = of.top = mUnrestrictedScreenTop;
+ pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;
+ pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight + mUnrestrictedScreenTop;
+ cf.left = vf.left = mStableLeft;
+ cf.top = vf.top = mStableTop;
+ cf.right = vf.right = mStableRight;
+ vf.bottom = mStableBottom;
+ cf.bottom = mContentBottom;
} else {
// Default policy decor for the default display
@@ -3024,12 +3338,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;
@@ -3038,7 +3356,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
@@ -3083,9 +3401,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
@@ -3118,16 +3435,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
@@ -3202,13 +3526,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
+ mOverscanScreenHeight;
} else if (attrs.type == TYPE_WALLPAPER) {
- // The wallpaper also has Real Ultimate Power.
- pf.left = df.left = of.left = cf.left = mUnrestrictedScreenLeft;
- pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
- pf.right = df.right = of.right = cf.right
- = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
- pf.bottom = df.bottom = of.bottom = cf.bottom
- = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+ // The wallpaper also has Real Ultimate Power, but we want to tell
+ // it about the overscan area.
+ pf.left = df.left = mOverscanScreenLeft;
+ pf.top = df.top = mOverscanScreenTop;
+ pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+ pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+ of.left = cf.left = mUnrestrictedScreenLeft;
+ of.top = cf.top = mUnrestrictedScreenTop;
+ of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+ of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
} else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
&& attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
@@ -3222,7 +3549,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
@@ -3291,7 +3619,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;
@@ -3316,21 +3649,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && attrs.type != TYPE_SYSTEM_ERROR) {
- df.left = df.top = of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
- df.right = df.bottom = of.right = of.bottom = cf.right = cf.bottom
- = vf.right = vf.bottom = 10000;
+ df.left = df.top = -10000;
+ df.right = df.bottom = 10000;
+ if (attrs.type != TYPE_WALLPAPER) {
+ of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
+ of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
+ }
}
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.
@@ -3339,6 +3676,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) {
@@ -3347,6 +3688,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) {
@@ -3357,6 +3701,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() {
@@ -3368,43 +3746,48 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
mAppsToBeHidden.clear();
+ mAppsThatDismissKeyguard.clear();
mForceStatusBar = false;
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
- && attrs.type <= LAST_APPLICATION_WINDOW;
+ && attrs.type < FIRST_SYSTEM_WINDOW;
if (attrs.type == TYPE_DREAM) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
@@ -3415,39 +3798,58 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- final boolean showWhenLocked = (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+ final boolean showWhenLocked = (fl & FLAG_SHOW_WHEN_LOCKED) != 0;
+ final boolean dismissKeyguard = (fl & FLAG_DISMISS_KEYGUARD) != 0;
+ final boolean secureKeyguard = isKeyguardSecure();
if (appWindow) {
+ final IApplicationToken appToken = win.getAppToken();
if (showWhenLocked) {
- mAppsToBeHidden.remove(win.getAppToken());
+ // Remove any previous windows with the same appToken.
+ mAppsToBeHidden.remove(appToken);
+ mAppsThatDismissKeyguard.remove(appToken);
+ if (mAppsToBeHidden.isEmpty() && isKeyguardSecureIncludingHidden()) {
+ mWinShowWhenLocked = win;
+ mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
+ }
+ } else if (dismissKeyguard) {
+ if (secureKeyguard) {
+ mAppsToBeHidden.add(appToken);
+ } else {
+ mAppsToBeHidden.remove(appToken);
+ }
+ mAppsThatDismissKeyguard.add(appToken);
} else {
- mAppsToBeHidden.add(win.getAppToken());
+ mAppsToBeHidden.add(appToken);
}
if (attrs.x == 0 && attrs.y == 0
&& attrs.width == WindowManager.LayoutParams.MATCH_PARENT
&& attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
- if (mAppsToBeHidden.isEmpty()) {
- if (showWhenLocked) {
- if (DEBUG_LAYOUT) Slog.v(TAG,
- "Setting mHideLockScreen to true by win " + win);
- mHideLockScreen = true;
- mForceStatusBarFromKeyguard = false;
- }
- if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
- && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
- if (DEBUG_LAYOUT) Slog.v(TAG,
- "Setting mDismissKeyguard true by win " + win);
- mDismissKeyguard = mWinDismissingKeyguard == win ?
- DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
- mWinDismissingKeyguard = win;
- mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure();
- }
+ if (!mAppsThatDismissKeyguard.isEmpty() &&
+ mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+ 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 && secureKeyguard;
+ } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) {
+ if (DEBUG_LAYOUT) Slog.v(TAG,
+ "Setting mHideLockScreen to true by win " + win);
+ mHideLockScreen = true;
+ mForceStatusBarFromKeyguard = false;
}
- 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);
+ }
}
}
}
@@ -3455,6 +3857,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;
@@ -3487,13 +3899,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 mTopIsFullscreen is set only if the window
@@ -3529,11 +3942,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;
@@ -3547,24 +3961,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() {
@@ -3574,12 +3986,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);
}
}
@@ -3594,15 +4006,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) {
@@ -3614,10 +4058,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
- // do nothing if headless
- if (mHeadless) return;
-
// lid changed state
final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
if (newLidState == mLidState) {
@@ -3635,6 +4077,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ @Override
+ public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
+ int lensCoverState = lensCovered ? CAMERA_LENS_COVERED : CAMERA_LENS_UNCOVERED;
+ if (mCameraLensCoverState == lensCoverState) {
+ return;
+ }
+ if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
+ lensCoverState == CAMERA_LENS_UNCOVERED) {
+ Intent intent;
+ final boolean keyguardActive = mKeyguardDelegate == null ? false :
+ mKeyguardDelegate.isShowing();
+ if (keyguardActive) {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+ } else {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ }
+ mPowerManager.wakeUp(whenNanos / 1000000);
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ }
+ mCameraLensCoverState = lensCoverState;
+ }
+
void setHdmiPlugged(boolean plugged) {
if (mHdmiPlugged != plugged) {
mHdmiPlugged = plugged;
@@ -3680,57 +4144,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;
@@ -3802,12 +4215,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
return 0;
}
+ final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
@@ -3819,55 +4233,53 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// This will prevent any keys other than the power button from waking the screen
// when the keyguard is hidden by another activity.
final boolean keyguardActive = (mKeyguardDelegate == null ? false :
- (isScreenOn ?
- mKeyguardDelegate.isShowingAndNotHidden() :
+ (interactive ?
+ mKeyguardDelegate.isShowingAndNotOccluded() :
mKeyguardDelegate.isShowing()));
- if (keyCode == KeyEvent.KEYCODE_POWER) {
- policyFlags |= WindowManagerPolicy.FLAG_WAKE;
- }
- final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
- | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
- + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
- + " policyFlags=" + Integer.toHexString(policyFlags)
- + " isWakeKey=" + isWakeKey);
- }
-
- if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
- && event.getRepeatCount() == 0) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ + " interactive=" + interactive + " keyguardActive=" + keyguardActive
+ + " policyFlags=" + Integer.toHexString(policyFlags));
}
- // Basic policy based on screen state and keyguard.
- // FIXME: This policy isn't quite correct. We shouldn't care whether the screen
- // is on or off, really. We should care about whether the device is in an
- // interactive state or is in suspend pretending to be "off".
- // The primary screen might be turned off due to proximity sensor or
- // because we are presenting media on an auxiliary screen or remotely controlling
- // the device some other way (which is why we have an exemption here for injected
- // events).
+ // Basic policy based on interactive state.
int result;
- if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
- // When the screen is on or if the key is injected pass the key to the application.
+ boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
+ || event.isWakeKey();
+ if (interactive || (isInjected && !isWakeKey)) {
+ // When the device is interactive or the key is injected pass the
+ // key to the application.
+ result = ACTION_PASS_TO_USER;
+ isWakeKey = false;
+ } else if (!interactive && shouldDispatchInputWhenNonInteractive()) {
+ // If we're currently dozing with the screen on and the keyguard showing, pass the key
+ // to the application but preserve its wake key status to make sure we still move
+ // from dozing to fully interactive if we would normally go from off to fully
+ // interactive.
result = ACTION_PASS_TO_USER;
} 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.
result = 0;
- if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
- result |= ACTION_WAKE_UP;
+ if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+ isWakeKey = false;
}
}
// 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;
}
+ boolean useHapticFeedback = down
+ && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
+ && event.getRepeatCount() == 0;
+
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -3875,7 +4287,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
- if (isScreenOn && !mVolumeDownKeyTriggered
+ if (interactive && !mVolumeDownKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeDownKeyTriggered = true;
mVolumeDownKeyTime = event.getDownTime();
@@ -3889,7 +4301,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (down) {
- if (isScreenOn && !mVolumeUpKeyTriggered
+ if (interactive && !mVolumeUpKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mVolumeUpKeyTriggered = true;
cancelPendingPowerKeyAction();
@@ -3901,44 +4313,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);
+ TelecomManager telecomManager = getTelecommService();
+ if (telecomManager != null) {
+ if (telecomManager.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.)
+ telecomManager.silenceRinger();
+
+ // And *don't* pass this key thru to the current activity
+ // (which is probably the InCallScreen.)
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
+ if (telecomManager.isInCall()
+ && (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;
}
}
@@ -3948,16 +4360,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- ITelephony telephonyService = getTelephonyService();
+ TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
- if (telephonyService != null) {
- try {
- hungUp = telephonyService.endCall();
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony threw RemoteException", ex);
- }
+ if (telecomManager != null) {
+ hungUp = telecomManager.endCall();
}
- interceptPowerKeyDown(!isScreenOn || hungUp);
+ interceptPowerKeyDown(!interactive || hungUp);
} else {
if (interceptPowerKeyUp(canceled)) {
if ((mEndcallBehavior
@@ -3968,7 +4376,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime(),
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ isWakeKey = false;
}
}
}
@@ -3978,64 +4388,67 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
- mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
- isImmersiveMode(mLastSystemUiFlags));
- if (isScreenOn && !mPowerKeyTriggered
+ 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;
mPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
}
- ITelephony telephonyService = getTelephonyService();
+ TelecomManager telecomManager = 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() && isScreenOn) {
- // 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 (telecomManager != null) {
+ if (telecomManager.isRinging()) {
+ // Pressing Power while there's a ringing incoming
+ // call should silence the ringer.
+ telecomManager.silenceRinger();
+ } else if ((mIncallPowerBehavior
+ & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+ && telecomManager.isInCall() && interactive) {
+ // Otherwise, if "Power button ends call" is enabled,
+ // the Power button will hang up any current active call.
+ hungUp = telecomManager.endCall();
}
}
- interceptPowerKeyDown(!isScreenOn || hungUp
+ interceptPowerKeyDown(!interactive || hungUp
|| mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
} else {
mPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ powerShortPress(event.getEventTime());
+ isWakeKey = false;
}
mPendingPowerKeyUpCanceled = false;
}
break;
}
+ case KeyEvent.KEYCODE_SLEEP: {
+ result &= ~ACTION_PASS_TO_USER;
+ if (!mPowerManager.isInteractive()) {
+ useHapticFeedback = false; // suppress feedback if already non-interactive
+ }
+ mPowerManager.goToSleep(event.getEventTime(),
+ PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+ isWakeKey = false;
+ break;
+ }
+
+ case KeyEvent.KEYCODE_WAKEUP: {
+ result &= ~ACTION_PASS_TO_USER;
+ isWakeKey = true;
+ break;
+ }
+
case KeyEvent.KEYCODE_MEDIA_PLAY:
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);
- }
- }
- }
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_STOP:
@@ -4045,6 +4458,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
+ // If the global session is active pass all media keys to it
+ // instead of the active window.
+ result &= ~ACTION_PASS_TO_USER;
+ }
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
@@ -4062,25 +4480,42 @@ 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);
+ TelecomManager telecomManager = getTelecommService();
+ if (telecomManager != null) {
+ if (telecomManager.isRinging()) {
+ Log.i(TAG, "interceptKeyBeforeQueueing:"
+ + " CALL key-down while ringing: Answer the call!");
+ telecomManager.acceptRingingCall();
+
+ // And *don't* pass this key thru to the current activity
+ // (which is presumably the InCallScreen.)
+ result &= ~ACTION_PASS_TO_USER;
}
}
}
break;
}
+ case KeyEvent.KEYCODE_VOICE_ASSIST: {
+ // Only do this if we would otherwise not pass it to the user. In that case,
+ // interceptKeyBeforeDispatching would apply a similar but different policy in
+ // order to invoke voice assist actions. Note that we need to make a copy of the
+ // key event here because the original key event will be recycled when we return.
+ if ((result & ACTION_PASS_TO_USER) == 0 && !down) {
+ mBroadcastWakeLock.acquire();
+ Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK,
+ keyguardActive ? 1 : 0, 0);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+ }
+
+ if (useHapticFeedback) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
+
+ if (isWakeKey) {
+ mPowerManager.wakeUp(event.getEventTime());
}
return result;
}
@@ -4122,15 +4557,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- int result = 0;
-
- final boolean isWakeMotion = (policyFlags
- & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
- if (isWakeMotion) {
- result |= ACTION_WAKE_UP;
+ public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
+ if ((policyFlags & FLAG_WAKE) != 0) {
+ mPowerManager.wakeUp(whenNanos / 1000000);
+ return 0;
}
- return result;
+ if (shouldDispatchInputWhenNonInteractive()) {
+ return ACTION_PASS_TO_USER;
+ }
+ return 0;
+ }
+
+ private boolean shouldDispatchInputWhenNonInteractive() {
+ return keyguardIsShowingTq() && mDisplay != null &&
+ mDisplay.getState() != Display.STATE_OFF;
}
void dispatchMediaKeyWithWakeLock(KeyEvent event) {
@@ -4178,17 +4618,18 @@ 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);
}
}
+ void launchVoiceAssistWithWakeLock(boolean keyguardActive) {
+ Intent voiceIntent =
+ new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, keyguardActive);
+ mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT_OR_SELF);
+ mBroadcastWakeLock.release();
+ }
+
BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -4246,8 +4687,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) {
@@ -4264,110 +4716,187 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ // Called on the PowerManager's Notifier thread.
@Override
- public void screenTurnedOff(int why) {
+ public void goingToSleep(int why) {
EventLog.writeEvent(70000, 0);
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Going to sleep...");
+
+ // We must get this work done here because the power manager will drop
+ // the wake lock and let the system suspend once this function returns.
synchronized (mLock) {
- mScreenOnEarly = false;
- mScreenOnFully = false;
+ mAwake = false;
+ mKeyguardDrawComplete = false;
+ updateWakeGestureListenerLp();
+ updateOrientationListenerLp();
+ updateLockScreenTimeout();
}
+
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurnedOff(why);
}
- synchronized (mLock) {
- updateOrientationListenerLp();
- updateLockScreenTimeout();
- }
}
+ // Called on the PowerManager's Notifier thread.
@Override
- public void screenTurningOn(final ScreenOnListener screenOnListener) {
+ public void wakingUp() {
EventLog.writeEvent(70000, 1);
- if (false) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.i(TAG, "Screen turning on...", here);
- }
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Waking up...");
+ // Since goToSleep performs these functions synchronously, we must
+ // do the same here. We cannot post this work to a handler because
+ // that might cause it to become reordered with respect to what
+ // may happen in a future call to goToSleep.
synchronized (mLock) {
- mScreenOnEarly = true;
+ mAwake = true;
+ mKeyguardDrawComplete = false;
+ if (mKeyguardDelegate != null) {
+ mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_KEYGUARD_DRAWN_TIMEOUT, 1000);
+ }
+
+ updateWakeGestureListenerLp();
updateOrientationListenerLp();
updateLockScreenTimeout();
}
- waitForKeyguard(screenOnListener);
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.onScreenTurnedOn(mKeyguardDelegateCallback);
+ // ... eventually calls finishKeyguardDrawn
+ } else {
+ if (DEBUG_WAKEUP) Slog.d(TAG, "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
+ finishKeyguardDrawn();
+ }
}
- private void waitForKeyguard(final ScreenOnListener screenOnListener) {
- if (mKeyguardDelegate != null) {
- if (screenOnListener != null) {
- mKeyguardDelegate.onScreenTurnedOn(new KeyguardServiceDelegate.ShowListener() {
- @Override
- public void onShown(IBinder windowToken) {
- waitForKeyguardWindowDrawn(windowToken, screenOnListener);
- }
- });
- return;
- } else {
- mKeyguardDelegate.onScreenTurnedOn(null);
+ private void finishKeyguardDrawn() {
+ synchronized (mLock) {
+ if (!mAwake || mKeyguardDrawComplete) {
+ return; // spurious
+ }
+
+ mKeyguardDrawComplete = true;
+ if (mKeyguardDelegate != null) {
+ mHandler.removeMessages(MSG_KEYGUARD_DRAWN_TIMEOUT);
}
- } else {
- Slog.i(TAG, "No keyguard interface!");
}
- finishScreenTurningOn(screenOnListener);
+
+ finishScreenTurningOn();
}
- private void waitForKeyguardWindowDrawn(IBinder windowToken,
- final ScreenOnListener screenOnListener) {
- if (windowToken != null && !mHideLockScreen) {
- try {
- if (mWindowManager.waitForWindowDrawn(
- windowToken, new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- Slog.i(TAG, "Lock screen displayed!");
- finishScreenTurningOn(screenOnListener);
- }
- })) {
- return;
- }
- Slog.i(TAG, "No lock screen! waitForWindowDrawn false");
+ // Called on the DisplayManager's DisplayPowerController thread.
+ @Override
+ public void screenTurnedOff() {
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turned off...");
- } catch (RemoteException ex) {
- // Can't happen in system process.
+ synchronized (mLock) {
+ mScreenOnEarly = false;
+ mScreenOnFully = false;
+ mWindowManagerDrawComplete = false;
+ mScreenOnListener = null;
+ updateOrientationListenerLp();
+ }
+ }
+
+ // Called on the DisplayManager's DisplayPowerController thread.
+ @Override
+ public void screenTurningOn(final ScreenOnListener screenOnListener) {
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Screen turning on...");
+
+ synchronized (mLock) {
+ mScreenOnEarly = true;
+ mScreenOnFully = false;
+ mWindowManagerDrawComplete = false;
+ mScreenOnListener = screenOnListener;
+ updateOrientationListenerLp();
+ }
+
+ mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
+ WAITING_FOR_DRAWN_TIMEOUT);
+ // ... eventually calls finishWindowsDrawn
+ }
+
+ private void finishWindowsDrawn() {
+ synchronized (mLock) {
+ if (!mScreenOnEarly || mWindowManagerDrawComplete) {
+ return; // spurious
}
+
+ mWindowManagerDrawComplete = true;
}
- Slog.i(TAG, "No lock screen! windowToken=" + windowToken);
- finishScreenTurningOn(screenOnListener);
+ finishScreenTurningOn();
}
- private void finishScreenTurningOn(ScreenOnListener screenOnListener) {
+ private void finishScreenTurningOn() {
+ final ScreenOnListener listener;
+ final boolean enableScreen;
synchronized (mLock) {
+ if (DEBUG_WAKEUP) Slog.d(TAG,
+ "finishScreenTurningOn: mAwake=" + mAwake
+ + ", mScreenOnEarly=" + mScreenOnEarly
+ + ", mScreenOnFully=" + mScreenOnFully
+ + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+ + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
+
+ if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
+ || (mAwake && !mKeyguardDrawComplete)) {
+ return; // spurious or not ready yet
+ }
+
+ if (DEBUG_WAKEUP) Slog.i(TAG, "Finished screen turning on...");
+ listener = mScreenOnListener;
+ mScreenOnListener = null;
mScreenOnFully = true;
+
+ // Remember the first time we draw the keyguard so we know when we're done with
+ // the main part of booting and can enable the screen and hide boot messages.
+ if (!mKeyguardDrawnOnce && mAwake) {
+ mKeyguardDrawnOnce = true;
+ enableScreen = true;
+ if (mBootMessageNeedsHiding) {
+ mBootMessageNeedsHiding = false;
+ hideBootMessages();
+ }
+ } else {
+ enableScreen = false;
+ }
}
- try {
- mWindowManager.setEventDispatching(true);
- } catch (RemoteException unhandled) {
+ if (listener != null) {
+ listener.onScreenOn();
}
- if (screenOnListener != null) {
- screenOnListener.onScreenOn();
+ if (enableScreen) {
+ try {
+ mWindowManager.enableScreenIfNeeded();
+ } catch (RemoteException unhandled) {
+ }
}
}
- @Override
- public boolean isScreenOnEarly() {
- return mScreenOnEarly;
+ private void handleHideBootMessage() {
+ synchronized (mLock) {
+ if (!mKeyguardDrawnOnce) {
+ mBootMessageNeedsHiding = true;
+ return; // keyguard hasn't drawn the first time yet, not done booting
+ }
+ }
+
+ if (mBootMsgDialog != null) {
+ if (DEBUG_WAKEUP) Slog.d(TAG, "handleHideBootMessage: dismissing");
+ mBootMsgDialog.dismiss();
+ mBootMsgDialog = null;
+ }
}
@Override
- public boolean isScreenOnFully() {
+ public boolean isScreenOn() {
return mScreenOnFully;
}
/** {@inheritDoc} */
+ @Override
public void enableKeyguard(boolean enabled) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.setKeyguardEnabled(enabled);
@@ -4375,6 +4904,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.verifyUnlock(callback);
@@ -4383,43 +4913,73 @@ 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?
- mKeyguardDelegate.keyguardDone(false, true);
- } else {
- // ask the keyguard to prompt the user to authenticate if necessary
- mKeyguardDelegate.dismiss();
- }
+ // ask the keyguard to prompt the user to authenticate if necessary
+ mKeyguardDelegate.dismiss();
+ }
+ });
+ }
+ }
+
+ public void notifyActivityDrawnForKeyguardLw() {
+ if (mKeyguardDelegate != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mKeyguardDelegate.onActivityDrawn();
}
});
}
}
+ @Override
+ public boolean isKeyguardDrawnLw() {
+ synchronized (mLock) {
+ return mKeyguardDrawnOnce;
+ }
+ }
+
+ @Override
+ public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration);
+ }
+ }
+
void sendCloseSystemWindows() {
sendCloseSystemWindows(mContext, null);
}
@@ -4492,6 +5052,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
// Application just wants to remain locked in the last rotation.
preferredRotation = lastRotation;
+ } else if (!mSupportAutoRotation) {
+ // If we don't support auto-rotation then bail out here and ignore
+ // the sensor and any rotation lock settings.
+ preferredRotation = -1;
} else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
@@ -4625,6 +5189,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 ?
@@ -4633,6 +5198,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();
@@ -4654,6 +5220,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ @Override
public void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
performHapticFeedbackLw(null, safeMode
@@ -4676,10 +5243,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
public void systemReady() {
- if (!mHeadless) {
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
- mKeyguardDelegate.onSystemReady();
- }
+ mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+ mKeyguardDelegate.onSystemReady();
+
+ readCameraLensCoverState();
+ updateUiMode();
synchronized (mLock) {
updateOrientationListenerLp();
mSystemReady = true;
@@ -4693,24 +5261,39 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void systemBooted() {
if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
synchronized (mLock) {
mSystemBooted = true;
}
+ wakingUp();
+ screenTurningOn(null);
}
ProgressDialog mBootMsgDialog = null;
/** {@inheritDoc} */
+ @Override
public void showBootMessage(final CharSequence msg, final boolean always) {
- if (mHeadless) return;
mHandler.post(new Runnable() {
@Override public void run() {
if (mBootMsgDialog == null) {
- mBootMsgDialog = new ProgressDialog(mContext) {
+ 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
// it, to avoid it trying to do things too early in boot.
@Override public boolean dispatchKeyEvent(KeyEvent event) {
@@ -4754,18 +5337,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
+ @Override
public void hideBootMessages() {
- mHandler.post(new Runnable() {
- @Override public void run() {
- if (mBootMsgDialog != null) {
- mBootMsgDialog.dismiss();
- mBootMsgDialog = null;
- }
- }
- });
+ mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE);
}
/** {@inheritDoc} */
+ @Override
public void userActivity() {
// ***************************************
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
@@ -4809,6 +5387,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);
@@ -4822,7 +5401,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
- boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly &&
+ boolean enable = (mAllowLockscreenWhenOn && mAwake &&
mKeyguardDelegate != null && mKeyguardDelegate.isSecure());
if (mLockScreenTimerActive != enable) {
if (enable) {
@@ -4847,7 +5426,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private void applyLidSwitchState() {
if (mLidState == LID_CLOSED && mLidControlsSleep) {
- mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ mPowerManager.goToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ }
+
+ synchronized (mLock) {
+ updateWakeGestureListenerLp();
+ }
+ }
+
+ void updateUiMode() {
+ if (mUiModeManager == null) {
+ mUiModeManager = IUiModeManager.Stub.asInterface(
+ ServiceManager.getService(Context.UI_MODE_SERVICE));
+ }
+ try {
+ mUiMode = mUiModeManager.getCurrentModeType();
+ } catch (RemoteException e) {
}
}
@@ -4896,6 +5492,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (ENABLE_DESK_DOCK_HOME_CAPTURE) {
intent = mDeskDockIntent;
}
+ } else if (mUiMode == Configuration.UI_MODE_TYPE_WATCH
+ && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK
+ || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK)) {
+ // Always launch dock home from home when watch is docked, if it exists.
+ intent = mDeskDockIntent;
}
if (intent == null) {
@@ -4966,7 +5568,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
- null, null, null, UserHandle.USER_CURRENT);
+ null, null, UserHandle.USER_CURRENT);
if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
}
@@ -4977,7 +5579,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
- null, null, null, UserHandle.USER_CURRENT);
+ null, null, UserHandle.USER_CURRENT);
if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
}
@@ -5025,7 +5627,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 (hapticsDisabled && !always) {
return false;
}
long[] pattern = null;
@@ -5039,6 +5641,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;
@@ -5059,10 +5667,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], VIBRATION_ATTRIBUTES);
} else {
// Pattern vibration
- mVibrator.vibrate(owningUid, owningPackage, pattern, -1);
+ mVibrator.vibrate(owningUid, owningPackage, pattern, -1, VIBRATION_ATTRIBUTES);
}
return true;
}
@@ -5073,8 +5681,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);
}
}
@@ -5086,7 +5693,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
@@ -5096,11 +5703,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;
@@ -5132,26 +5739,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);
+ if (!areTranslucentBarsAllowed() && transWin != mStatusBar) {
+ vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
+ | View.SYSTEM_UI_TRANSPARENT);
}
// update status bar
@@ -5159,7 +5768,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;
@@ -5192,7 +5801,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);
@@ -5223,7 +5833,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
@@ -5240,6 +5851,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
@Override
+ public int getInputMethodWindowVisibleHeightLw() {
+ return mDockBottom - mCurBottom;
+ }
+
+ @Override
public void setCurrentUserLw(int newUserId) {
mCurrentUserId = newUserId;
if (mKeyguardDelegate != null) {
@@ -5269,11 +5885,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) {
@@ -5289,6 +5900,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(" mSystemBooted="); pw.println(mSystemBooted);
pw.print(prefix); pw.print("mLidState="); pw.print(mLidState);
pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation);
+ pw.print(" mCameraLensCoverState="); pw.print(mCameraLensCoverState);
pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged);
if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
|| mForceClearedSystemUiFlags != 0) {
@@ -5303,6 +5915,10 @@ 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);
pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
@@ -5319,12 +5935,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
pw.print(mLidKeyboardAccessibility);
pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
pw.print(" mLidControlsSleep="); pw.println(mLidControlsSleep);
- pw.print(prefix); pw.print("mLongPressOnPowerBehavior=");
- pw.print(mLongPressOnPowerBehavior);
- pw.print(" mHasSoftInput="); pw.println(mHasSoftInput);
+ pw.print(prefix);
+ pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
+ pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
+ pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput);
+ pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
- pw.print(" mScreenOnFully="); pw.print(mScreenOnFully);
- pw.print(" mOrientationSensorEnabled="); pw.println(mOrientationSensorEnabled);
+ pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
+ pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
+ pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
+ pw.print(prefix); pw.print("mOrientationSensorEnabled=");
+ pw.println(mOrientationSensorEnabled);
pw.print(prefix); pw.print("mOverscanScreen=("); pw.print(mOverscanScreenLeft);
pw.print(","); pw.print(mOverscanScreenTop);
pw.print(") "); pw.print(mOverscanScreenWidth);
@@ -5369,6 +5990,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);
@@ -5389,15 +6014,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);
@@ -5440,7 +6063,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..9abd906
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -0,0 +1,258 @@
+/*
+ * 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.app.ActivityManager;
+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))
+ || ActivityManager.isRunningInTestHarness();
+ }
+
+ 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 d927592..2f60d55 100644
--- a/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
+++ b/policy/src/com/android/internal/policy/impl/WindowOrientationListener.java
@@ -25,6 +25,9 @@ import android.os.Handler;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
/**
* A special helper class used by the WindowManager
@@ -180,6 +183,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,
@@ -341,6 +359,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
@@ -363,12 +389,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;
@@ -380,6 +412,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) {
}
@@ -477,7 +522,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);
@@ -525,6 +581,9 @@ public abstract class WindowOrientationListener {
}
}
}
+ mFlat = isFlat;
+ mSwinging = isSwinging;
+ mAccelerating = isAccelerating;
// Determine new proposed rotation.
oldProposedRotation = mProposedRotation;
@@ -542,6 +601,7 @@ public abstract class WindowOrientationListener {
+ ", isAccelerating=" + isAccelerating
+ ", isFlat=" + isFlat
+ ", isSwinging=" + isSwinging
+ + ", isOverhead=" + mOverhead
+ ", timeUntilSettledMS=" + remainingMS(now,
mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS)
+ ", timeUntilAccelerationDelayExpiredMS=" + remainingMS(now,
@@ -659,8 +719,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();
}
@@ -725,6 +789,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 1357462..50fe7c7 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;
@@ -103,12 +102,18 @@ public class KeyguardServiceDelegate {
};
public KeyguardServiceDelegate(Context context, LockPatternUtils lockPatternUtils) {
+ mScrim = createScrim(context);
+ }
+
+ public void bindService(Context context) {
Intent intent = new Intent();
intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
- mScrim = createScrim(context);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+ mKeyguardState.showing = false;
+ mKeyguardState.showingAndNotOccluded = false;
+ mKeyguardState.secure = false;
} else {
if (DEBUG) Log.v(TAG, "*** Keyguard started");
}
@@ -146,11 +151,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() {
@@ -172,11 +177,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() {
@@ -246,7 +253,6 @@ public class KeyguardServiceDelegate {
if (mKeyguardService != null) {
mKeyguardService.onSystemReady();
} else {
- if (DEBUG) Log.v(TAG, "onSystemReady() called before keyguard service was ready");
mKeyguardState.systemIsReady = true;
}
}
@@ -270,6 +276,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);
@@ -285,6 +297,7 @@ public class KeyguardServiceDelegate {
stretch, stretch, type, flags, PixelFormat.TRANSLUCENT);
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+ lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED;
lp.setTitle("KeyguardScrim");
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.addView(view, lp);
@@ -324,4 +337,9 @@ public class KeyguardServiceDelegate {
mKeyguardState.bootCompleted = true;
}
+ public void onActivityDrawn() {
+ if (mKeyguardService != null) {
+ mKeyguardService.onActivityDrawn();
+ }
+ }
}
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..2778b15 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,22 @@ 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 onActivityDrawn() {
+ try {
+ mService.onActivityDrawn();
+ } catch (RemoteException e) {
+ Slog.w(TAG , "Remote Exception", e);
+ }
+ }
+
public void showAssistant() {
// Not used by PhoneWindowManager
}