From 3d1aad64754828b0b5f98f2499f125fd4c2b9fbc Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Tue, 20 Jun 2017 16:10:44 -0400 Subject: [PATCH] Fix mobile signal icon when in airplane mode 1. Empty state was drawing a line too thing and not dark enough to be seen. 2. Airplane mode should be the slashed, full signal, not the empty one Going into airplane mode now draws the full signal, lighter than normal, with a slash. And the empty state now has a thicker line. Test: runtest systemui Fixes: 62794461 Change-Id: Ic5e40d2e0f6ebe0d270129f10883a1fcb146d717 --- packages/SystemUI/res/values/dimens.xml | 3 + .../systemui/qs/tiles/CellularTile.java | 6 +- .../statusbar/phone/SignalDrawable.java | 106 +++++++++++++++++- .../policy/MobileSignalController.java | 4 + 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4245b1183e08c..f66a09e04192a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -776,4 +776,7 @@ 6dp + + 2dp + diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index b52414eeda348..fbcdf1acfc6fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -140,7 +140,11 @@ public class CellularTile extends QSTileImpl { state.value = mDataController.isMobileDataSupported() && mDataController.isMobileDataEnabled(); state.icon = new SignalIcon(cb.mobileSignalIconId); - state.state = Tile.STATE_ACTIVE; + if (cb.airplaneModeEnabled) { + state.state = Tile.STATE_INACTIVE; + } else { + state.state = Tile.STATE_ACTIVE; + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java index 0a638d84cb4a3..983a796153045 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SignalDrawable.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Path; @@ -28,6 +29,7 @@ import android.graphics.Path.Direction; import android.graphics.Path.FillType; import android.graphics.Path.Op; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Handler; import android.util.LayoutDirection; @@ -64,6 +66,7 @@ public class SignalDrawable extends Drawable { private static final int STATE_EMPTY = 1; private static final int STATE_CUT = 2; private static final int STATE_CARRIER_CHANGE = 3; + private static final int STATE_AIRPLANE = 4; private static final long DOT_DELAY = 1000; @@ -82,6 +85,13 @@ public class SignalDrawable extends Drawable { {-1.9f / VIEWPORT, -1.9f / VIEWPORT}, }; + // The easiest way to understand this is as if we set Style.STROKE and draw the triangle, + // but that is only theoretically right. Instead, draw the triangle and clip out a smaller + // one inset by this amount. + private final float mEmptyStrokeWidth; + private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f); + private final float mEmptyDiagInset; // == mEmptyStrokeWidth * INV_TAN + private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int mDarkModeBackgroundColor; @@ -91,6 +101,10 @@ public class SignalDrawable extends Drawable { private final Path mFullPath = new Path(); private final Path mForegroundPath = new Path(); private final Path mXPath = new Path(); + // Cut out when STATE_EMPTY + private final Path mCutPath = new Path(); + // Draws the slash when in airplane mode + private final SlashArtist mSlash = new SlashArtist(); private final Handler mHandler; private float mOldDarkIntensity = -1; private float mNumLevels = 1; @@ -111,6 +125,12 @@ public class SignalDrawable extends Drawable { mLightModeFillColor = Utils.getDefaultColor(context, R.color.light_mode_icon_color_dual_tone_fill); mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size); + + // mCutPath parameters + mEmptyStrokeWidth = context.getResources() + .getDimensionPixelSize(R.dimen.mobile_signal_empty_strokewidth); + mEmptyDiagInset = mEmptyStrokeWidth * INV_TAN; + mHandler = new Handler(); setDarkIntensity(0); } @@ -208,7 +228,7 @@ public class SignalDrawable extends Drawable { mFullPath.setFillType(FillType.WINDING); float width = getBounds().width(); float height = getBounds().height(); - float padding = (PAD * width); + float padding = Math.round(PAD * width); mFullPath.moveTo(width - padding, height - padding); mFullPath.lineTo(width - padding, padding); mFullPath.lineTo(padding, height - padding); @@ -241,10 +261,27 @@ public class SignalDrawable extends Drawable { mFullPath.rLineTo(0, cut); } - mPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); - mForegroundPaint.setStyle(mState == STATE_EMPTY ? Style.STROKE : Style.FILL); + if (mState == STATE_EMPTY) { + // Cut out a smaller triangle from the center of mFullPath + mCutPath.reset(); + mCutPath.setFillType(FillType.WINDING); + mCutPath.moveTo(width - padding - mEmptyStrokeWidth, + height - padding - mEmptyStrokeWidth); + mCutPath.lineTo(width - padding - mEmptyStrokeWidth, padding + mEmptyDiagInset); + mCutPath.lineTo(padding + mEmptyDiagInset, height - padding - mEmptyStrokeWidth); + mCutPath.lineTo(width - padding - mEmptyStrokeWidth, + height - padding - mEmptyStrokeWidth); - if (mState != STATE_CARRIER_CHANGE) { + // In empty state, draw the full path as the foreground paint + mForegroundPath.set(mFullPath); + mFullPath.reset(); + mForegroundPath.op(mCutPath, Path.Op.DIFFERENCE); + } else if (mState == STATE_AIRPLANE) { + // Airplane mode is slashed, full-signal + mForegroundPath.set(mFullPath); + mFullPath.reset(); + mSlash.draw((int) height, (int) width, canvas, mForegroundPaint); + } else if (mState != STATE_CARRIER_CHANGE) { mForegroundPath.reset(); int sigWidth = Math.round(calcFit(mLevel / (mNumLevels - 1)) * (width - 2 * padding)); mForegroundPath.addRect(padding, padding, padding + sigWidth, height - padding, @@ -354,4 +391,65 @@ public class SignalDrawable extends Drawable { public static int getEmptyState(int numLevels) { return (STATE_EMPTY << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); } + + public static int getAirplaneModeState(int numLevels) { + return (STATE_AIRPLANE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); + } + + private final class SlashArtist { + // These values are derived in un-rotated (vertical) orientation + private static final float SLASH_WIDTH = 1.8384776f; + private static final float SLASH_HEIGHT = 22f; + private static final float CENTER_X = 10.65f; + private static final float CENTER_Y = 15.869239f; + private static final float SCALE = 24f; + + // Bottom is derived during animation + private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE; + private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE; + private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE; + private static final float BOTTOM = (CENTER_Y + (SLASH_HEIGHT / 2)) / SCALE; + // Draw the slash washington-monument style; rotate to no-u-turn style + private static final float ROTATION = -45f; + + private final Path mPath = new Path(); + private final RectF mSlashRect = new RectF(); + + void draw(int height, int width, @NonNull Canvas canvas, Paint paint) { + Matrix m = new Matrix(); + updateRect( + scale(LEFT, width), + scale(TOP, height), + scale(RIGHT, width), + scale(BOTTOM, height)); + + mPath.reset(); + // Draw the slash vertically + mPath.addRect(mSlashRect, Direction.CW); + m.setRotate(ROTATION, width / 2, height / 2); + mPath.transform(m); + canvas.drawPath(mPath, paint); + + // Rotate back to vertical, and draw the cut-out rect next to this one + m.setRotate(-ROTATION, width / 2, height / 2); + mPath.transform(m); + m.setTranslate(mSlashRect.width(), 0); + mPath.transform(m); + mPath.addRect(mSlashRect, Direction.CW); + m.setRotate(ROTATION, width / 2, height / 2); + mPath.transform(m); + canvas.clipOutPath(mPath); + } + + void updateRect(float left, float top, float right, float bottom) { + mSlashRect.left = left; + mSlashRect.top = top; + mSlashRect.right = right; + mSlashRect.bottom = bottom; + } + + private float scale(float frac, int width) { + return frac * width; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 67b5596e34c94..efce87177faa8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -254,6 +254,10 @@ public class MobileSignalController extends SignalController< @Override public int getQsCurrentIconId() { + if (mCurrentState.airplaneMode) { + return SignalDrawable.getAirplaneModeState(getNumLevels()); + } + return getCurrentIconId(); }