diff --git a/res/layout/battery_history_detail.xml b/res/layout/battery_history_detail.xml
index b782e397c66..ea758655231 100644
--- a/res/layout/battery_history_detail.xml
+++ b/res/layout/battery_history_detail.xml
@@ -49,7 +49,7 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"/>
-
-
-
+
diff --git a/res/layout/usage_side_label.xml b/res/layout/usage_side_label.xml
new file mode 100644
index 00000000000..6c168806338
--- /dev/null
+++ b/res/layout/usage_side_label.xml
@@ -0,0 +1,20 @@
+
+
diff --git a/res/layout/usage_view.xml b/res/layout/usage_view.xml
new file mode 100644
index 00000000000..8e9c5802bbf
--- /dev/null
+++ b/res/layout/usage_view.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 5e7ee7e196c..acb6ec3effd 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -162,4 +162,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/com/android/settings/datausage/ChartDataUsagePreference.java b/src/com/android/settings/datausage/ChartDataUsagePreference.java
index f72d465e0db..ee074c03308 100644
--- a/src/com/android/settings/datausage/ChartDataUsagePreference.java
+++ b/src/com/android/settings/datausage/ChartDataUsagePreference.java
@@ -15,7 +15,6 @@
package com.android.settings.datausage;
import android.content.Context;
-import android.content.res.TypedArray;
import android.net.NetworkPolicy;
import android.net.NetworkStatsHistory;
import android.net.TrafficStats;
@@ -29,7 +28,7 @@ import android.util.AttributeSet;
import android.util.SparseIntArray;
import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settingslib.graph.UsageView;
+import com.android.settings.graph.UsageView;
public class ChartDataUsagePreference extends Preference {
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java
index c6f326f454d..3661467887b 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoryDetail.java
@@ -30,7 +30,7 @@ import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.fuelgauge.BatteryActiveView.BatteryActiveProvider;
-import com.android.settingslib.graph.UsageView;
+import com.android.settings.graph.UsageView;
public class BatteryHistoryDetail extends SettingsPreferenceFragment {
public static final String EXTRA_STATS = "stats";
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
index 04835344a7d..920f0e22fbc 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoryPreference.java
@@ -24,7 +24,7 @@ import android.util.AttributeSet;
import android.widget.TextView;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.R;
-import com.android.settingslib.graph.UsageView;
+import com.android.settings.graph.UsageView;
/**
* Custom preference for displaying power consumption as a bar and an icon on the left for the
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 3825218de47..6daf23b5bbc 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -34,7 +34,7 @@ import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.R;
import com.android.settings.Utils;
-import com.android.settingslib.graph.UsageView;
+import com.android.settings.graph.UsageView;
public class BatteryInfo {
diff --git a/src/com/android/settings/graph/BottomLabelLayout.java b/src/com/android/settings/graph/BottomLabelLayout.java
new file mode 100644
index 00000000000..45fab38bc3b
--- /dev/null
+++ b/src/com/android/settings/graph/BottomLabelLayout.java
@@ -0,0 +1,97 @@
+/*
+ * 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.settings.graph;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.support.annotation.VisibleForTesting;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.settingslib.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ *
+ * Main logic in this class comes from {@link android.support.v7.widget.ButtonBarLayout}.
+ * Compared with {@link android.support.v7.widget.ButtonBarLayout}, this layout won't reverse
+ * children's order and won't update the minimum height
+ */
+public class BottomLabelLayout extends LinearLayout {
+ private static final String TAG = "BottomLabelLayout";
+
+ public BottomLabelLayout(Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ final boolean isStacked = isStacked();
+ boolean needsRemeasure = false;
+
+ // If we're not stacked, make sure the measure spec is AT_MOST rather
+ // than EXACTLY. This ensures that we'll still get TOO_SMALL so that we
+ // know to stack the buttons.
+ final int initialWidthMeasureSpec;
+ if (!isStacked && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
+ initialWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
+
+ // We'll need to remeasure again to fill excess space.
+ needsRemeasure = true;
+ } else {
+ initialWidthMeasureSpec = widthMeasureSpec;
+ }
+
+ super.onMeasure(initialWidthMeasureSpec, heightMeasureSpec);
+ if (!isStacked) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & View.MEASURED_STATE_MASK;
+
+ if (measuredWidthState == View.MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+ // Measure again in the new orientation.
+ needsRemeasure = true;
+ }
+ }
+
+ if (needsRemeasure) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ }
+
+ @VisibleForTesting
+ void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.START : Gravity.BOTTOM);
+
+ final View spacer = findViewById(R.id.spacer);
+ if (spacer != null) {
+ spacer.setVisibility(stacked ? View.GONE : View.VISIBLE);
+ }
+ }
+
+ private boolean isStacked() {
+ return getOrientation() == LinearLayout.VERTICAL;
+ }
+}
diff --git a/src/com/android/settings/graph/UsageGraph.java b/src/com/android/settings/graph/UsageGraph.java
new file mode 100644
index 00000000000..37046c054c9
--- /dev/null
+++ b/src/com/android/settings/graph/UsageGraph.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2016 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.settings.graph;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.CornerPathEffect;
+import android.graphics.DashPathEffect;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Join;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.SparseIntArray;
+import android.util.TypedValue;
+import android.view.View;
+import com.android.settingslib.R;
+
+public class UsageGraph extends View {
+
+ private static final int PATH_DELIM = -1;
+
+ private final Paint mLinePaint;
+ private final Paint mFillPaint;
+ private final Paint mDottedPaint;
+
+ private final Drawable mDivider;
+ private final Drawable mTintedDivider;
+ private final int mDividerSize;
+
+ private final Path mPath = new Path();
+
+ // Paths in coordinates they are passed in.
+ private final SparseIntArray mPaths = new SparseIntArray();
+ // Paths in local coordinates for drawing.
+ private final SparseIntArray mLocalPaths = new SparseIntArray();
+ private final int mCornerRadius;
+
+ private int mAccentColor;
+ private boolean mShowProjection;
+ private boolean mProjectUp;
+
+ private float mMaxX = 100;
+ private float mMaxY = 100;
+
+ private float mMiddleDividerLoc = .5f;
+ private int mMiddleDividerTint = -1;
+ private int mTopDividerTint = -1;
+
+ public UsageGraph(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ final Resources resources = context.getResources();
+
+ mLinePaint = new Paint();
+ mLinePaint.setStyle(Style.STROKE);
+ mLinePaint.setStrokeCap(Cap.ROUND);
+ mLinePaint.setStrokeJoin(Join.ROUND);
+ mLinePaint.setAntiAlias(true);
+ mCornerRadius = resources.getDimensionPixelSize(R.dimen.usage_graph_line_corner_radius);
+ mLinePaint.setPathEffect(new CornerPathEffect(mCornerRadius));
+ mLinePaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.usage_graph_line_width));
+
+ mFillPaint = new Paint(mLinePaint);
+ mFillPaint.setStyle(Style.FILL);
+
+ mDottedPaint = new Paint(mLinePaint);
+ mDottedPaint.setStyle(Style.STROKE);
+ float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size);
+ float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval);
+ mDottedPaint.setStrokeWidth(dots * 3);
+ mDottedPaint.setPathEffect(new DashPathEffect(new float[] {dots, interval}, 0));
+ mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots));
+
+ TypedValue v = new TypedValue();
+ context.getTheme().resolveAttribute(com.android.internal.R.attr.listDivider, v, true);
+ mDivider = context.getDrawable(v.resourceId);
+ mTintedDivider = context.getDrawable(v.resourceId);
+ mDividerSize = resources.getDimensionPixelSize(R.dimen.usage_graph_divider_size);
+ }
+
+ void clearPaths() {
+ mPaths.clear();
+ }
+
+ void setMax(int maxX, int maxY) {
+ mMaxX = maxX;
+ mMaxY = maxY;
+ }
+
+ void setDividerLoc(int height) {
+ mMiddleDividerLoc = 1 - height / mMaxY;
+ }
+
+ void setDividerColors(int middleColor, int topColor) {
+ mMiddleDividerTint = middleColor;
+ mTopDividerTint = topColor;
+ }
+
+ public void addPath(SparseIntArray points) {
+ for (int i = 0; i < points.size(); i++) {
+ mPaths.put(points.keyAt(i), points.valueAt(i));
+ }
+ mPaths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM);
+ calculateLocalPaths();
+ postInvalidate();
+ }
+
+ void setAccentColor(int color) {
+ mAccentColor = color;
+ mLinePaint.setColor(mAccentColor);
+ updateGradient();
+ postInvalidate();
+ }
+
+ void setShowProjection(boolean showProjection, boolean projectUp) {
+ mShowProjection = showProjection;
+ mProjectUp = projectUp;
+ postInvalidate();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ updateGradient();
+ calculateLocalPaths();
+ }
+
+ private void calculateLocalPaths() {
+ if (getWidth() == 0) return;
+ mLocalPaths.clear();
+ int pendingXLoc = 0;
+ int pendingYLoc = PATH_DELIM;
+ for (int i = 0; i < mPaths.size(); i++) {
+ int x = mPaths.keyAt(i);
+ int y = mPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ if (i == mPaths.size() - 1 && pendingYLoc != PATH_DELIM) {
+ // Connect to the end of the graph.
+ mLocalPaths.put(pendingXLoc, pendingYLoc);
+ }
+ // Clear out any pending points.
+ pendingYLoc = PATH_DELIM;
+ mLocalPaths.put(pendingXLoc + 1, PATH_DELIM);
+ } else {
+ final int lx = getX(x);
+ final int ly = getY(y);
+ pendingXLoc = lx;
+ if (mLocalPaths.size() > 0) {
+ int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
+ int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
+ if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
+ pendingYLoc = ly;
+ continue;
+ }
+ }
+ mLocalPaths.put(lx, ly);
+ }
+ }
+ }
+
+ private boolean hasDiff(int x1, int x2) {
+ return Math.abs(x2 - x1) >= mCornerRadius;
+ }
+
+ private int getX(float x) {
+ return (int) (x / mMaxX * getWidth());
+ }
+
+ private int getY(float y) {
+ return (int) (getHeight() * (1 - (y / mMaxY)));
+ }
+
+ private void updateGradient() {
+ mFillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(),
+ getColor(mAccentColor, .2f), 0, TileMode.CLAMP));
+ }
+
+ private int getColor(int color, float alphaScale) {
+ return (color & (((int) (0xff * alphaScale) << 24) | 0xffffff));
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // Draw lines across the top, middle, and bottom.
+ if (mMiddleDividerLoc != 0) {
+ drawDivider(0, canvas, mTopDividerTint);
+ }
+ drawDivider((int) ((canvas.getHeight() - mDividerSize) * mMiddleDividerLoc), canvas,
+ mMiddleDividerTint);
+ drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
+
+ if (mLocalPaths.size() == 0) {
+ return;
+ }
+ if (mShowProjection) {
+ drawProjection(canvas);
+ }
+ drawFilledPath(canvas);
+ drawLinePath(canvas);
+ }
+
+ private void drawProjection(Canvas canvas) {
+ mPath.reset();
+ int x = mLocalPaths.keyAt(mLocalPaths.size() - 2);
+ int y = mLocalPaths.valueAt(mLocalPaths.size() - 2);
+ mPath.moveTo(x, y);
+ mPath.lineTo(canvas.getWidth(), mProjectUp ? 0 : canvas.getHeight());
+ canvas.drawPath(mPath, mDottedPaint);
+ }
+
+ private void drawLinePath(Canvas canvas) {
+ mPath.reset();
+ mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
+ for (int i = 1; i < mLocalPaths.size(); i++) {
+ int x = mLocalPaths.keyAt(i);
+ int y = mLocalPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ if (++i < mLocalPaths.size()) {
+ mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
+ }
+ } else {
+ mPath.lineTo(x, y);
+ }
+ }
+ canvas.drawPath(mPath, mLinePaint);
+ }
+
+ private void drawFilledPath(Canvas canvas) {
+ mPath.reset();
+ float lastStartX = mLocalPaths.keyAt(0);
+ mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
+ for (int i = 1; i < mLocalPaths.size(); i++) {
+ int x = mLocalPaths.keyAt(i);
+ int y = mLocalPaths.valueAt(i);
+ if (y == PATH_DELIM) {
+ mPath.lineTo(mLocalPaths.keyAt(i - 1), getHeight());
+ mPath.lineTo(lastStartX, getHeight());
+ mPath.close();
+ if (++i < mLocalPaths.size()) {
+ lastStartX = mLocalPaths.keyAt(i);
+ mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
+ }
+ } else {
+ mPath.lineTo(x, y);
+ }
+ }
+ canvas.drawPath(mPath, mFillPaint);
+ }
+
+ private void drawDivider(int y, Canvas canvas, int tintColor) {
+ Drawable d = mDivider;
+ if (tintColor != -1) {
+ mTintedDivider.setTint(tintColor);
+ d = mTintedDivider;
+ }
+ d.setBounds(0, y, canvas.getWidth(), y + mDividerSize);
+ d.draw(canvas);
+ }
+}
diff --git a/src/com/android/settings/graph/UsageView.java b/src/com/android/settings/graph/UsageView.java
new file mode 100644
index 00000000000..fd128c44206
--- /dev/null
+++ b/src/com/android/settings/graph/UsageView.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2016 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.settings.graph;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.SparseIntArray;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.settingslib.R;
+
+public class UsageView extends FrameLayout {
+
+ private final UsageGraph mUsageGraph;
+ private final TextView[] mLabels;
+ private final TextView[] mBottomLabels;
+
+ public UsageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater.from(context).inflate(R.layout.usage_view, this);
+ mUsageGraph = findViewById(R.id.usage_graph);
+ mLabels = new TextView[] {
+ findViewById(R.id.label_bottom),
+ findViewById(R.id.label_middle),
+ findViewById(R.id.label_top),
+ };
+ mBottomLabels = new TextView[] {
+ findViewById(R.id.label_start),
+ findViewById(R.id.label_end),
+ };
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UsageView, 0, 0);
+ if (a.hasValue(R.styleable.UsageView_sideLabels)) {
+ setSideLabels(a.getTextArray(R.styleable.UsageView_sideLabels));
+ }
+ if (a.hasValue(R.styleable.UsageView_bottomLabels)) {
+ setBottomLabels(a.getTextArray(R.styleable.UsageView_bottomLabels));
+ }
+ if (a.hasValue(R.styleable.UsageView_textColor)) {
+ int color = a.getColor(R.styleable.UsageView_textColor, 0);
+ for (TextView v : mLabels) {
+ v.setTextColor(color);
+ }
+ for (TextView v : mBottomLabels) {
+ v.setTextColor(color);
+ }
+ }
+ if (a.hasValue(R.styleable.UsageView_android_gravity)) {
+ int gravity = a.getInt(R.styleable.UsageView_android_gravity, 0);
+ if (gravity == Gravity.END) {
+ LinearLayout layout = findViewById(R.id.graph_label_group);
+ LinearLayout labels = findViewById(R.id.label_group);
+ // Swap the children order.
+ layout.removeView(labels);
+ layout.addView(labels);
+ // Set gravity.
+ labels.setGravity(Gravity.END);
+ // Swap the bottom space order.
+ LinearLayout bottomLabels = findViewById(R.id.bottom_label_group);
+ View bottomSpace = bottomLabels.findViewById(R.id.bottom_label_space);
+ bottomLabels.removeView(bottomSpace);
+ bottomLabels.addView(bottomSpace);
+ } else if (gravity != Gravity.START) {
+ throw new IllegalArgumentException("Unsupported gravity " + gravity);
+ }
+ }
+ mUsageGraph.setAccentColor(a.getColor(R.styleable.UsageView_android_colorAccent, 0));
+ }
+
+ public void clearPaths() {
+ mUsageGraph.clearPaths();
+ }
+
+ public void addPath(SparseIntArray points) {
+ mUsageGraph.addPath(points);
+ }
+
+ public void configureGraph(int maxX, int maxY, boolean showProjection, boolean projectUp) {
+ mUsageGraph.setMax(maxX, maxY);
+ mUsageGraph.setShowProjection(showProjection, projectUp);
+ }
+
+ public void setAccentColor(int color) {
+ mUsageGraph.setAccentColor(color);
+ }
+
+ public void setDividerLoc(int dividerLoc) {
+ mUsageGraph.setDividerLoc(dividerLoc);
+ }
+
+ public void setDividerColors(int middleColor, int topColor) {
+ mUsageGraph.setDividerColors(middleColor, topColor);
+ }
+
+ public void setSideLabelWeights(float before, float after) {
+ setWeight(R.id.space1, before);
+ setWeight(R.id.space2, after);
+ }
+
+ private void setWeight(int id, float weight) {
+ View v = findViewById(id);
+ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) v.getLayoutParams();
+ params.weight = weight;
+ v.setLayoutParams(params);
+ }
+
+ public void setSideLabels(CharSequence[] labels) {
+ if (labels.length != mLabels.length) {
+ throw new IllegalArgumentException("Invalid number of labels");
+ }
+ for (int i = 0; i < mLabels.length; i++) {
+ mLabels[i].setText(labels[i]);
+ }
+ }
+
+ public void setBottomLabels(CharSequence[] labels) {
+ if (labels.length != mBottomLabels.length) {
+ throw new IllegalArgumentException("Invalid number of labels");
+ }
+ for (int i = 0; i < mBottomLabels.length; i++) {
+ mBottomLabels[i].setText(labels[i]);
+ }
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java
index c9be151b3e5..76ec5ba0ac8 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryPreferenceTest.java
@@ -30,7 +30,7 @@ import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
-import com.android.settingslib.graph.UsageView;
+import com.android.settings.graph.UsageView;
import org.junit.Before;
import org.junit.Test;
diff --git a/tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java b/tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java
new file mode 100644
index 00000000000..c9804d667f1
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/graph/BottomLabelLayoutTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.settings.graph;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.Space;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BottomLabelLayoutTest {
+ private BottomLabelLayout mBottomLabelLayout;
+ private Context mContext;
+ private Space mSpace;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mBottomLabelLayout = new BottomLabelLayout(mContext, null);
+ mBottomLabelLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+ mSpace = new Space(mContext);
+ mSpace.setId(R.id.spacer);
+ mBottomLabelLayout.addView(mSpace);
+ }
+
+ @Test
+ public void testSetStacked_stackedTrue_layoutVertical() {
+ mBottomLabelLayout.setStacked(true);
+
+ assertThat(mBottomLabelLayout.getOrientation()).isEqualTo(LinearLayout.VERTICAL);
+ assertThat(mSpace.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void testSetStacked_stackedFalse_layoutHorizontal() {
+ mBottomLabelLayout.setStacked(false);
+
+ assertThat(mBottomLabelLayout.getOrientation()).isEqualTo(LinearLayout.HORIZONTAL);
+ assertThat(mSpace.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+}