diff options
74 files changed, 900 insertions, 359 deletions
diff --git a/api/current.txt b/api/current.txt index 758851c79abe..f963c1713a79 100644 --- a/api/current.txt +++ b/api/current.txt @@ -414,6 +414,7 @@ package android { field public static final int contentInsetRight = 16843862; // 0x1010456 field public static final int contentInsetStart = 16843859; // 0x1010453 field public static final int contextClickable = 16844007; // 0x10104e7 + field public static final int contextPopupMenuStyle = 16844032; // 0x1010500 field public static final int controlX1 = 16843772; // 0x10103fc field public static final int controlX2 = 16843774; // 0x10103fe field public static final int controlY1 = 16843773; // 0x10103fd @@ -1220,6 +1221,7 @@ package android { field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f field public static final int textAppearanceMedium = 16842817; // 0x1010041 field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044 + field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501 field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0 field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1 field public static final int textAppearanceSmall = 16842818; // 0x1010042 @@ -36541,6 +36543,7 @@ package android.view { method public void setY(float); method public void setZ(float); method public boolean showContextMenu(); + method public boolean showContextMenu(float, float); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); @@ -37007,6 +37010,7 @@ package android.view { method public void setTransitionGroup(boolean); method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); + method public boolean showContextMenuForChild(android.view.View, float, float); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); @@ -37128,6 +37132,7 @@ package android.view { method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); + method public abstract boolean showContextMenuForChild(android.view.View, float, float); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } @@ -45349,10 +45354,7 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { - method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -45362,7 +45364,6 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); - method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -45436,10 +45437,7 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { - method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -45453,7 +45451,6 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; - method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/api/system-current.txt b/api/system-current.txt index 256824010308..d95c0ff8c145 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -506,6 +506,7 @@ package android { field public static final int contentInsetRight = 16843862; // 0x1010456 field public static final int contentInsetStart = 16843859; // 0x1010453 field public static final int contextClickable = 16844007; // 0x10104e7 + field public static final int contextPopupMenuStyle = 16844032; // 0x1010500 field public static final int controlX1 = 16843772; // 0x10103fc field public static final int controlX2 = 16843774; // 0x10103fe field public static final int controlY1 = 16843773; // 0x10103fd @@ -1316,6 +1317,7 @@ package android { field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f field public static final int textAppearanceMedium = 16842817; // 0x1010041 field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044 + field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501 field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0 field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1 field public static final int textAppearanceSmall = 16842818; // 0x1010042 @@ -38835,6 +38837,7 @@ package android.view { method public void setY(float); method public void setZ(float); method public boolean showContextMenu(); + method public boolean showContextMenu(float, float); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback); method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int); method public void startAnimation(android.view.animation.Animation); @@ -39301,6 +39304,7 @@ package android.view { method public void setTransitionGroup(boolean); method public boolean shouldDelayChildPressedState(); method public boolean showContextMenuForChild(android.view.View); + method public boolean showContextMenuForChild(android.view.View, float, float); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); method public void startLayoutAnimation(); @@ -39422,6 +39426,7 @@ package android.view { method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public abstract void requestTransparentRegion(android.view.View); method public abstract boolean showContextMenuForChild(android.view.View); + method public abstract boolean showContextMenuForChild(android.view.View, float, float); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback); method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int); } @@ -47957,10 +47962,7 @@ package java.lang.reflect { } public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { - method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<T> getDeclaringClass(); method public java.lang.Class<?>[] getExceptionTypes(); method public java.lang.reflect.Type[] getGenericExceptionTypes(); @@ -47970,7 +47972,6 @@ package java.lang.reflect { method public java.lang.annotation.Annotation[][] getParameterAnnotations(); method public java.lang.Class<?>[] getParameterTypes(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters(); - method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isSynthetic(); method public boolean isVarArgs(); method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException; @@ -48044,10 +48045,7 @@ package java.lang.reflect { } public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member { - method public boolean equals(java.lang.Object); method public A getAnnotation(java.lang.Class<A>); - method public java.lang.annotation.Annotation[] getAnnotations(); - method public java.lang.annotation.Annotation[] getDeclaredAnnotations(); method public java.lang.Class<?> getDeclaringClass(); method public java.lang.Object getDefaultValue(); method public java.lang.Class<?>[] getExceptionTypes(); @@ -48061,7 +48059,6 @@ package java.lang.reflect { method public java.lang.Class<?> getReturnType(); method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters(); method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException; - method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>); method public boolean isBridge(); method public boolean isSynthetic(); method public boolean isVarArgs(); diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 31d1ab7b92ac..5e8ad68957b2 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -90,6 +90,9 @@ public class StatusBarManager { public static final int WINDOW_STATE_HIDING = 1; public static final int WINDOW_STATE_HIDDEN = 2; + public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0; + public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1; + private Context mContext; private IStatusBarService mService; private IBinder mToken = new Binder(); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2a1d757feb7b..263ec7d18f08 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5388,7 +5388,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected boolean performButtonActionOnTouchDown(MotionEvent event) { if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE && (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { - showContextMenu(event.getX(), event.getY(), event.getMetaState()); + showContextMenu(event.getX(), event.getY()); mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; return true; } @@ -5409,13 +5409,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param x The referenced x coordinate. * @param y The referenced y coordinate. - * @param metaState The keyboard modifiers that were pressed. * @return Whether a context menu was displayed. - * - * @hide */ - public boolean showContextMenu(float x, float y, int metaState) { - return showContextMenu(); + public boolean showContextMenu(float x, float y) { + return getParent().showContextMenuForChild(this, x, y); } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index bdcd998de7c7..475ce2feed50 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -767,6 +767,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return mParent != null && mParent.showContextMenuForChild(originalView); } + @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return mParent != null && mParent.showContextMenuForChild(originalView, x, y); + } + /** * {@inheritDoc} */ diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 15b86d1245b2..07f1e2cbdb4f 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -182,6 +182,17 @@ public interface ViewParent { public boolean showContextMenuForChild(View originalView); /** + * Bring up a context menu for the specified view at the given x/y offset from + * the top left corner. + * + * @param originalView + * @param x The x offset at which to open the menu + * @param y The y offset at which to open the menu + * @return true if a context menu was displayed + */ + public boolean showContextMenuForChild(View originalView, float x, float y); + + /** * Have the parent populate the specified context menu if it has anything to * add (and then recurse on its parent). * diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8403c46e85bc..f6c60ed688a5 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6240,6 +6240,11 @@ public final class ViewRootImpl implements ViewParent, } @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return false; + } + + @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { return null; } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 5724f526918b..b8faf0c6cf98 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3080,6 +3080,15 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private class CheckForLongPress extends WindowRunnnable implements Runnable { + private static final int INVALID_COORD = -1; + private float mX = INVALID_COORD; + private float mY = INVALID_COORD; + + private void setCoords(float x, float y) { + mX = x; + mY = y; + } + @Override public void run() { final int motionPosition = mMotionPosition; @@ -3090,7 +3099,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te boolean handled = false; if (sameWindow() && !mDataChanged) { - handled = performLongPress(child, longPressPosition, longPressId); + if (mX != INVALID_COORD && mY != INVALID_COORD) { + handled = performLongPress(child, longPressPosition, longPressId, mX, mY); + } else { + handled = performLongPress(child, longPressPosition, longPressId); + } } if (handled) { mTouchMode = TOUCH_MODE_REST; @@ -3146,6 +3159,16 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te boolean performLongPress(final View child, final int longPressPosition, final long longPressId) { + return performLongPress( + child, + longPressPosition, + longPressId, + CheckForLongPress.INVALID_COORD, + CheckForLongPress.INVALID_COORD); + } + + boolean performLongPress(final View child, + final int longPressPosition, final long longPressId, float x, float y) { // CHOICE_MODE_MULTIPLE_MODAL takes over long press. if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) { if (mChoiceActionMode == null && @@ -3163,7 +3186,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (!handled) { mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId); - handled = super.showContextMenuForChild(AbsListView.this); + if (x != CheckForLongPress.INVALID_COORD && y != CheckForLongPress.INVALID_COORD) { + handled = super.showContextMenuForChild(AbsListView.this, x, y); + } else { + handled = super.showContextMenuForChild(AbsListView.this); + } } if (handled) { performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); @@ -3178,17 +3205,17 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te /** @hide */ @Override - public boolean showContextMenu(float x, float y, int metaState) { + public boolean showContextMenu(float x, float y) { final int position = pointToPosition((int)x, (int)y); if (position != INVALID_POSITION) { final long id = mAdapter.getItemId(position); View child = getChildAt(position - mFirstPosition); if (child != null) { mContextMenuInfo = createContextMenuInfo(child, position, id); - return super.showContextMenuForChild(AbsListView.this); + return super.showContextMenuForChild(AbsListView.this, x, y); } } - return super.showContextMenu(x, y, metaState); + return super.showContextMenu(x, y); } @Override @@ -3341,6 +3368,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mPendingCheckForLongPress == null) { mPendingCheckForLongPress = new CheckForLongPress(); } + mPendingCheckForLongPress.setCoords(x, y); mPendingCheckForLongPress.rememberWindowAttachCount(); postDelayed(mPendingCheckForLongPress, longPressTimeout); } else { diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java index eac3a0b51758..1fb62d0fa6c9 100644 --- a/core/java/android/widget/MenuPopupWindow.java +++ b/core/java/android/widget/MenuPopupWindow.java @@ -152,8 +152,16 @@ public class MenuPopupWindow extends ListPopupWindow implements MenuItemHoverLis boolean superVal = super.onHoverEvent(ev); if (dispatchHover && mHoverListener != null) { - mHoverListener.onItemHovered( - ((MenuAdapter) getAdapter()).getAdapterMenu(), position); + ListAdapter adapter = getAdapter(); + MenuAdapter menuAdapter; + if (adapter instanceof HeaderViewListAdapter) { + menuAdapter = (MenuAdapter) ((HeaderViewListAdapter) adapter) + .getWrappedAdapter(); + } else { + menuAdapter = (MenuAdapter) adapter; + } + + mHoverListener.onItemHovered(menuAdapter.getAdapterMenu(), position); } return superVal; diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index f9fa0272f147..864a0fe72fa1 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1449,11 +1449,13 @@ public class PopupWindow { anchor.getLocationOnScreen(mScreenLocation); onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) < (mScreenLocation[1] - yoff - displayFrame.top); - if (onTop) { - p.gravity = Gravity.LEFT | Gravity.BOTTOM; - p.y = root.getHeight() - mDrawingLocation[1] + yoff; - } else { - p.y = mDrawingLocation[1] + anchorHeight + yoff; + if (!mOverlapAnchor) { + if (onTop) { + p.gravity = Gravity.LEFT | Gravity.BOTTOM; + p.y = root.getHeight() - mDrawingLocation[1] + yoff; + } else { + p.y = mDrawingLocation[1] + anchorHeight + yoff; + } } } @@ -1469,13 +1471,21 @@ public class PopupWindow { p.width = Math.min(p.width, displayFrameWidth); } - if (onTop) { - final int popupTop = mScreenLocation[1] + yoff - mPopupHeight; - if (popupTop < 0) { - p.y += popupTop; + if (mOverlapAnchor) { + final int displayFrameHeight = displayFrame.bottom - displayFrame.top; + final int bottom = p.y + p.height; + if (bottom > displayFrame.bottom) { + p.y -= bottom - displayFrameHeight; } } else { - p.y = Math.max(p.y, displayFrame.top); + if (onTop) { + final int popupTop = mScreenLocation[1] + yoff - mPopupHeight; + if (popupTop < 0) { + p.y += popupTop; + } + } else { + p.y = Math.max(p.y, displayFrame.top); + } } } @@ -1542,7 +1552,13 @@ public class PopupWindow { Resources res = anchor.getContext().getResources(); bottomEdge = res.getDisplayMetrics().heightPixels; } - final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; + + final int distanceToBottom; + if (mOverlapAnchor) { + distanceToBottom = bottomEdge - anchorPos[1] - yOffset; + } else { + distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; + } final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset; // anchorPos[1] is distance from anchor to top of screen diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7ca333947918..ca1b211bc291 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.graphics.Rect; @@ -55,6 +56,8 @@ import android.view.ViewGroup; import android.widget.AdapterView.OnItemClickListener; import libcore.util.Objects; +import com.android.internal.R; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -206,14 +209,22 @@ public class RemoteViews implements Parcelable, Filter { /** @hide */ public static class OnClickHandler { + + private int mEnterAnimationId; + public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { try { // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? Context context = view.getContext(); - ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view, - 0, 0, - view.getMeasuredWidth(), view.getMeasuredHeight()); + ActivityOptions opts; + if (mEnterAnimationId != 0) { + opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0); + } else { + opts = ActivityOptions.makeScaleUpAnimation(view, + 0, 0, + view.getMeasuredWidth(), view.getMeasuredHeight()); + } context.startIntentSender( pendingIntent.getIntentSender(), fillInIntent, Intent.FLAG_ACTIVITY_NEW_TASK, @@ -228,6 +239,10 @@ public class RemoteViews implements Parcelable, Filter { } return true; } + + public void setEnterAnimationId(int enterAnimationId) { + mEnterAnimationId = enterAnimationId; + } } /** @@ -2761,11 +2776,31 @@ public class RemoteViews implements Parcelable, Filter { inflater.setFilter(this); result = inflater.inflate(rvToApply.getLayoutId(), parent, false); + loadTransitionOverride(context, handler); + rvToApply.performApply(result, parent, handler); return result; } + private static void loadTransitionOverride(Context context, + RemoteViews.OnClickHandler handler) { + if (handler != null && context.getResources().getBoolean( + com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) { + TypedArray windowStyle = context.getTheme().obtainStyledAttributes( + com.android.internal.R.styleable.Window); + int windowAnimations = windowStyle.getResourceId( + com.android.internal.R.styleable.Window_windowAnimationStyle, 0); + TypedArray windowAnimationStyle = context.obtainStyledAttributes( + windowAnimations, com.android.internal.R.styleable.WindowAnimation); + handler.setEnterAnimationId(windowAnimationStyle.getResourceId( + com.android.internal.R.styleable. + WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0)); + windowStyle.recycle(); + windowAnimationStyle.recycle(); + } + } + /** * Applies all of the actions to the provided view. * diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 3353d1669c9f..2e4d9b50b7be 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -71,6 +71,7 @@ import com.android.internal.view.menu.IconMenuPresenter; import com.android.internal.view.menu.ListMenuPresenter; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.widget.ActionBarContextView; @@ -274,6 +275,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ContextMenuBuilder mContextMenu; private MenuDialogHelper mContextMenuHelper; + private MenuPopupHelper mContextMenuPopupHelper; private boolean mClosingActionMenu; private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE; @@ -1123,6 +1125,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mContextMenuHelper.dismiss(); mContextMenuHelper = null; } + if (mContextMenuPopupHelper != null) { + mContextMenuPopupHelper.dismiss(); + mContextMenuPopupHelper = null; + } } @Override @@ -2846,6 +2852,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + // Reuse the context menu builder + if (mContextMenu == null) { + mContextMenu = new ContextMenuBuilder(getContext()); + mContextMenu.setCallback(mContextMenuCallback); + } else { + mContextMenu.clearAll(); + } + + final MenuPopupHelper helper = mContextMenu.showPopup( + getContext(), originalView, x, y); + if (helper != null) { + helper.setCallback(mContextMenuCallback); + } else if (mContextMenuPopupHelper != null) { + // No menu to show, but if we have a menu currently showing it just became blank. + // Close it. + mContextMenuPopupHelper.dismiss(); + } + mContextMenuPopupHelper = helper; + return helper != null; + } + + @Override public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) { return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY); diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index ab3ec985d688..11ef18b4d5c0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -74,7 +74,9 @@ oneway interface IStatusBar /** * Notifies the status bar that a camera launch gesture has been detected. + * + * @param source the identifier for the gesture, see {@link StatusBarManager} */ - void onCameraLaunchGestureDetected(); + void onCameraLaunchGestureDetected(int source); } diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java index aa7b34bb9999..293e2ade7229 100644 --- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java +++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java @@ -20,14 +20,16 @@ import android.view.ViewTreeObserver; import android.view.View.OnAttachStateChangeListener; import android.view.View.OnKeyListener; import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.AdapterView; import android.widget.DropDownListView; +import android.widget.FrameLayout; import android.widget.MenuItemHoverListener; +import android.widget.ListAdapter; import android.widget.ListView; import android.widget.MenuPopupWindow; import android.widget.MenuPopupWindow.MenuDropDownListView; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; +import android.widget.TextView; import com.android.internal.util.Preconditions; @@ -36,8 +38,8 @@ import com.android.internal.util.Preconditions; * side. * @hide */ -final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener, - MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener { +final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener, + PopupWindow.OnDismissListener { @Retention(RetentionPolicy.SOURCE) @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT}) public @interface HorizPosition {} @@ -96,7 +98,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl int menuIndex = -1; for (int i = 0; i < mListViews.size(); i++) { final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(i); - final MenuAdapter adapter = (MenuAdapter) view.getAdapter(); + final MenuAdapter adapter = toMenuAdapter(view.getAdapter()); if (adapter.getAdapterMenu() == menu) { menuIndex = i; @@ -129,7 +131,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl int nextIndex = mListViews.indexOf(view) + 1; if (nextIndex < mListViews.size()) { MenuAdapter nextSubMenuAdapter = - (MenuAdapter) mListViews.get(nextIndex).getAdapter(); + toMenuAdapter(mListViews.get(nextIndex).getAdapter()); // Disable exit animation, to prevent overlapping fading out // submenus. mPopupWindows.get(nextIndex).setExitTransition(null); @@ -151,7 +153,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl final MenuDropDownListView nextView = (MenuDropDownListView) mListViews.get(menuIndex + 1); - final MenuAdapter nextAdapter = (MenuAdapter) nextView.getAdapter(); + final MenuAdapter nextAdapter = toMenuAdapter(nextView.getAdapter()); mSubMenuHoverHandler.removeCallbacksAndMessages(null); mSubMenuHoverHandler.postDelayed(new Runnable() { @@ -184,7 +186,10 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl private int mLastPosition; private List<Integer> mPositions; private List<int[]> mOffsets; + private int mInitXOffset; + private int mInitYOffset; private boolean mForceShowIcon; + private boolean mShowTitle; private Callback mPresenterCallback; private ViewTreeObserver mTreeObserver; private PopupWindow.OnDismissListener mOnDismissListener; @@ -248,7 +253,25 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl for (int i = 0; i < mPopupWindows.size(); i++) { MenuPopupWindow popupWindow = mPopupWindows.get(i); popupWindow.show(); - mListViews.add((DropDownListView) popupWindow.getListView()); + DropDownListView listView = (DropDownListView) popupWindow.getListView(); + mListViews.add(listView); + + MenuBuilder menu = toMenuAdapter(listView.getAdapter()).getAdapterMenu(); + if (i == 0 && mShowTitle && menu.getHeaderTitle() != null) { + FrameLayout titleItemView = + (FrameLayout) LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.popup_menu_header_item_layout, + listView, + false); + TextView titleView = (TextView) titleItemView.findViewById( + com.android.internal.R.id.title); + titleView.setText(menu.getHeaderTitle()); + titleItemView.setEnabled(false); + listView.addHeaderView(titleItemView, null, false); + + // Update to show the title. + popupWindow.show(); + } } mShownAnchorView = mAnchorView; @@ -275,12 +298,6 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - MenuAdapter adapter = (MenuAdapter) parent.getAdapter(); - adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); - } - - @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { dismiss(); @@ -381,6 +398,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl y = lastOffset[1] + lastListView.getSelectedView().getTop() - lastListView.getChildAt(0).getTop(); + } else { + x = mInitXOffset; + y = mInitYOffset; } popupWindow.setWidth(menuWidth); @@ -393,7 +413,8 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl // we deliberately do not yet show the popupWindow, as #show() will do that later. if (isShowing()) { popupWindow.show(); - mListViews.add((DropDownListView) popupWindow.getListView()); + DropDownListView listView = (DropDownListView) popupWindow.getListView(); + mListViews.add(listView); } int[] offsets = {x, y}; @@ -425,8 +446,9 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl if (dismissedIndex != -1) { for (int i = dismissedIndex; i < mListViews.size(); i++) { ListView view = mListViews.get(i); - MenuAdapter adapter = (MenuAdapter) view.getAdapter(); - adapter.mAdapterMenu.close(); + ListAdapter adapter = view.getAdapter(); + MenuAdapter menuAdapter = toMenuAdapter(adapter); + menuAdapter.mAdapterMenu.close(); } } } @@ -434,7 +456,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl @Override public void updateMenuView(boolean cleared) { for (ListView view : mListViews) { - ((MenuAdapter) view.getAdapter()).notifyDataSetChanged(); + toMenuAdapter(view.getAdapter()).notifyDataSetChanged(); } } @@ -447,7 +469,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl public boolean onSubMenuSelected(SubMenuBuilder subMenu) { // Don't allow double-opening of the same submenu. for (ListView view : mListViews) { - if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) { + if (toMenuAdapter(view.getAdapter()).mAdapterMenu.equals(subMenu)) { // Just re-focus that one. view.requestFocus(); return true; @@ -471,7 +493,7 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl for (int i = 0; i < mListViews.size(); i++) { ListView view = mListViews.get(i); - MenuAdapter adapter = (MenuAdapter) view.getAdapter(); + MenuAdapter adapter = toMenuAdapter(view.getAdapter()); if (menuIndex == -1 && menu == adapter.mAdapterMenu) { menuIndex = i; @@ -557,4 +579,18 @@ final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemCl return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null; } + @Override + public void setHorizontalOffset(int x) { + mInitXOffset = x; + } + + @Override + public void setVerticalOffset(int y) { + mInitYOffset = y; + } + + @Override + public void setShowTitle(boolean showTitle) { + mShowTitle = showTitle; + } }
\ No newline at end of file diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java index bf44d51b6dd9..aaa1bf16bf80 100644 --- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java +++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java @@ -17,6 +17,7 @@ package com.android.internal.view.menu; import android.content.Context; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.IBinder; import android.util.EventLog; @@ -93,4 +94,29 @@ public class ContextMenuBuilder extends MenuBuilder implements ContextMenu { return null; } + public MenuPopupHelper showPopup(Context context, View originalView, float x, float y) { + if (originalView != null) { + // Let relevant views and their populate context listeners populate + // the context menu + originalView.createContextMenu(this); + } + + if (getVisibleItems().size() > 0) { + EventLog.writeEvent(50001, 1); + + int location[] = new int[2]; + originalView.getLocationOnScreen(location); + + final MenuPopupHelper helper = new MenuPopupHelper( + context, + this, + originalView, + false /* overflowOnly */, + com.android.internal.R.attr.contextPopupMenuStyle); + helper.show(Math.round(x), Math.round(y)); + return helper; + } + + return null; + } } diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java index b43e8adbc8ac..98f5d9061e14 100644 --- a/core/java/com/android/internal/view/menu/MenuPopup.java +++ b/core/java/com/android/internal/view/menu/MenuPopup.java @@ -17,10 +17,13 @@ package com.android.internal.view.menu; import android.content.Context; +import android.view.MenuItem; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.FrameLayout; +import android.widget.HeaderViewListAdapter; import android.widget.ListAdapter; import android.widget.PopupWindow; @@ -30,7 +33,8 @@ import android.widget.PopupWindow; * * @hide */ -public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { +public abstract class MenuPopup implements ShowableListMenu, MenuPresenter, + AdapterView.OnItemClickListener { public abstract void setForceShowIcon(boolean forceShow); @@ -49,6 +53,18 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { public abstract void setAnchorView(View anchor); + public abstract void setHorizontalOffset(int x); + + public abstract void setVerticalOffset(int y); + + /** + * Set whether a title entry should be shown in the popup menu (if a title exists for the + * menu). + * + * @param showTitle + */ + public abstract void setShowTitle(boolean showTitle); + /** * Set a listener to receive a callback when the popup is dismissed. * @@ -81,6 +97,16 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { return 0; } + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + ListAdapter outerAdapter = (ListAdapter) parent.getAdapter(); + MenuAdapter wrappedAdapter = toMenuAdapter(outerAdapter); + + // Use the position from the outer adapter so that if a header view was added, we don't get + // an off-by-1 error in position. + wrappedAdapter.mAdapterMenu.performItemAction((MenuItem) outerAdapter.getItem(position), 0); + } + /** * Measures the width of the given menu view. * @@ -121,4 +147,19 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter { return maxWidth; } -}
\ No newline at end of file + + /** + * Converts the given ListAdapter originating from a menu, to a MenuAdapter, accounting for + * the possibility of the parameter adapter actually wrapping the MenuAdapter. (That could + * happen if a header view was added on the menu.) + * + * @param adapter + * @return + */ + protected static MenuAdapter toMenuAdapter(ListAdapter adapter) { + if (adapter instanceof HeaderViewListAdapter) { + return (MenuAdapter) ((HeaderViewListAdapter) adapter).getWrappedAdapter(); + } + return (MenuAdapter) adapter; + } +} diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index ea7998339f3b..e674eccd889d 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -39,7 +39,11 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { private MenuPopup mPopup; private int mDropDownGravity = Gravity.NO_GRAVITY; + private boolean mForceShowIcon; + private boolean mShowTitle; private Callback mPresenterCallback; + private int mInitXOffset; + private int mInitYOffset; public MenuPopupHelper(Context context, MenuBuilder menu) { this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0); @@ -81,6 +85,7 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { } public void setForceShowIcon(boolean forceShow) { + mForceShowIcon = forceShow; mPopup.setForceShowIcon(forceShow); } @@ -99,6 +104,12 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { } } + public void show(int x, int y) { + if (!tryShow(x, y)) { + throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); + } + } + public ShowableListMenu getPopup() { return mPopup; } @@ -118,10 +129,40 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { return false; } + mInitXOffset = 0; + mInitYOffset = 0; + mShowTitle = false; + + showPopup(); + return true; + } + + public boolean tryShow(int x, int y) { + if (isShowing()) { + return true; + } + + if (mAnchorView == null) { + return false; + } + + mInitXOffset = x; + mInitYOffset = y; + mShowTitle = true; + + showPopup(); + return true; + } + + private void showPopup() { mPopup = createMenuPopup(); mPopup.setAnchorView(mAnchorView); - mPopup.setGravity(mDropDownGravity); mPopup.setCallback(mPresenterCallback); + mPopup.setForceShowIcon(mForceShowIcon); + mPopup.setGravity(mDropDownGravity); + mPopup.setHorizontalOffset(mInitXOffset); + mPopup.setShowTitle(mShowTitle); + mPopup.setVerticalOffset(mInitYOffset); // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface, // we must set the listener to this outer Helper rather than to the inner MenuPopup. @@ -131,7 +172,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { mPopup.addMenu(mMenu); mPopup.show(); - return true; } public void dismiss() { @@ -149,7 +189,6 @@ public class MenuPopupHelper implements PopupWindow.OnDismissListener { return mPopup != null && mPopup.isShowing(); } - public void setCallback(MenuPresenter.Callback cb) { mPresenterCallback = cb; mPopup.setCallback(cb); diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java index 8877f3d96a39..caee0d2d9a74 100644 --- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java +++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java @@ -6,17 +6,17 @@ import android.os.Parcelable; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.View.OnAttachStateChangeListener; import android.view.View.OnKeyListener; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.ViewTreeObserver; -import android.widget.AdapterView; +import android.widget.FrameLayout; import android.widget.ListView; import android.widget.MenuPopupWindow; import android.widget.PopupWindow; +import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.PopupWindow.OnDismissListener; @@ -92,6 +92,10 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On private int mDropDownGravity = Gravity.NO_GRAVITY; + private int mXOffset; + private int mYOffset; + private boolean mShowTitle; + public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr, int popupStyleRes, boolean overflowOnly) { mContext = Preconditions.checkNotNull(context); @@ -158,8 +162,28 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On mPopup.setContentWidth(mContentWidth); mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + mPopup.setHorizontalOffset(mXOffset); + mPopup.setVerticalOffset(mYOffset); mPopup.show(); - mPopup.getListView().setOnKeyListener(this); + + ListView listView = mPopup.getListView(); + listView.setOnKeyListener(this); + + if (mShowTitle && mMenu.getHeaderTitle() != null) { + FrameLayout titleItemView = + (FrameLayout) LayoutInflater.from(mContext).inflate( + com.android.internal.R.layout.popup_menu_header_item_layout, + listView, + false); + TextView titleView = (TextView) titleItemView.findViewById( + com.android.internal.R.id.title); + titleView.setText(mMenu.getHeaderTitle()); + titleItemView.setEnabled(false); + listView.addHeaderView(titleItemView, null, false); + + // Update to show the title. + mPopup.show(); + } return true; } @@ -178,12 +202,6 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - MenuAdapter adapter = mAdapter; - adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); - } - - @Override public void addMenu(MenuBuilder menu) { // No-op: standard implementation has only one menu which is set in the constructor. } @@ -288,4 +306,20 @@ final class StandardMenuPopup extends MenuPopup implements OnDismissListener, On public ListView getListView() { return mPopup.getListView(); } -}
\ No newline at end of file + + + @Override + public void setHorizontalOffset(int x) { + mXOffset = x; + } + + @Override + public void setVerticalOffset(int y) { + mYOffset = y; + } + + @Override + public void setShowTitle(boolean showTitle) { + mShowTitle = showTitle; + } +} diff --git a/core/res/res/layout/popup_menu_header_item_layout.xml b/core/res/res/layout/popup_menu_header_item_layout.xml new file mode 100644 index 000000000000..5879f85fbd6c --- /dev/null +++ b/core/res/res/layout/popup_menu_header_item_layout.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="?attr/dropdownListPreferredItemHeight" + android:minWidth="196dip" + android:paddingStart="16dip" + android:paddingEnd="16dip"> + + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?attr/textAppearancePopupMenuHeader" + android:layout_gravity="center_vertical" + android:singleLine="true" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:textAlignment="viewStart" /> + +</FrameLayout> diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml index 41b05ea8757a..919519e5832a 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -54,4 +54,7 @@ <!-- Do not show the message saying USB is connected in charging mode. --> <bool name="config_usbChargingMessage">false</bool> + + <!-- Use a custom transition for RemoteViews. --> + <bool name="config_overrideRemoteViewsActivityTransition">true</bool> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index dc96df4e9d7c..a6eb68b73baa 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -162,6 +162,9 @@ <!-- Text color, typeface, size, and style for small text inside of a popup menu. --> <attr name="textAppearanceSmallPopupMenu" format="reference" /> + <!-- Text color, typeface, size, and style for header text inside of a popup menu. --> + <attr name="textAppearancePopupMenuHeader" format="reference" /> + <!-- The underline color and thickness for easy correct suggestion --> <attr name="textAppearanceEasyCorrectSuggestion" format="reference" /> @@ -729,6 +732,8 @@ i <attr name="listPopupWindowStyle" format="reference" /> <!-- Default PopupMenu style. --> <attr name="popupMenuStyle" format="reference" /> + <!-- Default context menu PopupMenu style. --> + <attr name="contextPopupMenuStyle" format="reference" /> <!-- Default StackView style. --> <attr name="stackViewStyle" format="reference" /> @@ -2150,6 +2155,13 @@ i (which is exiting the screen). The wallpaper remains static behind the animation. --> <attr name="wallpaperIntraCloseExitAnimation" format="reference" /> + + <!-- When opening a new activity from a RemoteViews, this is the + animation that is run on the next activity (which is entering the + screen). Requires config_overrideRemoteViewsActivityTransition to + be true. --> + <attr name="activityOpenRemoteViewsEnterAnimation" format="reference" /> + </declare-styleable> <!-- ============================= --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 9b1a613894d9..24d760fddbf8 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2214,6 +2214,10 @@ <bool name="config_defaultWindowFeatureOptionsPanel">true</bool> <bool name="config_defaultWindowFeatureContextMenu">true</bool> + <!-- If true, the transition for a RemoteViews is read from a resource instead of using the + default scale-up transition. --> + <bool name="config_overrideRemoteViewsActivityTransition">false</bool> + <!-- This config is used to check if the carrier requires converting destination number before sending out a SMS. Formats for this configuration as below: diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index 55bea9e38291..96a81d138457 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -72,6 +72,7 @@ <dimen name="text_size_title_material_toolbar">20dp</dimen> <dimen name="text_size_subtitle_material_toolbar">16dp</dimen> <dimen name="text_size_menu_material">16sp</dimen> + <dimen name="text_size_menu_header_material">14sp</dimen> <dimen name="text_size_body_2_material">14sp</dimen> <dimen name="text_size_body_1_material">14sp</dimen> <dimen name="text_size_caption_material">12sp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 89d9babbbc1e..f4d0b398561f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2674,6 +2674,8 @@ <public type="attr" name="buttonGravity" /> <public type="attr" name="collapseIcon" /> <public type="attr" name="level" /> + <public type="attr" name="contextPopupMenuStyle" /> + <public type="attr" name="textAppearancePopupMenuHeader" /> <public type="style" name="Theme.Material.DayNight" /> <public type="style" name="Theme.Material.DayNight.DarkActionBar" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 611b17148158..38a1693141dc 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -307,6 +307,10 @@ please see styles_device_defaults.xml. <style name="TextAppearance.Material.Widget.PopupMenu"/> <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" /> <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" /> + <style name="TextAppearance.Material.Widget.PopupMenu.Header" parent="TextAppearance.Material.Subhead"> + <item name="fontFamily">@string/font_family_title_material</item> + <item name="textSize">@dimen/text_size_menu_header_material</item> + </style> <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" /> @@ -863,6 +867,11 @@ please see styles_device_defaults.xml. <item name="dropDownHorizontalOffset">-4dip</item> </style> + <style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow"> + <item name="overlapAnchor">true</item> + <item name="popupEnterTransition">@null</item> + </style> + <style name="Widget.Material.ActionButton"> <item name="background">?attr/actionBarItemBackground</item> <item name="paddingStart">12dp</item> diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml index c6052fffd2e2..05835e7b41ab 100644 --- a/core/res/res/values/styles_micro.xml +++ b/core/res/res/values/styles_micro.xml @@ -18,6 +18,7 @@ <style name="Animation.Micro.Activity" parent="Animation.Material.Activity"> <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item> + <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item> <item name="activityOpenExitAnimation">@null</item> <item name="activityCloseEnterAnimation">@null</item> <item name="activityCloseExitAnimation">@anim/slide_out_micro</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index b5efbfd2462a..06de81d1081e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1290,6 +1290,7 @@ <java-symbol type="layout" name="number_picker" /> <java-symbol type="layout" name="permissions_package_list_item" /> <java-symbol type="layout" name="popup_menu_item_layout" /> + <java-symbol type="layout" name="popup_menu_header_item_layout" /> <java-symbol type="layout" name="remote_views_adapter_default_loading_view" /> <java-symbol type="layout" name="search_bar" /> <java-symbol type="layout" name="search_dropdown_item_icons_2line" /> @@ -2191,6 +2192,7 @@ <java-symbol type="bool" name="config_sms_force_7bit_encoding" /> <java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" /> <java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" /> + <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" /> <java-symbol type="layout" name="simple_account_item" /> <java-symbol type="array" name="config_sms_convert_destination_number_support" /> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 30101909f0b4..59dfc921c392 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -93,6 +93,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Material.Button</item> @@ -283,6 +284,7 @@ please see themes_device_defaults.xml. <item name="stackViewStyle">@style/Widget.Material.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item> @@ -449,6 +451,7 @@ please see themes_device_defaults.xml. <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item> <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item> + <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item> <!-- Button styles --> <item name="buttonStyle">@style/Widget.Material.Light.Button</item> @@ -640,6 +643,7 @@ please see themes_device_defaults.xml. <item name="stackViewStyle">@style/Widget.Material.Light.StackView</item> <item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item> <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item> + <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item> <!-- Preference styles --> <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item> diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index ac6f950a0a82..295cb80ade52 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -3,6 +3,7 @@ <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" /> <uses-permission android:name="android.permission.REMOVE_TASKS" /> + <uses-permission android:name="android.permission.REORDER_TASKS" /> <application android:name=".DocumentsApplication" @@ -49,8 +50,8 @@ </activity> <activity - android:name=".FilesActivity" - android:theme="@style/FilesTheme" + android:name=".LauncherActivity" + android:theme="@android:style/Theme.NoDisplay" android:icon="@drawable/ic_files_app" android:label="@string/files_label" android:enabled="@bool/productivity_device"> @@ -58,6 +59,17 @@ <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> + </activity> + + <activity + android:name=".FilesActivity" + android:theme="@style/FilesTheme" + android:icon="@drawable/ic_files_app" + android:label="@string/files_label" + android:documentLaunchMode="intoExisting"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + </intent-filter> <intent-filter> <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml index 7df152fb9775..673a254f63f5 100644 --- a/packages/DocumentsUI/res/menu/activity.xml +++ b/packages/DocumentsUI/res/menu/activity.xml @@ -26,6 +26,7 @@ android:id="@+id/menu_create_dir" android:title="@string/menu_create_dir" android:icon="@drawable/ic_menu_new_folder" + android:alphabeticShortcut="e" android:showAsAction="always" android:visible="false" /> <item @@ -56,11 +57,18 @@ android:icon="@drawable/ic_menu_view_list" android:showAsAction="never" /> <item + android:id="@+id/menu_new_window" + android:title="@string/menu_new_window" + android:alphabeticShortcut="n" + android:showAsAction="never" + android:visible="false" /> + <item android:id="@+id/menu_paste_from_clipboard" android:title="@string/menu_paste_from_clipboard" android:alphabeticShortcut="v" android:showAsAction="never" android:visible="false" /> + <!-- Copy action is defined in mode_directory.xml --> <item android:id="@+id/menu_advanced" android:showAsAction="never" diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml index a12edf397178..a4acb604c1ef 100644 --- a/packages/DocumentsUI/res/values/strings.xml +++ b/packages/DocumentsUI/res/values/strings.xml @@ -54,6 +54,8 @@ <!-- Menu item title that moves the selected documents [CHAR LIMIT=24] --> <string name="menu_move">Move to\u2026</string> + <!-- Menu item title that creates a new window in the activity [CHAR LIMIT=24] --> + <string name="menu_new_window">New window</string> <!-- Menu item title that copies the selected documents to clipboard [CHAR LIMIT=24] --> <string name="menu_copy_to_clipboard">Copy</string> <!-- Menu item title that pastes files from the clipboard [CHAR LIMIT=24] --> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index c8ec4dc2c510..a6a45e59f469 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -75,10 +75,11 @@ abstract class BaseActivity extends Activity { RootsCache mRoots; SearchManager mSearchManager; DrawerController mDrawer; + boolean mProductivityDevice; + private final String mTag; @LayoutRes private int mLayoutId; - private final String mTag; private DirectoryContainerView mDirectoryContainer; public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings); @@ -99,6 +100,7 @@ abstract class BaseActivity extends Activity { public void onCreate(Bundle icicle) { super.onCreate(icicle); + mProductivityDevice = getResources().getBoolean(R.bool.productivity_device); mState = (icicle != null) ? icicle.<State>getParcelable(EXTRA_STATE) : buildState(); @@ -208,6 +210,7 @@ abstract class BaseActivity extends Activity { switch (item.getItemId()) { case R.id.menu_advanced: case R.id.menu_file_size: + case R.id.menu_new_window: break; default: item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index 7e9531b777fa..e8d10888af47 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -19,6 +19,7 @@ package com.android.documentsui; import static com.android.documentsui.DirectoryFragment.ANIM_NONE; import static com.android.documentsui.Shared.DEBUG; import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkState; import android.app.Activity; import android.app.FragmentManager; @@ -85,11 +86,12 @@ public class FilesActivity extends BaseActivity { RootsFragment.show(getFragmentManager(), null); if (!mState.restored) { - Uri rootUri = getIntent().getData(); + Intent intent = getIntent(); + Uri rootUri = intent.getData(); // If we've got a specific root to display, restore that root using a dedicated // authority. That way a misbehaving provider won't result in an ANR. - if (rootUri != null) { + if (rootUri != null && !LauncherActivity.isLaunchUri(rootUri)) { new RestoreRootTask(rootUri).executeOnExecutor( ProviderExecutor.forAuthority(rootUri.getAuthority())); } else { @@ -97,7 +99,6 @@ public class FilesActivity extends BaseActivity { } // Show a failure dialog if there was a failed operation. - final Intent intent = getIntent(); final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK); final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0); final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, @@ -207,16 +208,25 @@ public class FilesActivity extends BaseActivity { public boolean onPrepareOptionsMenu(Menu menu) { boolean shown = super.onPrepareOptionsMenu(menu); - final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); + menu.findItem(R.id.menu_file_size).setVisible(true); + menu.findItem(R.id.menu_advanced).setVisible(true); + final MenuItem createDir = menu.findItem(R.id.menu_create_dir); + final MenuItem newWindow = menu.findItem(R.id.menu_new_window); + final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); boolean canCreateDir = canCreateDirectory(); createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); createDir.setVisible(canCreateDir); + createDir.setEnabled(canCreateDir); + + newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + newWindow.setVisible(mProductivityDevice); + newWindow.setEnabled(mProductivityDevice); - pasteFromCb.setVisible(true); pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); + pasteFromCb.setVisible(true); pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); return shown; @@ -224,12 +234,19 @@ public class FilesActivity extends BaseActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - final int id = item.getItemId(); - if (id == R.id.menu_paste_from_clipboard) { - DirectoryFragment dir = DirectoryFragment.get(getFragmentManager()); - dir = DirectoryFragment.get(getFragmentManager()); - dir.pasteFromClipboard(); - return true; + switch (item.getItemId()) { + case R.id.menu_create_dir: + checkState(canCreateDirectory()); + showCreateDirectoryDialog(); + return true; + case R.id.menu_new_window: + startActivity(LauncherActivity.createLaunchIntent(this)); + return true; + case R.id.menu_paste_from_clipboard: + DirectoryFragment dir = DirectoryFragment.get(getFragmentManager()); + dir = DirectoryFragment.get(getFragmentManager()); + dir.pasteFromClipboard(); + return true; } return super.onOptionsItemSelected(item); @@ -317,19 +334,13 @@ public class FilesActivity extends BaseActivity { dir = DirectoryFragment.get(getFragmentManager()); dir.selectAllFiles(); return true; - case KeyEvent.KEYCODE_N: - if (event.isShiftPressed() && canCreateDirectory()) { - showCreateDirectoryDialog(); - return true; - } case KeyEvent.KEYCODE_C: // TODO: Should be statically bound using alphabeticShortcut. See b/21330356. dir = DirectoryFragment.get(getFragmentManager()); dir.copySelectedToClipboard(); - // TODO: Cancel action mode in directory fragment. } - return super.onKeyUp(keyCode, event); + return super.onKeyShortcut(keyCode, event); } @Override diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java new file mode 100644 index 000000000000..c29937d68cdf --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 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.documentsui; + +import android.app.Activity; +import android.app.ActivityManager; +import android.app.ActivityManager.AppTask; +import android.app.ActivityManager.RecentTaskInfo; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.Nullable; + +import java.util.List; + +/** + * Provides FilesActivity task grouping support. This allows multiple FilesActivities to be + * launched (a behavior imparted by way of {@code documentLaunchMode="intoExisting"} and + * our use of pseudo document {@link Uri}s. This also lets us move an existing task + * to the foreground when a suitable task exists. + * + * Requires that {@code documentLaunchMode="intoExisting"} be set on target activity. + * + */ +public class LauncherActivity extends Activity { + + public static final String LAUNCH_CONTROL_AUTHORITY = "com.android.documentsui.launchControl"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + List<AppTask> tasks = activities.getAppTasks(); + + AppTask raiseTask = null; + for (AppTask task : tasks) { + Uri taskUri = task.getTaskInfo().baseIntent.getData(); + if (taskUri != null && isLaunchUri(taskUri)) { + raiseTask = task; + } + } + + if (raiseTask == null) { + launchFilesTask(); + } else { + raiseFilesTask(activities, raiseTask.getTaskInfo()); + } + + finish(); + } + + private void launchFilesTask() { + Intent intent = createLaunchIntent(this); + startActivity(intent); + } + + private void raiseFilesTask(ActivityManager activities, RecentTaskInfo task) { + activities.moveTaskToFront(task.id, 0); + } + + static Intent createLaunchIntent(Context context) { + Intent intent = new Intent(context, FilesActivity.class); + intent.setData(buildLaunchUri()); + return intent; + } + + private static Uri buildLaunchUri() { + return new Uri.Builder() + .authority(LAUNCH_CONTROL_AUTHORITY) + .fragment(String.valueOf(System.currentTimeMillis())) + .build(); + } + + static boolean isLaunchUri(@Nullable Uri uri) { + return uri != null && LAUNCH_CONTROL_AUTHORITY.equals(uri.getAuthority()); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java index bbffad326dff..4306a0e024a2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/State.java +++ b/packages/DocumentsUI/src/com/android/documentsui/State.java @@ -44,14 +44,14 @@ public class State implements android.os.Parcelable { public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME; public boolean allowMultiple; - public boolean forceSize ; + public boolean forceSize; public boolean showSize; - public boolean localOnly ; - public boolean forceAdvanced ; - public boolean showAdvanced ; - public boolean stackTouched ; - public boolean restored ; - public boolean directoryCopy ; + public boolean localOnly; + public boolean forceAdvanced; + public boolean showAdvanced; + public boolean stackTouched; + public boolean restored; + public boolean directoryCopy; /** Transfer mode for file copy/move operations. */ public int transferMode; diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 93dc88950fe5..8fc7ad089427 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -206,7 +206,7 @@ android:resumeWhilePausing="true" android:screenOrientation="behind" android:resizeableActivity="true" - android:theme="@style/config_recents_activity_theme"> + android:theme="@style/RecentsTheme.Wallpaper"> <intent-filter> <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" /> </intent-filter> diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index d608e25ebeba..f7e23449fa0a 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -20,10 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <integer name="status_bar_recents_bg_gradient_degrees">90</integer> - <!-- The maximum number of rows in the QuickSettings --> <integer name="quick_settings_max_rows">2</integer> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index a9e7735ea660..2893b999997f 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -19,25 +19,6 @@ <!-- thickness (width) of the navigation bar on phones that require it --> <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen> - <!-- Recent Applications parameters --> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen> - <!-- How far the thumbnail for a recent app appears from top edge --> - <dimen name="status_bar_recents_thumbnail_top_margin">28dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">156dip</dimen> - <!-- Left margin of application label text --> - <dimen name="status_bar_recents_app_label_left_margin">12dip</dimen> - <!-- Margin between recents container and glow on the right --> - <dimen name="status_bar_recents_right_glow_margin">0dip</dimen> - <!-- Padding between recents items --> - <dimen name="status_bar_recents_item_padding">2dip</dimen> - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - <!-- The side padding for the task stack as a percentage of the width. --> <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.26</item> diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index 3a62ad94f2c7..81ca86bcb9ef 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -17,8 +17,6 @@ --> <resources> <!-- Recent Applications parameters --> - <dimen name="status_bar_recents_app_label_width">190dip</dimen> - <!-- The side padding for the task stack as a percentage of the width. --> <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item> diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml deleted file mode 100644 index 7dc91d164e2e..000000000000 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (c) 2012, 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. -*/ ---> -<resources> - <!-- Recent Applications parameters --> - <dimen name="status_bar_recents_app_label_width">140dip</dimen> -</resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 1af4ab1f4b15..6deb818ade04 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -32,10 +32,6 @@ <!-- The width of the view containing the menu/ime navigation bar icons --> <dimen name="navigation_extra_key_width">48dip</dimen> - <!-- Size of application thumbnail --> - <dimen name="status_bar_recents_thumbnail_width">200dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">177dp</dimen> - <!-- Minimum fraction of the screen that should be taken up by the notification panel. --> <item type="dimen" name="notification_panel_min_height_frac">40%</item> diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml index fbeadcd56da7..1efae42eac2b 100644 --- a/packages/SystemUI/res/values-sw720dp/config.xml +++ b/packages/SystemUI/res/values-sw720dp/config.xml @@ -22,20 +22,6 @@ <resources> <integer name="status_bar_config_maxNotificationIcons">5</integer> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <bool name="config_recents_interface_for_tablets">true</bool> - - <!-- Whether recents thumbnails should stretch in both x and y to fill their - ImageView --> - <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool> - - <!-- Min alpha % that recent items will fade to while being dismissed --> - <integer name="config_recent_item_min_alpha">0</integer> - - <!-- Transposes the search bar layout in landscape --> - <bool name="recents_transpose_search_layout_with_orientation">false</bool> - <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow card. --> <integer name="keyguard_max_notification_count">5</integer> diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml index dd158c2c70bc..7cee38140fe7 100644 --- a/packages/SystemUI/res/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp/dimens.xml @@ -29,42 +29,9 @@ <!-- Bottom margin (from display edge) for status bar panels --> <dimen name="panel_float">56dp</dimen> - <!-- Recent Applications parameters --> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">28dp</dimen> - <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen> - <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen> - - <!-- Size of application icon --> - <dimen name="status_bar_recents_thumbnail_width">208dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">130dp</dimen> - - <!-- Width of recents panel --> - <dimen name="status_bar_recents_width">600dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Size of application label text --> - <dimen name="status_bar_recents_app_label_text_size">18dip</dimen> - <!-- Size of application description text --> - <dimen name="status_bar_recents_app_description_text_size">18dip</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">97dip</dimen> - <!-- Left margin for application label --> - <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen> - <!-- Size of fading edge for text --> - <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen> - <!-- Size of fading edge for scrolling --> - <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen> - <!-- The radius of the rounded corners on a task view. --> <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen> - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index da210843bd28..f40f0d9aecdb 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -24,11 +24,8 @@ <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black --> <color name="system_bar_background_transparent">#00000000</color> <color name="notification_panel_solid_background">#ff000000</color> - <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable> - <color name="status_bar_recents_app_label_color">#ffffffff</color> <drawable name="status_bar_notification_row_background_color">#ff090909</drawable> <color name="notification_list_shadow_top">#80000000</color> - <drawable name="recents_callout_line">#99ffffff</drawable> <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable> <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white --> <color name="batterymeter_charge_color">#FFFFFFFF</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 8da11488c482..f28c9d3efc14 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -20,15 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <bool name="config_recents_interface_for_tablets">false</bool> - - <!-- Whether recents thumbnails should stretch in both x and y to fill their - ImageView --> - <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool> - <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled for devices where the java drawing of round rects may be slow --> <bool name="config_recents_use_hardware_layers">false</bool> @@ -46,9 +37,6 @@ certain GPU's and thus can be turned off with only minimal visual impact. --> <bool name="config_notifications_round_rect_clipping">true</bool> - <!-- The theme to use for RecentsActivity. --> - <item type="style" name="config_recents_activity_theme">@style/RecentsTheme.Wallpaper</item> - <!-- Control whether status bar should distinguish HSPA data icon form UMTS data icon on devices --> <bool name="config_hspa_data_distinguishable">false</bool> @@ -92,10 +80,6 @@ <!-- The length of the vibration when the notification pops open. --> <integer name="one_finger_pop_duration_ms">10</integer> - <!-- Whether we're using the tablet-optimized recents interface (we use this - value at runtime for some things) --> - <integer name="status_bar_recents_bg_gradient_degrees">90</integer> - <!-- decay duration (from size_max -> size), in ms --> <integer name="navigation_bar_deadzone_hold">333</integer> <integer name="navigation_bar_deadzone_decay">333</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 96a77256bc42..abfd86383776 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -16,45 +16,6 @@ */ --> <resources> - <!-- Recent Applications parameters --> - <!-- Upper width limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_width">48dp</dimen> - <!-- Upper height limit for application icon --> - <dimen name="status_bar_recents_app_icon_max_height">48dp</dimen> - - <!-- Size of application thumbnail --> - <dimen name="status_bar_recents_thumbnail_width">164dp</dimen> - <dimen name="status_bar_recents_thumbnail_height">145dp</dimen> - <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen> - - <!-- Size of application label text --> - <dimen name="status_bar_recents_app_label_text_size">14dip</dimen> - <!-- Size of application description text --> - <dimen name="status_bar_recents_app_description_text_size">14dip</dimen> - <!-- Size of fading edge for text --> - <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen> - <!-- Size of fading edge for scrolling --> - <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen> - <!-- Margin between recents container and glow on the right --> - <dimen name="status_bar_recents_right_glow_margin">100dip</dimen> - <!-- How far the thumbnail for a recent app appears from left edge --> - <dimen name="status_bar_recents_thumbnail_left_margin">20dp</dimen> - <!-- Padding for text descriptions --> - <dimen name="status_bar_recents_text_description_padding">8dp</dimen> - <!-- Width of application label text --> - <dimen name="status_bar_recents_app_label_width">88dip</dimen> - <!-- Left margin of application label text --> - <dimen name="status_bar_recents_app_label_left_margin">0dip</dimen> - <!-- Padding between recents items --> - <dimen name="status_bar_recents_item_padding">0dip</dimen> - <!-- When recents first appears, how far the icon and label of the primary activity - travel --> - <dimen name="status_bar_recents_app_icon_translate_distance">35dip</dimen> - - <!-- Where to place the app icon over the thumbnail --> - <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen> - <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen> - <!-- Amount to offset bottom of notification peek window from top of status bar. --> <dimen name="peek_window_y_offset">-12dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 33f6564b948a..620732442659 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -34,6 +34,8 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; +import com.android.systemui.classifier.FalsingManager; + public class SwipeHelper implements Gefingerpoken { static final String TAG = "com.android.systemui.SwipeHelper"; private static final boolean DEBUG = false; @@ -67,6 +69,7 @@ public class SwipeHelper implements Gefingerpoken { private Handler mHandler; private int mSwipeDirection; private VelocityTracker mVelocityTracker; + private FalsingManager mFalsingManager; private float mInitialTouchPos; private boolean mDragging; @@ -97,6 +100,7 @@ public class SwipeHelper implements Gefingerpoken { android.R.interpolator.fast_out_linear_in); mFalsingThreshold = context.getResources().getDimensionPixelSize( R.dimen.swipe_helper_falsing_threshold); + mFalsingManager = FalsingManager.getInstance(context); } public void setLongPressListener(LongPressListener listener) { @@ -449,8 +453,13 @@ public class SwipeHelper implements Gefingerpoken { boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) && (Math.abs(velocity) > Math.abs(perpendicularVelocity)) && (velocity > 0) == (getTranslation(mCurrAnimView) > 0); - boolean falsingDetected = mCallback.isAntiFalsingNeeded() - && !mTouchAboveFalsingThreshold; + boolean falsingDetected = mCallback.isAntiFalsingNeeded(); + + if (mFalsingManager.isClassiferEnabled()) { + falsingDetected = falsingDetected && mFalsingManager.isFalseTouch(); + } else { + falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold; + } boolean dismissChild = mCallback.canChildBeDismissed(mCurrView) && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough) diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java index 649279dac285..c83c74f69f90 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java @@ -28,12 +28,10 @@ import java.util.ArrayList; public class ClassifierData { private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>(); private ArrayList<Stroke> mEndingStrokes = new ArrayList<>(); - private float mXdpi; - private float mYdpi; + private final float mDpi; - public ClassifierData(float xdpi, float ydpi) { - mXdpi = xdpi; - mYdpi = ydpi; + public ClassifierData(float dpi) { + mDpi = dpi; } public void update(MotionEvent event) { @@ -46,7 +44,7 @@ public class ClassifierData { for (int i = 0; i < event.getPointerCount(); i++) { int id = event.getPointerId(i); if (mCurrentStrokes.get(id) == null) { - mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mXdpi, mYdpi)); + mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mDpi)); } mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i), event.getEventTimeNano()); diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java index c68fff837c6f..735a7c4bad4a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java @@ -39,7 +39,11 @@ import com.android.systemui.statusbar.StatusBarState; public class FalsingManager implements SensorEventListener { private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer"; - private static final int[] SENSORS = new int[] { + private static final int[] CLASSIFIER_SENSORS = new int[] { + Sensor.TYPE_PROXIMITY, + }; + + private static final int[] COLLECTOR_SENSORS = new int[] { Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_GYROSCOPE, Sensor.TYPE_PROXIMITY, @@ -113,7 +117,17 @@ public class FalsingManager implements SensorEventListener { private void onSessionStart() { mBouncerOn = false; mSessionActive = true; - for (int sensorType : SENSORS) { + + if (mHumanInteractionClassifier.isEnabled()) { + registerSensors(CLASSIFIER_SENSORS); + } + if (mDataCollector.isEnabled()) { + registerSensors(COLLECTOR_SENSORS); + } + } + + private void registerSensors(int [] sensors) { + for (int sensorType : sensors) { Sensor s = mSensorManager.getDefaultSensor(sensorType); if (s != null) { mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME); @@ -121,6 +135,10 @@ public class FalsingManager implements SensorEventListener { } } + public boolean isClassiferEnabled() { + return mHumanInteractionClassifier.isEnabled(); + } + private boolean isEnabled() { return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled(); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java index 6ef805c569dd..0e45ac19469a 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java @@ -23,8 +23,10 @@ import android.os.Build; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; +import android.util.DisplayMetrics; import android.view.MotionEvent; +import java.util.ArrayDeque; import java.util.ArrayList; /** @@ -32,6 +34,7 @@ import java.util.ArrayList; */ public class HumanInteractionClassifier extends Classifier { private static final String HIC_ENABLE = "HIC_enable"; + private static final float FINGER_DISTANCE = 0.1f; private static HumanInteractionClassifier sInstance = null; private final Handler mHandler = new Handler(); @@ -39,11 +42,13 @@ public class HumanInteractionClassifier extends Classifier { private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>(); private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>(); + private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>(); private final int mStrokeClassifiersSize; private final int mGestureClassifiersSize; + private final float mDpi; private HistoryEvaluator mHistoryEvaluator; - private boolean mEnableClassifier = false; + private boolean mEnableClassifier = true; private int mCurrentType = Classifier.GENERIC; protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) { @@ -55,8 +60,13 @@ public class HumanInteractionClassifier extends Classifier { private HumanInteractionClassifier(Context context) { mContext = context; - mClassifierData = new ClassifierData(mContext.getResources().getDisplayMetrics().xdpi, - mContext.getResources().getDisplayMetrics().ydpi); + DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics(); + + // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi + // were to be used separately. Due negligible differences in xdpi and ydpi we can just + // take the average. + mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f; + mClassifierData = new ClassifierData(mDpi); mHistoryEvaluator = new HistoryEvaluator(); mStrokeClassifiers.add(new AnglesVarianceClassifier(mClassifierData)); @@ -101,40 +111,71 @@ public class HumanInteractionClassifier extends Classifier { @Override public void onTouchEvent(MotionEvent event) { - if (mEnableClassifier) { - mClassifierData.update(event); + if (!mEnableClassifier) { + return; + } - for (int i = 0; i < mStrokeClassifiersSize; i++) { - mStrokeClassifiers.get(i).onTouchEvent(event); + // If the user is dragging down the notification, he might want to drag it down + // enough to see the content, read it for a while and then lift the finger to open + // the notification. This kind of motion scores very bad in the Classifier so the + // MotionEvents which are close to the current position of the finger are not + // sent to the classifiers until the finger moves far enough. When the finger if lifted + // up, the last MotionEvent which was far enough from the finger is set as the final + // MotionEvent and sent to the Classifiers. + if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN) { + mBufferedEvents.add(MotionEvent.obtain(event)); + Point pointEnd = new Point(event.getX() / mDpi, event.getY() / mDpi); + + while (pointEnd.dist(new Point(mBufferedEvents.getFirst().getX() / mDpi, + mBufferedEvents.getFirst().getY() / mDpi)) > FINGER_DISTANCE) { + addTouchEvent(mBufferedEvents.getFirst()); + mBufferedEvents.remove(); } - for (int i = 0; i < mGestureClassifiersSize; i++) { - mGestureClassifiers.get(i).onTouchEvent(event); + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP) { + mBufferedEvents.getFirst().setAction(MotionEvent.ACTION_UP); + addTouchEvent(mBufferedEvents.getFirst()); + mBufferedEvents.clear(); } + } else { + addTouchEvent(event); + } + } - int size = mClassifierData.getEndingStrokes().size(); - for (int i = 0; i < size; i++) { - Stroke stroke = mClassifierData.getEndingStrokes().get(i); - float evaluation = 0.0f; - for (int j = 0; j < mStrokeClassifiersSize; j++) { - evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation( - mCurrentType, stroke); - } - mHistoryEvaluator.addStroke(evaluation); - } + private void addTouchEvent(MotionEvent event) { + mClassifierData.update(event); - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - float evaluation = 0.0f; - for (int i = 0; i < mGestureClassifiersSize; i++) { - evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType); - } - mHistoryEvaluator.addGesture(evaluation); - setType(Classifier.GENERIC); + for (int i = 0; i < mStrokeClassifiersSize; i++) { + mStrokeClassifiers.get(i).onTouchEvent(event); + } + + for (int i = 0; i < mGestureClassifiersSize; i++) { + mGestureClassifiers.get(i).onTouchEvent(event); + } + + int size = mClassifierData.getEndingStrokes().size(); + for (int i = 0; i < size; i++) { + Stroke stroke = mClassifierData.getEndingStrokes().get(i); + float evaluation = 0.0f; + for (int j = 0; j < mStrokeClassifiersSize; j++) { + evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation( + mCurrentType, stroke); } + mHistoryEvaluator.addStroke(evaluation); + } - mClassifierData.cleanUp(event); + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + float evaluation = 0.0f; + for (int i = 0; i < mGestureClassifiersSize; i++) { + evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType); + } + mHistoryEvaluator.addGesture(evaluation); + setType(Classifier.GENERIC); } + + mClassifierData.cleanUp(event); } @Override @@ -149,7 +190,10 @@ public class HumanInteractionClassifier extends Classifier { } public boolean isFalseTouch() { - return mHistoryEvaluator.getEvaluation() >= 5.0f; + if (mEnableClassifier) { + return mHistoryEvaluator.getEvaluation() >= 5.0f; + } + return false; } public boolean isEnabled() { diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java index 49e6fb8b62c9..fb04d3e73a2d 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java @@ -29,18 +29,16 @@ public class Stroke { private long mStartTimeNano; private long mEndTimeNano; private float mLength; - private float mXdpi; - private float mYdpi; + private final float mDpi; - public Stroke(long eventTimeNano, float xdpi, float ydpi) { - mXdpi = xdpi; - mYdpi = ydpi; + public Stroke(long eventTimeNano, float dpi) { + mDpi = dpi; mStartTimeNano = mEndTimeNano = eventTimeNano; } public void addPoint(float x, float y, long eventTimeNano) { mEndTimeNano = eventTimeNano; - Point point = new Point(x / mXdpi, y / mYdpi, eventTimeNano - mStartTimeNano); + Point point = new Point(x / mDpi, y / mDpi, eventTimeNano - mStartTimeNano); if (!mPoints.isEmpty()) { mLength += mPoints.get(mPoints.size() - 1).dist(point); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index cbccaf887d69..a3e89f2f06c4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -500,6 +500,8 @@ public class Recents extends SystemUI mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height); mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); + // TODO: We can't rely on this anymore since the activity context will yield different + // resources while multiwindow is enabled mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy); mConfig.updateOnConfigurationChange(); Rect searchBarBounds = new Rect(); @@ -735,7 +737,10 @@ public class Recents extends SystemUI /** Starts the recents activity */ void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) { RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); - RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy); + // Don't reinitialize the configuration completely here, since it has the wrong context, + // only update the parts that we can get from any context + RecentsConfiguration config = RecentsConfiguration.getInstance(); + config.reinitializeWithApplicationContext(mContext, mSystemServicesProxy); if (sInstanceLoadPlan == null) { // Create a new load plan if onPreloadRecents() was never triggered diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index b41b5e75e0f6..a59eb3048be3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -166,7 +166,7 @@ public class RecentsConfiguration { sInstance.update(context); sPrevConfigurationHashCode = configHashCode; } - sInstance.updateOnReinitialize(context, ssp); + sInstance.reinitializeWithApplicationContext(context.getApplicationContext(), ssp); return sInstance; } @@ -276,8 +276,8 @@ public class RecentsConfiguration { systemInsets.set(insets); } - /** Updates the states that need to be re-read whenever we re-initialize. */ - void updateOnReinitialize(Context context, SystemServicesProxy ssp) { + /** Updates the states that need to be re-read from the application context. */ + void reinitializeWithApplicationContext(Context context, SystemServicesProxy ssp) { // Check if the developer options are enabled developerOptionsEnabled = ssp.getGlobalSetting(context, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index b01a2a8a2c2f..10d4a965852f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -112,7 +112,7 @@ public class CommandQueue extends IStatusBar.Stub { public void appTransitionStarting(long startTime, long duration); public void showAssistDisclosure(); public void startAssist(Bundle args); - public void onCameraLaunchGestureDetected(); + public void onCameraLaunchGestureDetected(int source); } public CommandQueue(Callbacks callbacks, StatusBarIconList list) { @@ -306,10 +306,10 @@ public class CommandQueue extends IStatusBar.Stub { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { synchronized (mList) { mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE); - mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget(); + mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget(); } } @@ -415,7 +415,7 @@ public class CommandQueue extends IStatusBar.Stub { mCallbacks.startAssist((Bundle) msg.obj); break; case MSG_CAMERA_LAUNCH_GESTURE: - mCallbacks.onCameraLaunchGestureDetected(); + mCallbacks.onCameraLaunchGestureDetected(msg.arg1); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java index d9127952a329..687f6c1b0922 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java @@ -130,7 +130,7 @@ public class DragDownHelper implements Gefingerpoken { } return true; case MotionEvent.ACTION_UP: - if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild, + if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild, (int) (y - mInitialTouchY))) { if (mStartingChild == null) { mDragDownCallback.setEmptyDragAmount(0f); @@ -148,6 +148,13 @@ public class DragDownHelper implements Gefingerpoken { return false; } + private boolean isFalseTouch() { + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); + } + return !mDraggedFarEnough; + } + private void captureStartingChild(float x, float y) { if (mStartingChild == null) { mStartingChild = findView(x, y); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 60ebfdf639ef..41adeb587736 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -28,6 +28,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.systemui.R; +import com.android.systemui.classifier.FalsingManager; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; @@ -62,6 +63,7 @@ public class KeyguardAffordanceHelper { private Interpolator mAppearInterpolator; private Interpolator mDisappearInterpolator; private Animator mSwipeAnimator; + private FalsingManager mFalsingManager; private int mMinBackgroundRadius; private boolean mMotionCancelled; private int mTouchTargetSize; @@ -109,6 +111,7 @@ public class KeyguardAffordanceHelper { android.R.interpolator.linear_out_slow_in); mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in); + mFalsingManager = FalsingManager.getInstance(mContext); } private void initIcons() { @@ -322,7 +325,12 @@ public class KeyguardAffordanceHelper { float vel = getCurrentVelocity(lastX, lastY); // We snap back if the current translation is not far enough - boolean snapBack = isBelowFalsingThreshold(); + boolean snapBack; + if (mFalsingManager.isFalseTouch()) { + snapBack = mFalsingManager.isFalseTouch(); + } else { + snapBack = isBelowFalsingThreshold(); + } // or if the velocity is in the opposite direction. boolean velIsInWrongDirection = vel * mTranslation < 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 012dc9c53207..14176a6f5b3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -77,6 +77,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView"; + public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance"; + public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture"; + public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap"; + + public static final String EXTRA_CAMERA_LAUNCH_SOURCE + = "com.android.systemui.camera_launch_source"; + private static final Intent SECURE_CAMERA_INTENT = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE) .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); @@ -170,7 +177,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } else if (host == mCameraImageView) { - launchCamera(); + launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); return true; } else if (host == mLeftAffordanceView) { launchLeftAffordance(); @@ -349,7 +356,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onClick(View v) { if (v == mCameraImageView) { - launchCamera(); + launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE); } else if (v == mLeftAffordanceView) { launchLeftAffordance(); } if (v == mLockIcon) { @@ -417,8 +424,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - public void launchCamera() { + public void launchCamera(String source) { final Intent intent = getCameraIntent(); + intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source); boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity( mContext, intent, KeyguardUpdateMonitor.getCurrentUser()); if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 980527b82666..08353cbb51c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -22,6 +22,7 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.Context; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -204,6 +205,7 @@ public class NotificationPanelView extends PanelView implements private boolean mHeadsUpAnimatingAway; private boolean mLaunchingAffordance; private FalsingManager mFalsingManager; + private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() { @Override @@ -480,6 +482,7 @@ public class NotificationPanelView extends PanelView implements mUnlockIconActive = false; if (!mLaunchingAffordance) { mAfforanceHelper.reset(false); + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; } closeQs(); mStatusBar.dismissPopups(); @@ -692,7 +695,7 @@ public class NotificationPanelView extends PanelView implements } private boolean flingExpandsQs(float vel) { - if (isBelowFalsingThreshold()) { + if (isFalseTouch()) { return false; } if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) { @@ -702,8 +705,14 @@ public class NotificationPanelView extends PanelView implements } } - private boolean isBelowFalsingThreshold() { - return !mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD; + private boolean isFalseTouch() { + if (mStatusBarState != StatusBarState.KEYGUARD) { + return false; + } + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); + } + return !mQsTouchAboveFalsingThreshold; } private float getQsExpansionFraction() { @@ -1428,7 +1437,7 @@ public class NotificationPanelView extends PanelView implements } return; } - boolean belowFalsingThreshold = isBelowFalsingThreshold(); + boolean belowFalsingThreshold = isFalseTouch(); if (belowFalsingThreshold) { vel = 0; } @@ -1965,20 +1974,23 @@ public class NotificationPanelView extends PanelView implements mKeyguardBottomArea.launchLeftAffordance(); } } else { - EventLogTags.writeSysuiLockscreenGesture( - EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp); - + if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals( + mLastCameraLaunchSource)) { + EventLogTags.writeSysuiLockscreenGesture( + EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, + lengthDp, velocityDp); + } mFalsingManager.onCameraOn(); if (mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard(new Runnable() { @Override public void run() { - mKeyguardBottomArea.launchCamera(); + mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); } }, null, true /* dismissShade */, false /* afterKeyguardGone */); } else { - mKeyguardBottomArea.launchCamera(); + mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource); } } mStatusBar.startLaunchTransitionTimeout(); @@ -2419,7 +2431,17 @@ public class NotificationPanelView extends PanelView implements return !mDozing; } - public void launchCamera(boolean animate) { + public void launchCamera(boolean animate, int source) { + if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP; + } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) { + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE; + } else { + + // Default. + mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE; + } + // If we are launching it when we are occluded already we don't want it to animate, // nor setting these flags, since the occluded state doesn't change anymore, hence it's // never reset. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 3feead8f36ad..bd16257e6ece 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -610,8 +610,8 @@ public abstract class PanelView extends FrameLayout { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } - if (mFalsingManager.isFalseTouch()) { - return true; + if (mFalsingManager.isClassiferEnabled()) { + return mFalsingManager.isFalseTouch(); } if (!mTouchAboveFalsingThreshold) { return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 151fa3c5a033..98f5444b16d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -492,6 +492,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private ExpandableNotificationRow mDraggedDownRow; private boolean mLaunchCameraOnScreenTurningOn; private boolean mLaunchCameraOnFinishedGoingToSleep; + private int mLastCameraLaunchSource; private PowerManager.WakeLock mGestureWakeLock; private Vibrator mVibrator; @@ -3992,7 +3993,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHandler.post(new Runnable() { @Override public void run() { - onCameraLaunchGestureDetected(); + onCameraLaunchGestureDetected(mLastCameraLaunchSource); } }); } @@ -4010,7 +4011,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mFalsingManager.onScreenTurningOn(); mNotificationPanel.onScreenTurningOn(); if (mLaunchCameraOnScreenTurningOn) { - mNotificationPanel.launchCamera(false); + mNotificationPanel.launchCamera(false, mLastCameraLaunchSource); mLaunchCameraOnScreenTurningOn = false; } } @@ -4175,7 +4176,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { + mLastCameraLaunchSource = source; if (mStartedGoingToSleep) { mLaunchCameraOnFinishedGoingToSleep = true; return; @@ -4201,7 +4203,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); } if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) { - mNotificationPanel.launchCamera(mDeviceInteractive /* animate */); + mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source); } else { // We need to defer the camera launch until the screen comes on, since otherwise // we will dismiss us too early since we are waiting on an activity to be drawn and diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 2587b9f237c8..bbe5dd90d11f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -171,7 +171,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { } @Override diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index 7c85001c9175..f2459852d706 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -17,6 +17,7 @@ package com.android.server; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -263,7 +264,8 @@ public class GestureLauncherService extends SystemService { } if (launched) { Slog.i(TAG, "Power button double tap gesture detected, launching camera."); - launched = handleCameraLaunchGesture(false /* useWakelock */); + launched = handleCameraLaunchGesture(false /* useWakelock */, + StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP); if (launched) { MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE, (int) doubleTapInterval); @@ -276,7 +278,7 @@ public class GestureLauncherService extends SystemService { /** * @return true if camera was launched, false otherwise. */ - private boolean handleCameraLaunchGesture(boolean useWakelock) { + private boolean handleCameraLaunchGesture(boolean useWakelock, int source) { boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 0) != 0; if (!userSetupComplete) { @@ -295,7 +297,7 @@ public class GestureLauncherService extends SystemService { } StatusBarManagerInternal service = LocalServices.getService( StatusBarManagerInternal.class); - service.onCameraLaunchGestureDetected(); + service.onCameraLaunchGestureDetected(source); return true; } @@ -334,7 +336,8 @@ public class GestureLauncherService extends SystemService { Slog.d(TAG, String.format("Received a camera launch event: " + "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2])); } - if (handleCameraLaunchGesture(true /* useWakelock */)) { + if (handleCameraLaunchGesture(true /* useWakelock */, + StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) { MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE); trackCameraLaunchEvent(event); } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 17a44720deaf..842b8cdff7ed 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -24,6 +24,7 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; @@ -87,6 +88,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.Trace; import android.os.TransactionTooLargeException; import android.os.UserHandle; import android.os.WorkSource; @@ -2968,6 +2970,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId); + ActivityRecord r = stack.topRunningActivityLocked(null); mTmpBounds.clear(); @@ -3051,6 +3055,8 @@ public final class ActivityStackSupervisor implements DisplayListener { resumeTopActivitiesLocked(stack, null, null); } } + + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) { @@ -3079,6 +3085,8 @@ public final class ActivityStackSupervisor implements DisplayListener { return; } + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId); + // The stack of a task is determined by its size (fullscreen vs non-fullscreen). // Place the task in the right stack if it isn't there already based on the requested // bounds. @@ -3124,6 +3132,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } } mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); + + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 99ca050c9ae7..e49a7e49822c 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2524,11 +2524,14 @@ public class AudioService extends IAudioService.Stub { } /** @see AudioManager#setBluetoothScoOn(boolean) */ - public void setBluetoothScoOn(boolean on){ + public void setBluetoothScoOn(boolean on) { if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { return; } + setBluetoothScoOnInt(on); + } + public void setBluetoothScoOnInt(boolean on) { if (on) { mForcedUseForComm = AudioSystem.FORCE_BT_SCO; } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { @@ -2889,6 +2892,8 @@ public class AudioService extends IAudioService.Stub { mScoAudioState = SCO_STATE_INACTIVE; broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); } + AudioSystem.setParameters("A2dpSuspended=false"); + setBluetoothScoOnInt(false); } private void broadcastScoConnectionState(int state) { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 533f425e33f7..452378ff1e45 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -837,7 +837,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mPendingScreenOff && target != Display.STATE_OFF) { setScreenState(Display.STATE_OFF); mPendingScreenOff = false; - mPowerState.dismissColorFade(); } if (target == Display.STATE_ON) { @@ -911,7 +910,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // A black surface is already hiding the contents of the screen. setScreenState(Display.STATE_OFF); mPendingScreenOff = false; - mPowerState.dismissColorFade(); } else if (performScreenOffTransition && mPowerState.prepareColorFade(mContext, mColorFadeFadesConfig ? diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index be37f524eb8d..088d96e4a6e0 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -544,7 +544,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId); } } - if (physIndex > 0 && mActivePhysIndex == physIndex) { + if (mActivePhysIndex == physIndex) { return; } SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 5d0193108891..25d646d2bb3b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -28,5 +28,5 @@ public interface StatusBarManagerInternal { void showScreenPinningRequest(); void showAssistDisclosure(); void startAssist(Bundle args); - void onCameraLaunchGestureDetected(); + void onCameraLaunchGestureDetected(int source); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 11a16394a502..19b03d5e56cd 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -178,10 +178,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void onCameraLaunchGestureDetected() { + public void onCameraLaunchGestureDetected(int source) { if (mBar != null) { try { - mBar.onCameraLaunchGestureDetected(); + mBar.onCameraLaunchGestureDetected(source); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index d1904d80ebc5..df2e5e80b59b 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -22,6 +22,7 @@ import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.RESIZE_MODE_FORCED; import static android.app.ActivityManager.RESIZE_MODE_USER; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS; import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP; @@ -33,6 +34,7 @@ import android.graphics.Rect; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.Trace; import android.util.DisplayMetrics; import android.util.Slog; import android.view.Choreographer; @@ -145,10 +147,12 @@ class TaskPositioner implements DimLayer.DimLayerUser { synchronized (mService.mWindowMap) { mDragEnded = notifyMoveLocked(newX, newY); } + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask"); try { mService.mActivityManager.resizeTask( mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER); } catch(RemoteException e) {} + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } break; case MotionEvent.ACTION_UP: { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c73dbaf607eb..37deffe39bea 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; @@ -38,6 +39,7 @@ import android.app.AppOpsManager; import android.os.PowerManager; import android.os.RemoteCallbackList; import android.os.SystemClock; +import android.os.Trace; import android.os.WorkSource; import android.util.DisplayMetrics; import android.util.TimeUtils; @@ -1465,10 +1467,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // We want the tag name to be somewhat stable so that it is easier to correlate // in wake lock statistics. So in particular, we don't want to include the // window's hash code as in toString(). - CharSequence tag = mAttrs.getTitle(); - if (tag == null) { - tag = mAttrs.packageName; - } + final CharSequence tag = getWindowTag(); mDrawLock = mService.mPowerManager.newWakeLock( PowerManager.DRAW_WAKE_LOCK, "Window:" + tag); mDrawLock.setReferenceCounted(false); @@ -1605,6 +1604,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } void reportResized() { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag()); try { if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this + ": " + mCompatFrame); @@ -1670,6 +1670,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.mPendingRemove.add(this); mService.mWindowPlacerLocked.requestTraversal(); } + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } public void registerFocusObserver(IWindowFocusObserver observer) { @@ -1901,15 +1902,20 @@ final class WindowState implements WindowManagerPolicy.WindowState { String makeInputChannelName() { return Integer.toHexString(System.identityHashCode(this)) - + " " + mAttrs.getTitle(); + + " " + getWindowTag(); + } + + private CharSequence getWindowTag() { + CharSequence tag = mAttrs.getTitle(); + if (tag == null || tag.length() <= 0) { + tag = mAttrs.packageName; + } + return tag; } @Override public String toString() { - CharSequence title = mAttrs.getTitle(); - if (title == null || title.length() <= 0) { - title = mAttrs.packageName; - } + final CharSequence title = getWindowTag(); if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) { mLastTitle = title; mWasExiting = mExiting; diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java index 9ee9cf4fbcc6..e0d2ac12be21 100644 --- a/services/net/java/android/net/dhcp/DhcpClient.java +++ b/services/net/java/android/net/dhcp/DhcpClient.java @@ -244,8 +244,9 @@ public class DhcpClient extends BaseDhcpStateMachine { private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) { String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName; - Intent intent = new Intent(action, null) - .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + Intent intent = new Intent(action, null).addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | + Intent.FLAG_RECEIVER_FOREGROUND); // TODO: The intent's package covers the whole of the system server, so it's pretty generic. // Consider adding some sort of token as well. intent.setPackage(mContext.getPackageName()); diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 8779462e073e..6e60d607fc08 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -14,6 +14,7 @@ package android.telecom; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; @@ -472,9 +473,12 @@ public class TelecomManager { * <p> * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param uriScheme The URI scheme. * @return The {@link PhoneAccountHandle} corresponding to the account to be used. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { try { if (isServiceConnected()) { @@ -606,9 +610,12 @@ public class TelecomManager { * calls. The returned list includes only those accounts which have been explicitly enabled * by the user. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @see #EXTRA_PHONE_ACCOUNT_HANDLE * @return A list of {@code PhoneAccountHandle} objects. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public List<PhoneAccountHandle> getCallCapablePhoneAccounts() { return getCallCapablePhoneAccounts(false); } @@ -881,9 +888,12 @@ public class TelecomManager { * Return whether a given phone number is the configured voicemail number for a * particular phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the account to check the voicemail number against * @param number The number to look up. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { try { if (isServiceConnected()) { @@ -899,10 +909,13 @@ public class TelecomManager { /** * Return the voicemail number for a given phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the phone account. * @return The voicemail number for the phone account, and {@code null} if one has not been * configured. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { @@ -918,9 +931,12 @@ public class TelecomManager { /** * Return the line 1 phone number for given phone account. * + * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} + * * @param accountHandle The handle for the account retrieve a number for. * @return A string representation of the line 1 phone number. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1Number(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { @@ -940,6 +956,7 @@ public class TelecomManager { * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} * </p> */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isInCall() { try { if (isServiceConnected()) { @@ -1031,7 +1048,10 @@ public class TelecomManager { /** * Silences the ringer if a ringing call exists. + * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger() { try { if (isServiceConnected()) { @@ -1136,9 +1156,12 @@ public class TelecomManager { * Requires that the method-caller be set as the system dialer app. * </p> * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param dialString The digits to dial. * @return True if the digits were processed as an MMI code, false otherwise. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String dialString) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1159,10 +1182,13 @@ public class TelecomManager { * Requires that the method-caller be set as the system dialer app. * </p> * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param accountHandle The handle for the account the MMI code should apply to. * @param dialString The digits to dial. * @return True if the digits were processed as an MMI code, false otherwise. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1177,11 +1203,14 @@ public class TelecomManager { } /** + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * * @param accountHandle The handle for the account to derive an adn query URI for or * {@code null} to return a URI which will use the default account. * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount} * for the the content retrieve. */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) { ITelecomService service = getTelecomService(); if (service != null && accountHandle != null) { @@ -1199,7 +1228,10 @@ public class TelecomManager { * <p> * Requires that the method-caller be set as the system dialer app. * </p> + * + * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification() { ITelecomService service = getTelecomService(); if (service != null) { @@ -1221,6 +1253,7 @@ public class TelecomManager { * * @param showDialpad Brings up the in-call dialpad as part of showing the in-call screen. */ + @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean showDialpad) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1262,6 +1295,7 @@ public class TelecomManager { * @param address The address to make the call to. * @param extras Bundle of extras to use with the call. */ + @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void placeCall(Uri address, Bundle extras) { ITelecomService service = getTelecomService(); if (service != null) { diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java index 0b43666a5453..8085db72fba5 100644 --- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java +++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java @@ -31,5 +31,7 @@ public class CameraActivity extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.camera_activity); Log.i(TAG, "Activity created"); + Log.i(TAG, "Source: " + + getIntent().getStringExtra("com.android.systemui.camera_launch_source")); } } diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java index 530fe0063954..242d3b2c2a98 100644 --- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java +++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java @@ -17,6 +17,7 @@ package com.google.android.test.cameraprewarm; import android.app.Activity; +import android.graphics.Camera; import android.os.Bundle; import android.util.Log; import android.view.WindowManager; @@ -31,5 +32,7 @@ public class SecureCameraActivity extends Activity { setContentView(R.layout.camera_activity); getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); Log.i(CameraActivity.TAG, "Activity created"); + Log.i(CameraActivity.TAG, "Source: " + + getIntent().getStringExtra("com.android.systemui.camera_launch_source")); } } |