Merge "Update SignalDrawable." into qt-dev

This commit is contained in:
TreeHugger Robot
2019-05-06 17:47:51 +00:00
committed by Android (Google) Code Review
23 changed files with 432 additions and 416 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2019 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
-->
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:minLevel="0" android:maxLevel="0" android:drawable="@drawable/ic_signal_cellular_0_4_bar" />
<item android:minLevel="1" android:maxLevel="1" android:drawable="@drawable/ic_signal_cellular_1_4_bar" />
<item android:minLevel="2" android:maxLevel="2" android:drawable="@drawable/ic_signal_cellular_2_4_bar" />
<item android:minLevel="3" android:maxLevel="3" android:drawable="@drawable/ic_signal_cellular_3_4_bar" />
<item android:minLevel="4" android:maxLevel="4" android:drawable="@drawable/ic_signal_cellular_4_4_bar" />
<item android:minLevel="10" android:maxLevel="10" android:drawable="@drawable/ic_signal_cellular_0_5_bar" />
<item android:minLevel="11" android:maxLevel="11" android:drawable="@drawable/ic_signal_cellular_1_5_bar" />
<item android:minLevel="12" android:maxLevel="12" android:drawable="@drawable/ic_signal_cellular_2_5_bar" />
<item android:minLevel="13" android:maxLevel="13" android:drawable="@drawable/ic_signal_cellular_3_5_bar" />
<item android:minLevel="14" android:maxLevel="14" android:drawable="@drawable/ic_signal_cellular_4_5_bar" />
<item android:minLevel="15" android:maxLevel="15" android:drawable="@drawable/ic_signal_cellular_5_5_bar" />
</level-list>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 11 13 L 2 22 L 11 22 Z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M8.72,15.28,2,22H8.72V15.28Z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 13 11 L 2 22 L 13 22 Z" />
</vector>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 11.45 12.55 L 2 22 L 11.45 22 L 11.45 12.55 Z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 2 22 L 16 22 L 16 21 L 16 20 L 16 11 L 16 10 L 16 8 Z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 14.96 9.04 L 2 22 L 14.96 22 L 14.96 9.04 Z" />
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M22,2L2,22h20V2L22,2z" />
</vector>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 18.48 5.52 L 2 22 L 18.48 22 L 18.48 5.52 Z" />
</vector>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M22,2L2,22h20V2L22,2z" />
</vector>

View File

@@ -1410,6 +1410,7 @@
<java-symbol type="drawable" name="ic_signal_wifi_transient_animation" />
<java-symbol type="drawable" name="ic_hotspot_transient_animation" />
<java-symbol type="drawable" name="ic_bluetooth_transient_animation" />
<java-symbol type="drawable" name="ic_signal_cellular" />
<java-symbol type="drawable" name="stat_notify_rssi_in_range" />
<java-symbol type="drawable" name="stat_sys_gps_on" />
<java-symbol type="drawable" name="stat_sys_tether_wifi" />

View File

@@ -35,4 +35,8 @@
<color name="bt_color_bg_5">#fdcfe8</color> <!-- Material Pink 100 -->
<color name="bt_color_bg_6">#e9d2fd</color> <!-- Material Purple 100 -->
<color name="bt_color_bg_7">#cbf0f8</color> <!-- Material Cyan 100 -->
<color name="dark_mode_icon_color_single_tone">#99000000</color>
<color name="light_mode_icon_color_single_tone">#ffffff</color>
</resources>

View File

@@ -88,8 +88,6 @@
<!-- SignalDrawable -->
<dimen name="signal_icon_size">15dp</dimen>
<!-- How far to inset the rounded edges -->
<dimen name="stat_sys_mobile_signal_circle_inset">0.9dp</dimen>
<!-- Size of nearby icon -->
<dimen name="bt_nearby_icon_size">24dp</dimen>

View File

