Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java +221 −2 Original line number Original line Diff line number Diff line Loading @@ -16,9 +16,17 @@ package com.android.systemui.statusbar.phone; package com.android.systemui.statusbar.phone; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.annotation.NonNull; import android.content.Context; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.util.FloatProperty; import android.util.MathUtils; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.View; import android.view.WindowManager; import android.view.WindowManager; Loading @@ -27,6 +35,71 @@ import com.android.systemui.R; public class NavigationBarEdgePanel extends View { public class NavigationBarEdgePanel extends View { private static final String TAG = "NavigationBarEdgePanel"; private static final String TAG = "NavigationBarEdgePanel"; // TODO: read from resources once drawing is finalized. private static final boolean SHOW_PROTECTION_STROKE = true; private static final int PROTECTION_COLOR = 0xffc0c0c0; private static final int STROKE_COLOR = 0xffe5e5e5; private static final int PROTECTION_WIDTH_PX = 4; private static final int BASE_EXTENT = 32; private static final int ARROW_HEIGHT_DP = 32; private static final int POINT_EXTENT_DP = 8; private static final int ARROW_THICKNESS_DP = 4; private static final float TRACK_LENGTH_MULTIPLIER = 1.5f; private static final float START_POINTING_RATIO = 0.3f; private static final float POINTEDNESS_BEFORE_SNAP_RATIO = 0.4f; private static final int ANIM_DURATION_MS = 150; private final Paint mPaint = new Paint(); private final Paint mProtectionPaint = new Paint(); private final ObjectAnimator mEndAnimator; private final ObjectAnimator mLegAnimator; private final float mDensity; private final float mBaseExtent; private final float mPointExtent; private final float mHeight; private final float mStrokeThickness; private final boolean mIsLeftPanel; private float mStartY; private float mStartX; private boolean mGestureDetected; private boolean mArrowsPointLeft; private float mGestureLength; private float mLegProgress; private float mDragProgress; // How much the "legs" of the back arrow have proceeded from being a line to an arrow. private static final FloatProperty<NavigationBarEdgePanel> LEG_PROGRESS = new FloatProperty<NavigationBarEdgePanel>("legProgress") { @Override public void setValue(NavigationBarEdgePanel object, float value) { object.setLegProgress(value); } @Override public Float get(NavigationBarEdgePanel object) { return object.getLegProgress(); } }; // How far across the view the arrow should be drawn. private static final FloatProperty<NavigationBarEdgePanel> DRAG_PROGRESS = new FloatProperty<NavigationBarEdgePanel>("dragProgress") { @Override public void setValue(NavigationBarEdgePanel object, float value) { object.setDragProgress(value); } @Override public Float get(NavigationBarEdgePanel object) { return object.getDragProgress(); } }; public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height, public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height, int gravity) { int gravity) { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, Loading @@ -40,13 +113,43 @@ public class NavigationBarEdgePanel extends View { lp.setTitle(TAG + context.getDisplayId()); lp.setTitle(TAG + context.getDisplayId()); lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel); lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel); lp.windowAnimations = 0; lp.windowAnimations = 0; NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context); NavigationBarEdgePanel panel = new NavigationBarEdgePanel( context, (gravity & Gravity.LEFT) != 0); panel.setLayoutParams(lp); panel.setLayoutParams(lp); return panel; return panel; } } private NavigationBarEdgePanel(Context context) { private NavigationBarEdgePanel(Context context, boolean isLeftPanel) { super(context); super(context); mEndAnimator = ObjectAnimator.ofFloat(this, DRAG_PROGRESS, 1f); mEndAnimator.setAutoCancel(true); mEndAnimator.setDuration(ANIM_DURATION_MS); mLegAnimator = ObjectAnimator.ofFloat(this, LEG_PROGRESS, 1f); mLegAnimator.setAutoCancel(true); mLegAnimator.setDuration(ANIM_DURATION_MS); mDensity = context.getResources().getDisplayMetrics().density; mBaseExtent = dp(BASE_EXTENT); mHeight = dp(ARROW_HEIGHT_DP); mPointExtent = dp(POINT_EXTENT_DP); mStrokeThickness = dp(ARROW_THICKNESS_DP); mPaint.setStrokeWidth(mStrokeThickness); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(STROKE_COLOR); mPaint.setAntiAlias(true); mProtectionPaint.setStrokeWidth(mStrokeThickness + PROTECTION_WIDTH_PX); mProtectionPaint.setStrokeCap(Paint.Cap.ROUND); mProtectionPaint.setColor(PROTECTION_COLOR); mProtectionPaint.setAntiAlias(true); // Both panels arrow point the same way mArrowsPointLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR; mIsLeftPanel = isLeftPanel; } } public void setWindowFlag(int flags, boolean enable) { public void setWindowFlag(int flags, boolean enable) { Loading @@ -62,6 +165,58 @@ public class NavigationBarEdgePanel extends View { updateLayout(lp); updateLayout(lp); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN : { show(event.getX(), event.getY()); break; } case MotionEvent.ACTION_MOVE: { handleNewSwipePoint(event.getX()); break; } // Fall through case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { hide(); break; } } return false; } @Override protected void onDraw(Canvas canvas) { float edgeOffset = mBaseExtent * mDragProgress - mStrokeThickness; float animatedOffset = mPointExtent * mLegProgress; canvas.save(); canvas.translate( mIsLeftPanel ? edgeOffset : getWidth() - edgeOffset, mStartY - mHeight * 0.5f); float outsideX = mArrowsPointLeft ? animatedOffset : 0; float middleX = mArrowsPointLeft ? 0 : animatedOffset; if (SHOW_PROTECTION_STROKE) { canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mProtectionPaint); canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mProtectionPaint); } canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mPaint); canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mPaint); canvas.restore(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // TODO: read the gesture length from the nav controller. mGestureLength = getWidth(); } public void setDimensions(int width, int height) { public void setDimensions(int width, int height) { final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); if (lp.width != width || lp.height != height) { if (lp.width != width || lp.height != height) { Loading @@ -71,8 +226,72 @@ public class NavigationBarEdgePanel extends View { } } } } private void setLegProgress(float progress) { mLegProgress = progress; invalidate(); } private float getLegProgress() { return mLegProgress; } private void setDragProgress(float dragProgress) { mDragProgress = dragProgress; invalidate(); } private float getDragProgress() { return mDragProgress; } private void hide() { animate().alpha(0f).setDuration(ANIM_DURATION_MS); } private void show(float x, float y) { mEndAnimator.cancel(); mLegAnimator.cancel(); setLegProgress(0f); setDragProgress(0f); setAlpha(1f); float halfHeight = mHeight * 0.5f; mStartY = MathUtils.constrain(y, halfHeight, getHeight() - halfHeight); mStartX = x; } private void handleNewSwipePoint(float x) { float dist = MathUtils.abs(x - mStartX); setDragProgress(MathUtils.constrainedMap( 0, 1.0f, 0, mGestureLength * TRACK_LENGTH_MULTIPLIER, dist)); if (dist < mGestureLength) { setLegProgress(MathUtils.constrainedMap( 0f, POINTEDNESS_BEFORE_SNAP_RATIO, mGestureLength * START_POINTING_RATIO, mGestureLength, dist)); mGestureDetected = false; } else { if (!mGestureDetected) { performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); mGestureDetected = true; mLegAnimator.setFloatValues(1f); mLegAnimator.start(); } } } private void updateLayout(WindowManager.LayoutParams lp) { private void updateLayout(WindowManager.LayoutParams lp) { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); wm.updateViewLayout(this, lp); wm.updateViewLayout(this, lp); } } private float dp(float dp) { return mDensity * dp; } } } packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -1227,10 +1227,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav .getSystemService(Context.WINDOW_SERVICE); .getSystemService(Context.WINDOW_SERVICE); int width = mPrototypeController.getEdgeSensitivityWidth(); int width = mPrototypeController.getEdgeSensitivityWidth(); int height = mPrototypeController.getEdgeSensitivityHeight(); int height = mPrototypeController.getEdgeSensitivityHeight(); // Explicitly left and right, not start and end as this is device relative. mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, Gravity.START | Gravity.BOTTOM); Gravity.LEFT | Gravity.BOTTOM); mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, Gravity.END | Gravity.BOTTOM); Gravity.RIGHT | Gravity.BOTTOM); mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener); wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams()); wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams()); Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java +221 −2 Original line number Original line Diff line number Diff line Loading @@ -16,9 +16,17 @@ package com.android.systemui.statusbar.phone; package com.android.systemui.statusbar.phone; import android.animation.ObjectAnimator; import android.annotation.NonNull; import android.annotation.NonNull; import android.content.Context; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PixelFormat; import android.util.FloatProperty; import android.util.MathUtils; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.View; import android.view.WindowManager; import android.view.WindowManager; Loading @@ -27,6 +35,71 @@ import com.android.systemui.R; public class NavigationBarEdgePanel extends View { public class NavigationBarEdgePanel extends View { private static final String TAG = "NavigationBarEdgePanel"; private static final String TAG = "NavigationBarEdgePanel"; // TODO: read from resources once drawing is finalized. private static final boolean SHOW_PROTECTION_STROKE = true; private static final int PROTECTION_COLOR = 0xffc0c0c0; private static final int STROKE_COLOR = 0xffe5e5e5; private static final int PROTECTION_WIDTH_PX = 4; private static final int BASE_EXTENT = 32; private static final int ARROW_HEIGHT_DP = 32; private static final int POINT_EXTENT_DP = 8; private static final int ARROW_THICKNESS_DP = 4; private static final float TRACK_LENGTH_MULTIPLIER = 1.5f; private static final float START_POINTING_RATIO = 0.3f; private static final float POINTEDNESS_BEFORE_SNAP_RATIO = 0.4f; private static final int ANIM_DURATION_MS = 150; private final Paint mPaint = new Paint(); private final Paint mProtectionPaint = new Paint(); private final ObjectAnimator mEndAnimator; private final ObjectAnimator mLegAnimator; private final float mDensity; private final float mBaseExtent; private final float mPointExtent; private final float mHeight; private final float mStrokeThickness; private final boolean mIsLeftPanel; private float mStartY; private float mStartX; private boolean mGestureDetected; private boolean mArrowsPointLeft; private float mGestureLength; private float mLegProgress; private float mDragProgress; // How much the "legs" of the back arrow have proceeded from being a line to an arrow. private static final FloatProperty<NavigationBarEdgePanel> LEG_PROGRESS = new FloatProperty<NavigationBarEdgePanel>("legProgress") { @Override public void setValue(NavigationBarEdgePanel object, float value) { object.setLegProgress(value); } @Override public Float get(NavigationBarEdgePanel object) { return object.getLegProgress(); } }; // How far across the view the arrow should be drawn. private static final FloatProperty<NavigationBarEdgePanel> DRAG_PROGRESS = new FloatProperty<NavigationBarEdgePanel>("dragProgress") { @Override public void setValue(NavigationBarEdgePanel object, float value) { object.setDragProgress(value); } @Override public Float get(NavigationBarEdgePanel object) { return object.getDragProgress(); } }; public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height, public static NavigationBarEdgePanel create(@NonNull Context context, int width, int height, int gravity) { int gravity) { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height, Loading @@ -40,13 +113,43 @@ public class NavigationBarEdgePanel extends View { lp.setTitle(TAG + context.getDisplayId()); lp.setTitle(TAG + context.getDisplayId()); lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel); lp.accessibilityTitle = context.getString(R.string.nav_bar_edge_panel); lp.windowAnimations = 0; lp.windowAnimations = 0; NavigationBarEdgePanel panel = new NavigationBarEdgePanel(context); NavigationBarEdgePanel panel = new NavigationBarEdgePanel( context, (gravity & Gravity.LEFT) != 0); panel.setLayoutParams(lp); panel.setLayoutParams(lp); return panel; return panel; } } private NavigationBarEdgePanel(Context context) { private NavigationBarEdgePanel(Context context, boolean isLeftPanel) { super(context); super(context); mEndAnimator = ObjectAnimator.ofFloat(this, DRAG_PROGRESS, 1f); mEndAnimator.setAutoCancel(true); mEndAnimator.setDuration(ANIM_DURATION_MS); mLegAnimator = ObjectAnimator.ofFloat(this, LEG_PROGRESS, 1f); mLegAnimator.setAutoCancel(true); mLegAnimator.setDuration(ANIM_DURATION_MS); mDensity = context.getResources().getDisplayMetrics().density; mBaseExtent = dp(BASE_EXTENT); mHeight = dp(ARROW_HEIGHT_DP); mPointExtent = dp(POINT_EXTENT_DP); mStrokeThickness = dp(ARROW_THICKNESS_DP); mPaint.setStrokeWidth(mStrokeThickness); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setColor(STROKE_COLOR); mPaint.setAntiAlias(true); mProtectionPaint.setStrokeWidth(mStrokeThickness + PROTECTION_WIDTH_PX); mProtectionPaint.setStrokeCap(Paint.Cap.ROUND); mProtectionPaint.setColor(PROTECTION_COLOR); mProtectionPaint.setAntiAlias(true); // Both panels arrow point the same way mArrowsPointLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR; mIsLeftPanel = isLeftPanel; } } public void setWindowFlag(int flags, boolean enable) { public void setWindowFlag(int flags, boolean enable) { Loading @@ -62,6 +165,58 @@ public class NavigationBarEdgePanel extends View { updateLayout(lp); updateLayout(lp); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN : { show(event.getX(), event.getY()); break; } case MotionEvent.ACTION_MOVE: { handleNewSwipePoint(event.getX()); break; } // Fall through case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { hide(); break; } } return false; } @Override protected void onDraw(Canvas canvas) { float edgeOffset = mBaseExtent * mDragProgress - mStrokeThickness; float animatedOffset = mPointExtent * mLegProgress; canvas.save(); canvas.translate( mIsLeftPanel ? edgeOffset : getWidth() - edgeOffset, mStartY - mHeight * 0.5f); float outsideX = mArrowsPointLeft ? animatedOffset : 0; float middleX = mArrowsPointLeft ? 0 : animatedOffset; if (SHOW_PROTECTION_STROKE) { canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mProtectionPaint); canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mProtectionPaint); } canvas.drawLine(outsideX, 0, middleX, mHeight * 0.5f, mPaint); canvas.drawLine(middleX, mHeight * 0.5f, outsideX, mHeight, mPaint); canvas.restore(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // TODO: read the gesture length from the nav controller. mGestureLength = getWidth(); } public void setDimensions(int width, int height) { public void setDimensions(int width, int height) { final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams(); if (lp.width != width || lp.height != height) { if (lp.width != width || lp.height != height) { Loading @@ -71,8 +226,72 @@ public class NavigationBarEdgePanel extends View { } } } } private void setLegProgress(float progress) { mLegProgress = progress; invalidate(); } private float getLegProgress() { return mLegProgress; } private void setDragProgress(float dragProgress) { mDragProgress = dragProgress; invalidate(); } private float getDragProgress() { return mDragProgress; } private void hide() { animate().alpha(0f).setDuration(ANIM_DURATION_MS); } private void show(float x, float y) { mEndAnimator.cancel(); mLegAnimator.cancel(); setLegProgress(0f); setDragProgress(0f); setAlpha(1f); float halfHeight = mHeight * 0.5f; mStartY = MathUtils.constrain(y, halfHeight, getHeight() - halfHeight); mStartX = x; } private void handleNewSwipePoint(float x) { float dist = MathUtils.abs(x - mStartX); setDragProgress(MathUtils.constrainedMap( 0, 1.0f, 0, mGestureLength * TRACK_LENGTH_MULTIPLIER, dist)); if (dist < mGestureLength) { setLegProgress(MathUtils.constrainedMap( 0f, POINTEDNESS_BEFORE_SNAP_RATIO, mGestureLength * START_POINTING_RATIO, mGestureLength, dist)); mGestureDetected = false; } else { if (!mGestureDetected) { performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); mGestureDetected = true; mLegAnimator.setFloatValues(1f); mLegAnimator.start(); } } } private void updateLayout(WindowManager.LayoutParams lp) { private void updateLayout(WindowManager.LayoutParams lp) { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); wm.updateViewLayout(this, lp); wm.updateViewLayout(this, lp); } } private float dp(float dp) { return mDensity * dp; } } }
packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -1227,10 +1227,11 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav .getSystemService(Context.WINDOW_SERVICE); .getSystemService(Context.WINDOW_SERVICE); int width = mPrototypeController.getEdgeSensitivityWidth(); int width = mPrototypeController.getEdgeSensitivityWidth(); int height = mPrototypeController.getEdgeSensitivityHeight(); int height = mPrototypeController.getEdgeSensitivityHeight(); // Explicitly left and right, not start and end as this is device relative. mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, mLeftEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, Gravity.START | Gravity.BOTTOM); Gravity.LEFT | Gravity.BOTTOM); mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, mRightEdgePanel = NavigationBarEdgePanel.create(getContext(), width, height, Gravity.END | Gravity.BOTTOM); Gravity.RIGHT | Gravity.BOTTOM); mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mLeftEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener); mRightEdgePanel.setOnTouchListener(mEdgePanelTouchListener); wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams()); wm.addView(mLeftEdgePanel, mLeftEdgePanel.getLayoutParams()); Loading