Merge "QS: Improve dual tile labels."

This commit is contained in:
John Spurlock
2014-07-01 14:42:15 +00:00
committed by Android (Google) Code Review
7 changed files with 125 additions and 45 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask"
android:drawable="@android:color/white" />
</ripple>

View File

@@ -1,20 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
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
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.
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" >
<size
android:width="24.0dp"
android:height="24.0dp"/>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/spinner_mtrl_am_alpha"
android:tint="@color/qs_tile_text"
android:autoMirrored="true" />
<viewport
android:viewportWidth="48.0"
android:viewportHeight="48.0"/>
<path
android:fill="@color/qs_tile_text"
android:pathData="M14.0,20.0l10.0,10.0 10.0,-10.0z"/>
</vector>

View File

@@ -160,8 +160,9 @@
<dimen name="qs_tile_text_size">12sp</dimen>
<dimen name="qs_tile_divider_height">1dp</dimen>
<dimen name="qs_panel_padding">16dp</dimen>
<dimen name="qs_dual_tile_height">104dp</dimen>
<dimen name="qs_dual_tile_padding_below_divider">4dp</dimen>
<dimen name="qs_dual_tile_height">112dp</dimen>
<dimen name="qs_dual_tile_padding_vertical">8dp</dimen>
<dimen name="qs_dual_tile_padding_horizontal">6dp</dimen>
<dimen name="qs_tile_padding_top">16dp</dimen>
<dimen name="qs_tile_padding_below_icon">12dp</dimen>
<dimen name="qs_tile_padding_bottom">16dp</dimen>

View File

@@ -18,6 +18,5 @@
<dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
<drawable name="notification_material_bg">@*android:drawable/notification_material_bg</drawable>
<drawable name="spinner_mtrl_am_alpha">@*android:drawable/spinner_mtrl_am_alpha</drawable>
</resources>

View File