@@ -19,25 +19,28 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Path.FillType;
import android.graphics.Path.Op;
import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableWrapper;
import android.os.Handler;
import android.telephony.SignalStrength;
import android.util.LayoutDirection;
import com.android.settingslib.R;
import com.android.settingslib.Utils;
public class SignalDrawable extends Drawable {
/**
* Drawable displaying a mobile cell signal indicator.
*/
public class SignalDrawable extends DrawableWrapper {
private static final String TAG = "SignalDrawable";
@@ -48,11 +51,7 @@ public class SignalDrawable extends Drawable {
private static final float CUT_OUT = 7.9f / VIEWPORT;
private static final float DOT_SIZE = 3f / VIEWPORT;
private static final float DOT_PADDING = 1f / VIEWPORT;
private static final float DOT_CUT_WIDTH = (DOT_SIZE * 3) + (DOT_PADDING * 5);
private static final float DOT_CUT_HEIGHT = (DOT_SIZE * 1) + (DOT_PADDING * 1);
private static final float[] FIT = {2.26f, -3.02f, 1.76f};
private static final float DOT_PADDING = 1.5f / VIEWPORT;
// All of these are masks to push all of the drawable state into one int for easy callbacks
// and flow through sysui.
@@ -61,11 +60,8 @@ public class SignalDrawable extends Drawable {
private static final int NUM_LEVEL_MASK = 0xff << NUM_LEVEL_SHIFT;
private static final int STATE_SHIFT = 16;
private static final int STATE_MASK = 0xff << STATE_SHIFT;
private static final int STATE_NONE = 0;
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;
@@ -84,76 +80,30 @@ public class SignalDrawable extends Drawable {
{-1.9f / VIEWPORT, -1.9f / VIEWPORT},
};
// Rounded corners are achieved by arcing a circle of radius `R` from its tangent points along
// the curve (curve ≡ triangle). On the top and left corners of the triangle, the tangents are
// as follows:
// 1) Along the straight lines (y = 0 and x = width):
// Ps = circleOffset + R
// 2) Along the diagonal line (y = x):
// Pd = √((Ps^2) / 2)
// or (remember: sin(π/4) ≈ 0.7071)
// Pd = (circleOffset + R - 0.7071, height - R - 0.7071)
// Where Pd is the (x,y) coords of the point that intersects the circle at the bottom
// left of the triangle
private static final float RADIUS_RATIO = 0.75f / 17f;
private static final float DIAG_OFFSET_MULTIPLIER = 0.707107f;
// How far the circle defining the corners is inset from the edges
private final float mAppliedCornerInset;
private static final float INV_TAN = 1f / (float) Math.tan(Math.PI / 8f);
private static final float CUT_WIDTH_DP = 1f / 12f;
// Where the top and left points of the triangle would be if not for rounding
private final PointF mVirtualTop = new PointF();
private final PointF mVirtualLeft = new PointF();
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final int mDarkModeBackgroundColor;
private final Paint mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final int mDarkModeFillColor;
private final int mLightModeBackgroundColor;
private final int mLightModeFillColor;
private final Path mFullPath = new Path();
private final Path mCutoutPath = 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;
private int mIntrinsicSize;
private int mLevel;
private int mState;
private boolean mVisible;
private float mDarkIntensity = -1;
private final int mIntrinsicSize;
private boolean mAnimating;
private int mCurrentDot;
public SignalDrawable(Context context) {
mDarkModeBackgroundColor =
Utils.getColorStateListDefaultColor(context,
R.color.dark_mode_icon_color_dual_tone_background);
mDarkModeFillColor =
Utils.getColorStateListDefaultColor(context,
R.color.dark_mode_icon_color_dual_tone_fill);
mLightModeBackgroundColor =
Utils.getColorStateListDefaultColor(context,
R.color.light_mode_icon_color_dual_tone_background);
mLightModeFillColor =
Utils.getColorStateListDefaultColor(context,
R.color.light_mode_icon_color_dual_tone_fill);
super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular));
mDarkModeFillColor = Utils.getColorStateListDefaultColor(context,
R.color.dark_mode_icon_color_single_tone);
mLightModeFillColor = Utils.getColorStateListDefaultColor(context,
R.color.light_mode_icon_color_single_tone);
mIntrinsicSize = context.getResources().getDimensionPixelSize(R.dimen.signal_icon_size);
mTransparentPaint.setColor(context.getColor(android.R.color.transparent));
mTransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mHandler = new Handler();
setDarkIntensity(0);
mAppliedCornerInset = context.getResources()
.getDimensionPixelSize(R.dimen.stat_sys_mobile_signal_circle_inset);
}
public void setIntrinsicSize(int size) {
mIntrinsicSize = size;
}
@Override
@@ -166,21 +116,8 @@ public class SignalDrawable extends Drawable {
return mIntrinsicSize;
}
public void setNumLevels(int levels) {
if (levels == mNumLevels) return;
mNumLevels = levels;
invalidateSelf();
}
private void setSignalState(int state) {
if (state == mState) return;
mState = state;
updateAnimation();
invalidateSelf();
}
private void updateAnimation() {
boolean shouldAnimate = (mState == STATE_CARRIER_CHANGE) && mVisible;
boolean shouldAnimate = isInState(STATE_CARRIER_CHANGE) && isVisible();
if (shouldAnimate == mAnimating) return;
mAnimating = shouldAnimate;
if (shouldAnimate) {
@@ -191,33 +128,33 @@ public class SignalDrawable extends Drawable {
}
@Override
protected boolean onLevelChange(int state) {
setNumLevels(getNumLevels(state));
setSignalState(getState(state));
int level = getLevel(state);
if (level != mLevel) {
mLevel = level;
invalidateSelf();
}
protected boolean onLevelChange(int packedState) {
super.onLevelChange(unpackLevel(packedState));
updateAnimation();
setTintList(ColorStateList.valueOf(mForegroundPaint.getColor()));
return true;
}
public void setColors(int background, int foreground) {
int colorBackground = mPaint.getColor();
int colorForeground = mForegroundPaint.getColor();
mPaint.setColor(background);
mForegroundPaint.setColor(foreground);
if (colorBackground != background || colorForeground != foreground) invalidateSelf();
private int unpackLevel(int packedState) {
int numBins = (packedState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT;
int levelOffset = numBins == (SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1) ? 10 : 0;
int level = (packedState & LEVEL_MASK);
return level + levelOffset;
}
public void setDarkIntensity(float darkIntensity) {
if (darkIntensity == mOldDarkIntensity) {
if (darkIntensity == mDarkIntensity) {
return;
}
mPaint.setColor(getBackgroundColor(darkIntensity));
mForegroundPaint.setColor(getFillColor(darkIntensity));
mOldDarkIntensity = darkIntensity;
invalidateSelf();
setTintList(ColorStateList.valueOf(getFillColor(darkIntensity)));
}
@Override
public void setTintList(ColorStateList tint) {
super.setTintList(tint);
int colorForeground = mForegroundPaint.getColor();
mForegroundPaint.setColor(tint.getDefaultColor());
if (colorForeground != mForegroundPaint.getColor()) invalidateSelf();
}
private int getFillColor(float darkIntensity) {
@@ -225,11 +162,6 @@ public class SignalDrawable extends Drawable {
darkIntensity, mLightModeFillColor, mDarkModeFillColor);
}
private int getBackgroundColor(float darkIntensity) {
return getColorForDarkIntensity(
darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
}
private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
}
@@ -242,6 +174,7 @@ public class SignalDrawable extends Drawable {
@Override
public void draw(@NonNull Canvas canvas) {
canvas.saveLayer(null, null);
final float width = getBounds().width();
final float height = getBounds().height();
@@ -252,113 +185,32 @@ public class SignalDrawable extends Drawable {
canvas.translate(width, 0);
canvas.scale(-1.0f, 1.0f);
}
mFullPath.reset();
mFullPath.setFillType(FillType.WINDING);
super.draw(canvas);
mCutoutPath.reset();
mCutoutPath.setFillType(FillType.WINDING);
final float padding = Math.round(PAD * width);
final float cornerRadius = RADIUS_RATIO * height;
// Offset from circle where the hypotenuse meets the circle
final float diagOffset = DIAG_OFFSET_MULTIPLIER * cornerRadius;
// 1 - Bottom right, above corner
mFullPath.moveTo(width - padding, height - padding - cornerRadius);
// 2 - Line to top right, below corner
mFullPath.lineTo(width - padding, padding + cornerRadius + mAppliedCornerInset);
// 3 - Arc to top right, on hypotenuse
mFullPath.arcTo(
width - padding - (2 * cornerRadius),
padding + mAppliedCornerInset,
width - padding,
padding + mAppliedCornerInset + (2 * cornerRadius),
0.f, -135.f, false
);
// 4 - Line to bottom left, on hypotenuse
mFullPath.lineTo(padding + mAppliedCornerInset + cornerRadius - diagOffset,
height - padding - cornerRadius - diagOffset);
// 5 - Arc to bottom left, on leg
mFullPath.arcTo(
padding + mAppliedCornerInset,
height - padding - (2 * cornerRadius),
padding + mAppliedCornerInset + ( 2 * cornerRadius),
height - padding,
-135.f, -135.f, false
);
// 6 - Line to bottom rght, before corner
mFullPath.lineTo(width - padding - cornerRadius, height - padding);
// 7 - Arc to beginning (bottom right, above corner)
mFullPath.arcTo(
width - padding - (2 * cornerRadius),
height - padding - (2 * cornerRadius),
width - padding,
height - padding,
90.f, -90.f, false
);
if (mState == STATE_CARRIER_CHANGE) {
float cutWidth = (DOT_CUT_WIDTH * width);
float cutHeight = (DOT_CUT_HEIGHT * width);
if (isInState(STATE_CARRIER_CHANGE)) {
float dotSize = (DOT_SIZE * height);
float dotPadding = (DOT_PADDING * height);
mFullPath.moveTo(width - padding, height - padding);
mFullPath.rLineTo(-cutWidth, 0);
mFullPath.rLineTo(0, -cutHeight);
mFullPath.rLineTo(cutWidth, 0);
mFullPath.rLineTo(0, cutHeight);
float dotSpacing = dotPadding * 2 + dotSize;
float dotSpacing = dotPadding + dotSize;
float x = width - padding - dotSize;
float y = height - padding - dotSize;
mForegroundPath.reset();
drawDot(mFullPath, mForegroundPath, x, y, dotSize, 2);
drawDot(mFullPath, mForegroundPath, x - dotSpacing, y, dotSize, 1);
drawDot(mFullPath, mForegroundPath, x - dotSpacing * 2, y, dotSize, 0);
} else if (mState == STATE_CUT) {
drawDotAndPadding(x, y, dotPadding, dotSize, 2);
drawDotAndPadding(x - dotSpacing, y, dotPadding, dotSize, 1);
drawDotAndPadding(x - dotSpacing * 2, y, dotPadding, dotSize, 0);
canvas.drawPath(mCutoutPath, mTransparentPaint);
canvas.drawPath(mForegroundPath, mForegroundPaint);
} else if (isInState(STATE_CUT)) {
float cut = (CUT_OUT * width);
mFullPath.moveTo(width - padding, height - padding);
mFullPath.rLineTo(-cut, 0);
mFullPath.rLineTo(0, -cut);
mFullPath.rLineTo(cut, 0);
mFullPath.rLineTo(0, cut);
}
if (mState == STATE_EMPTY) {
// Where the corners would be if this were a real triangle
mVirtualTop.set(
width - padding,
(padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius));
mVirtualLeft.set(
(padding + cornerRadius + mAppliedCornerInset) - (INV_TAN * cornerRadius),
height - padding);
final float cutWidth = CUT_WIDTH_DP * height;
final float cutDiagInset = cutWidth * INV_TAN;
// Cut out a smaller triangle from the center of mFullPath
mCutPath.reset();
mCutPath.setFillType(FillType.WINDING);
mCutPath.moveTo(width - padding - cutWidth, height - padding - cutWidth);
mCutPath.lineTo(width - padding - cutWidth, mVirtualTop.y + cutDiagInset);
mCutPath.lineTo(mVirtualLeft.x + cutDiagInset, height - padding - cutWidth);
mCutPath.lineTo(width - padding - cutWidth, height - padding - cutWidth);
// Draw empty state as only background
mForegroundPath.reset();
mFullPath.op(mCutPath, Path.Op.DIFFERENCE);
} else if (mState == STATE_AIRPLANE) {
// Airplane mode is slashed, fully drawn background
mForegroundPath.reset();
mSlash.draw((int) height, (int) width, canvas, mPaint);
} 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,
Direction.CW);
mForegroundPath.op(mFullPath, Op.INTERSECT);
}
canvas.drawPath(mFullPath, mPaint);
canvas.drawPath(mForegroundPath, mForegroundPaint);
if (mState == STATE_CUT) {
mCutoutPath.moveTo(width - padding, height - padding);
mCutoutPath.rLineTo(-cut, 0);
mCutoutPath.rLineTo(0, -cut);
mCutoutPath.rLineTo(cut, 0);
mCutoutPath.rLineTo(0, cut);
canvas.drawPath(mCutoutPath, mTransparentPaint);
mXPath.reset();
mXPath.moveTo(X_PATH[0][0] * width, X_PATH[0][1] * height);
for (int i = 1; i < X_PATH.length; i++) {
@@ -369,57 +221,37 @@ public class SignalDrawable extends Drawable {
if (isRtl) {
canvas.restore();
}
canvas.restore();
}
private void drawDot(Path fullPath, Path foregroundPath, float x, float y, float dotSize,
int i) {
Path p = (i == mCurrentDot) ? foregroundPath : fullPath;
p.addRect(x, y, x + dotSize, y + dotSize, Direction.CW);
}
// This is a fit line based on previous values of provided in assets, but if
// you look at the a plot of this actual fit, it makes a lot of sense, what it does
// is compress the areas that are very visually easy to see changes (the middle sections)
// and spread out the sections that are hard to see (each end of the icon).
// The current fit is cubic, but pretty easy to change the way the code is written (just add
// terms to the end of FIT).
private float calcFit(float v) {
float ret = 0;
float t = v;
for (int i = 0; i < FIT.length; i++) {
ret += FIT[i] * t;
t *= v;
private void drawDotAndPadding(float x, float y,
float dotPadding, float dotSize, int i) {
if (i == mCurrentDot) {
// Draw dot
mForegroundPath.addRect(x, y, x + dotSize, y + dotSize, Direction.CW);
// Draw dot padding
mCutoutPath.addRect(x - dotPadding, y - dotPadding, x + dotSize + dotPadding,
y + dotSize + dotPadding, Direction.CW);
}
return ret;
}
@Override
public int getAlpha() {
return mPaint.getAlpha();
}
@Override
public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
mPaint.setAlpha(alpha);
super.setAlpha(alpha);
mForegroundPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
super.setColorFilter(colorFilter);
mForegroundPaint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return 255;
}
@Override
public boolean setVisible(boolean visible, boolean restart) {
mVisible = visible;
boolean changed = super.setVisible(visible, restart);
updateAnimation();
return super.setVisible(visible, restart);
return changed;
}
private final Runnable mChangeDot = new Runnable() {
@@ -433,92 +265,33 @@ public class SignalDrawable extends Drawable {
}
};
public static int getLevel(int fullState) {
return fullState & LEVEL_MASK;
/**
* Returns whether this drawable is in the specified state.
*
* @param state must be one of {@link #STATE_CARRIER_CHANGE} or {@link #STATE_CUT}
*/
private boolean isInState(int state) {
return getState(getLevel()) == state;
}
public static int getState(int fullState) {
return (fullState & STATE_MASK) >> STATE_SHIFT;
}
public static int getNumLevels(int fullState) {
return (fullState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT;
}
public static int getState(int level, int numLevels, boolean cutOut) {
return ((cutOut ? STATE_CUT : 0) << STATE_SHIFT)
| (numLevels << NUM_LEVEL_SHIFT)
| level;
}
/** Returns the state representing empty mobile signal with the given number of levels. */
public static int getEmptyState(int numLevels) {
// TODO empty state == 0 state. does there need to be a new drawable for this?
return getState(0, numLevels, false);
}
/** Returns the state representing carrier change with the given number of levels. */
public static int getCarrierChangeState(int numLevels) {
return (STATE_CARRIER_CHANGE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT);
}
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 {
private static final float CORNER_RADIUS = 1f;
// 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();
final float radius = scale(CORNER_RADIUS, width);
updateRect(
scale(LEFT, width),
scale(TOP, height),
scale(RIGHT, width),
scale(BOTTOM, height));
mPath.reset();
// Draw the slash vertically
mPath.addRoundRect(mSlashRect, radius, radius, 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.addRoundRect(mSlashRect, radius, radius, 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;
}
}
}

View File

@@ -111,11 +111,9 @@
<color name="segmented_buttons_background">#14FFFFFF</color><!-- 8% white -->
<color name="dark_mode_icon_color_single_tone">#99000000</color>
<color name="dark_mode_icon_color_dual_tone_background">#3d000000</color>
<color name="dark_mode_icon_color_dual_tone_fill">#7a000000</color>
<color name="light_mode_icon_color_single_tone">#ffffff</color>
<color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
<color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2017 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.systemui.qs;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.widget.ImageView;
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import java.util.Objects;
// Exists to provide easy way to add sim icon to cell tile
// TODO Find a better way to handle this and remove it.
public class CellTileView extends SignalTileView {
private final SignalDrawable mSignalDrawable;
public CellTileView(Context context) {
super(context);
mSignalDrawable = new SignalDrawable(mContext);
mSignalDrawable.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
mSignalDrawable.setIntrinsicSize(context.getResources().getDimensionPixelSize(
R.dimen.qs_tile_icon_size));
}
protected void updateIcon(ImageView iv, State state, boolean allowAnimations) {
if (!(state.icon instanceof SignalIcon)) {
super.updateIcon(iv, state, allowAnimations);
return;
} else if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
mSignalDrawable.setLevel(((SignalIcon) state.icon).getState());
iv.setImageDrawable(mSignalDrawable);
iv.setTag(R.id.qs_icon_tag, state.icon);
}
}
public static class SignalIcon extends Icon {
private final int mState;
public SignalIcon(int state) {
mState = state;
}
public int getState() {
return mState;
}
@Override
public Drawable getDrawable(Context context) {
//TODO: Not the optimal solution to create this drawable
SignalDrawable d = new SignalDrawable(context);
d.setColors(QSTileImpl.getColorForState(context, Tile.STATE_UNAVAILABLE),
QSTileImpl.getColorForState(context, Tile.STATE_ACTIVE));
d.setLevel(getState());
return d;
}
}
}

View File

@@ -75,12 +75,11 @@ public class QSCarrier extends LinearLayout {
mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
if (state.visible) {
mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
mMobileRoaming.setImageTintList(ColorStateList.valueOf(
mDualToneHandler.getSingleColor(mColorForegroundIntensity)));
SignalDrawable d = new SignalDrawable(mContext);
d.setColors(mDualToneHandler.getBackgroundColor(mColorForegroundIntensity),
mDualToneHandler.getFillColor(mColorForegroundIntensity));
mMobileSignal.setImageDrawable(d);
ColorStateList colorStateList = ColorStateList.valueOf(
mDualToneHandler.getSingleColor(mColorForegroundIntensity));
mMobileRoaming.setImageTintList(colorStateList);
mMobileSignal.setImageDrawable(new SignalDrawable(mContext));
mMobileSignal.setImageTintList(colorStateList);
mMobileSignal.setImageLevel(state.mobileSignalIconId);
StringBuilder contentDescription = new StringBuilder();

View File

@@ -40,9 +40,7 @@ import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.qs.CellTileView;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -88,11 +86,6 @@ public class CellularTile extends QSTileImpl<SignalState> {
public void handleSetListening(boolean listening) {
}
@Override
public QSIconView createTileView(Context context) {
return new CellTileView(context);
}
@Override
public Intent getLongClickIntent() {
return getCellularSettingIntent();

View File

@@ -211,8 +211,8 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
if (!isInArea(area, this)) {
return;
}
mMobileDrawable.setColors(mDualToneHandler.getBackgroundColor(darkIntensity),
mDualToneHandler.getFillColor(darkIntensity));
mMobileDrawable.setTintList(
ColorStateList.valueOf(mDualToneHandler.getFillColor(darkIntensity)));
ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
mIn.setImageTintList(color);
mOut.setImageTintList(color);
@@ -237,8 +237,8 @@ public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
float intensity = color == Color.WHITE ? 0 : 1;
// We want the ability to change the theme from the one set by SignalDrawable in certain
// surfaces. In this way, we can pass a theme to the view.
mMobileDrawable.setColors(mDualToneHandler.getBackgroundColor(intensity),
mDualToneHandler.getFillColor(intensity));
mMobileDrawable.setTintList(
ColorStateList.valueOf(mDualToneHandler.getFillColor(intensity)));
mIn.setImageTintList(list);
mOut.setImageTintList(list);
mMobileType.setImageTintList(list);

View File

@@ -284,10 +284,6 @@ public class MobileSignalController extends SignalController<
@Override
public int getQsCurrentIconId() {
if (mCurrentState.airplaneMode) {
return SignalDrawable.getAirplaneModeState(getNumLevels());
}
return getCurrentIconId();
}

View File

@@ -1012,6 +1012,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
SignalStrength.NUM_SIGNAL_STRENGTH_BINS);
controller.getState().connected = controller.getState().level >= 0;
}
if (args.containsKey("inflate")) {
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
mMobileSignalControllers.valueAt(i).mInflateSignalStrengths =
"true".equals(args.getString("inflate"));
}
}
String activity = args.getString("activity");
if (activity != null) {
controller.getState().dataConnected = true;