@@ -24,8 +24,12 @@ import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
import java.util.Objects;
/**
@@ -39,50 +43,77 @@ import java.util.Objects;
*/
public class QSDualTileLabel extends FrameLayout {
private static final String SPACING_TEXT = " ";
private final Context mContext;
private final TextView mFirstLine;
private final ImageView mFirstLineCaret;
private final TextView mSecondLine;
private final int mHorizontalPaddingPx;
private String mText;
public QSDualTileLabel(Context context) {
super(context);
mContext = context;
mHorizontalPaddingPx = mContext.getResources()
.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_horizontal);
mFirstLine = initTextView();
mFirstLine.setPadding(mHorizontalPaddingPx, 0, 0, 0);
final LinearLayout firstLineLayout = new LinearLayout(mContext);
firstLineLayout.setPadding(0, 0, 0, 0);
firstLineLayout.setOrientation(LinearLayout.HORIZONTAL);
firstLineLayout.setClickable(false);
firstLineLayout.setBackground(null);
firstLineLayout.addView(mFirstLine);
mFirstLineCaret = new ImageView(mContext);
mFirstLineCaret.setScaleType(ImageView.ScaleType.MATRIX);
mFirstLineCaret.setClickable(false);
firstLineLayout.addView(mFirstLineCaret);
addView(firstLineLayout, newFrameLayoutParams());
mSecondLine = initTextView();
mSecondLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
mSecondLine.setEllipsize(TruncateAt.END);
mSecondLine.setVisibility(GONE);
addView(mSecondLine, newFrameLayoutParams());
addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if ((oldRight - oldLeft) != (right - left)) {
updateText();
rescheduleUpdateText();
}
}
});
}
public void setFirstLineBackground(Drawable d) {
mFirstLine.setBackground(d);
private static LayoutParams newFrameLayoutParams() {
final LayoutParams lp =
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
return lp;
}
public void setFirstLineCaret(Drawable d) {
mFirstLineCaret.setImageDrawable(d);
if (d != null) {
final int h = d.getIntrinsicHeight();
final LayoutParams lp = (LayoutParams) mSecondLine.getLayoutParams();
lp.topMargin = d.getIntrinsicHeight() * 3 / 4;
lp.topMargin = h * 4 / 5;
mSecondLine.setLayoutParams(lp);
mFirstLine.setMinHeight(h);
}
}
private TextView initTextView() {
final TextView tv = new TextView(mContext);
tv.setPadding(0, 0, 0, 0);
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setSingleLine(true);
tv.setClickable(false);
tv.setBackground(null);
final LayoutParams lp =
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
addView(tv, lp);
return tv;
}
@@ -90,7 +121,7 @@ public class QSDualTileLabel extends FrameLayout {
final String newText = text == null ? null : text.toString().trim();
if (Objects.equals(newText, mText)) return;
mText = newText;
updateText();
rescheduleUpdateText();
}
public String getText() {
@@ -100,16 +131,24 @@ public class QSDualTileLabel extends FrameLayout {
public void setTextSize(int unit, float size) {
mFirstLine.setTextSize(unit, size);
mSecondLine.setTextSize(unit, size);
rescheduleUpdateText();
}
public void setTextColor(int color) {
mFirstLine.setTextColor(color);
mSecondLine.setTextColor(color);
rescheduleUpdateText();
}
public void setTypeface(Typeface tf) {
mFirstLine.setTypeface(tf);
mSecondLine.setTypeface(tf);
rescheduleUpdateText();
}
private void rescheduleUpdateText() {
removeCallbacks(mUpdateText);
post(mUpdateText);
}
private void updateText() {
@@ -117,14 +156,16 @@ public class QSDualTileLabel extends FrameLayout {
if (TextUtils.isEmpty(mText)) {
mFirstLine.setText(null);
mSecondLine.setText(null);
mSecondLine.setVisibility(GONE);
return;
}
final float maxWidth = getWidth() - mFirstLine.getBackground().getIntrinsicWidth()
final float maxWidth = getWidth() - mFirstLineCaret.getWidth() - mHorizontalPaddingPx
- getPaddingLeft() - getPaddingRight();
float width = mFirstLine.getPaint().measureText(mText + SPACING_TEXT);
float width = mFirstLine.getPaint().measureText(mText);
if (width <= maxWidth) {
mFirstLine.setText(mText + SPACING_TEXT);
mFirstLine.setText(mText);
mSecondLine.setText(null);
mSecondLine.setVisibility(GONE);
return;
}
final int n = mText.length();
@@ -132,23 +173,32 @@ public class QSDualTileLabel extends FrameLayout {
boolean inWhitespace = false;
int i = 0;
for (i = 1; i < n; i++) {
width = mFirstLine.getPaint().measureText(mText.substring(0, i));
final boolean done = width > maxWidth;
if (Character.isWhitespace(mText.charAt(i))) {
if (!inWhitespace) {
if (!inWhitespace && !done) {
lastWordBoundary = i;
}
inWhitespace = true;
} else {
inWhitespace = false;
}
width = mFirstLine.getPaint().measureText(mText.substring(0, i) + SPACING_TEXT);
if (width > maxWidth) {
if (done) {
break;
}
}
if (lastWordBoundary == -1) {
lastWordBoundary = i - 1;
}
mFirstLine.setText(mText.substring(0, lastWordBoundary) + SPACING_TEXT);
mFirstLine.setText(mText.substring(0, lastWordBoundary));
mSecondLine.setText(mText.substring(lastWordBoundary).trim());
mSecondLine.setVisibility(VISIBLE);
}
private final Runnable mUpdateText = new Runnable() {
@Override
public void run() {
updateText();
}
};
}

View File

@@ -48,6 +48,7 @@ public class QSPanel extends ViewGroup {
private int mLargeCellWidth;
private int mLargeCellHeight;
private int mPanelPaddingBottom;
private int mDualTileUnderlap;
private boolean mExpanded;
private TileRecord mDetailRecord;
@@ -82,6 +83,7 @@ public class QSPanel extends ViewGroup {
mLargeCellHeight = res.getDimensionPixelSize(R.dimen.qs_dual_tile_height);
mLargeCellWidth = (int)(mLargeCellHeight * TILE_ASPECT);
mPanelPaddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
mDualTileUnderlap = res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
if (mColumns != columns) {
mColumns = columns;
postInvalidate();
@@ -243,7 +245,7 @@ public class QSPanel extends ViewGroup {
private int getRowTop(int row) {
if (row <= 0) return 0;
return mLargeCellHeight + (row - 1) * mCellHeight;
return mLargeCellHeight - mDualTileUnderlap + (row - 1) * mCellHeight;
}
private int getColumnCount(int row) {

View File

@@ -26,7 +26,6 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -50,7 +49,7 @@ public class QSTileView extends ViewGroup {
private final int mTileSpacingPx;
private final int mTilePaddingTopPx;
private final int mTilePaddingBelowIconPx;
private final int mDualTilePaddingBelowDividerPx;
private final int mDualTileVerticalPaddingPx;
private TextView mLabel;
private QSDualTileLabel mDualLabel;
@@ -68,8 +67,8 @@ public class QSTileView extends ViewGroup {
mTileSpacingPx = res.getDimensionPixelSize(R.dimen.qs_tile_spacing);
mTilePaddingTopPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_top);
mTilePaddingBelowIconPx = res.getDimensionPixelSize(R.dimen.qs_tile_padding_below_icon);
mDualTilePaddingBelowDividerPx =
res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_below_divider);
mDualTileVerticalPaddingPx =
res.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_vertical);
recreateLabel();
setClipChildren(false);
@@ -100,12 +99,12 @@ public class QSTileView extends ViewGroup {
}
final Resources res = mContext.getResources();
if (mDual) {
final Context c = new ContextThemeWrapper(mContext, R.style.BorderlessButton_Tiny);
mDualLabel = new QSDualTileLabel(c);
mDualLabel = new QSDualTileLabel(mContext);
mDualLabel.setId(android.R.id.title);
mDualLabel.setFirstLineBackground(res.getDrawable(R.drawable.qs_dual_tile_caret));
mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect);
mDualLabel.setFirstLineCaret(res.getDrawable(R.drawable.qs_dual_tile_caret));
mDualLabel.setTextColor(res.getColor(R.color.qs_tile_text));
mDualLabel.setPadding(0, mDualTilePaddingBelowDividerPx, 0, 0);
mDualLabel.setPadding(0, mDualTileVerticalPaddingPx, 0, mDualTileVerticalPaddingPx);
mDualLabel.setTypeface(CONDENSED);
mDualLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
res.getDimensionPixelSize(R.dimen.qs_tile_text_size));