Commit 6703c21c authored by Newton Allen's avatar Newton Allen

Add third_party/android_data_chart for data chart widget.

This adds a new third_party directory, android_data_chart, which
contains the data usage chart UI widget from Android's Settings app. The
widget shows a graph of how much data the user has used and saved over
time.

BUG=428885
R=bengr@chromium.org, cpu@chromium.org, dannyb@google.com, tedchoc@chromium.org

Review URL: https://codereview.chromium.org/866813004

Cr-Commit-Position: refs/heads/master@{#314251}
parent 796a0bc0
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/android/rules.gni")
assert(is_android)
android_resources("android_data_chart_java_resources") {
custom_package = "org.chromium.third_party.android"
resource_dirs = [ "java/res" ]
}
android_library("android_data_chart_java") {
DEPRECATED_java_in_dir = "java/src"
deps = [
":android_data_chart_java_resources",
]
}
This diff is collapsed.
tedchoc@chromium.org
newt@chromium.org
bengr@chromium.org
Name: Android Open Source Project
URL: https://android.googlesource.com/platform/packages/apps/Settings/
Version: unknown
License: Apache 2.0
Security Critical: yes
Description:
This is a modified copy of the data usage chart UI widget from Android's
Settings app. The widget shows a graph of data usage and data savings over time.
Local Modifications:
The code has been modified rather extensively to tweak the UI to Chromium's
needs.
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'variables': {
'chromium_code': 1,
},
'targets': [
{
'target_name': 'android_data_chart_java',
'type': 'none',
'variables': {
'java_in_dir': 'java',
'has_java_resources': 1,
'R_package': 'org.chromium.third_party.android',
'R_package_relpath': 'org/chromium/third_party/android',
},
'includes': [ '../../build/java.gypi' ],
},
],
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 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.
-->
<com.google.android.apps.chrome.third_party.datausagechart.ChartDataUsageView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:id="@+id/chart"
android:layout_width="match_parent"
android:layout_height="@dimen/data_usage_chart_height"
android:paddingTop="16dp"
android:paddingBottom="8dp" >
<com.google.android.apps.chrome.third_party.datausagechart.ChartNetworkSeriesView
android:id="@+id/series"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"
android:background="@color/data_reduction_chart_background_color"
settings:strokeColor="@color/data_reduction_original_color"
settings:fillColor="@color/data_reduction_original_color"
settings:fillColorSecondary="@color/data_reduction_original_color" />
<com.google.android.apps.chrome.third_party.datausagechart.ChartNetworkSeriesView
android:id="@+id/detail_series"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"
settings:strokeColor="@color/data_reduction_compressed_color"
settings:fillColor="@color/data_reduction_compressed_color"
settings:fillColorSecondary="@color/data_reduction_compressed_color" />
</com.google.android.apps.chrome.third_party.datausagechart.ChartDataUsageView>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<resources>
<!-- Data usage chart dimensions -->
<dimen name="data_usage_chart_height">325dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<resources>
<declare-styleable name="ChartView">
<!-- optimal width of the chart -->
<attr name="optimalWidth" format="dimension" />
<!-- how to weight extra space beyond optimal width -->
<attr name="optimalWidthWeight" format="float" />
</declare-styleable>
<declare-styleable name="ChartGridView">
<attr name="primaryDrawable" format="reference" />
<attr name="secondaryDrawable" format="reference" />
<attr name="borderDrawable" format="reference" />
</declare-styleable>
<declare-styleable name="ChartNetworkSeriesView">
<attr name="strokeColor" format="color" />
<attr name="fillColor" format="color" />
<attr name="fillColorSecondary" format="color" />
</declare-styleable>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<resources>
<!-- Data Reduction Colors -->
<color name="data_reduction_compressed_color">@color/pref_accent_color</color>
<color name="data_reduction_original_color">#E1E1E1</color>
<color name="data_reduction_chart_background_color">#FAFAFA</color>
<color name="pref_accent_color">#03a9f4</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2015 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<resources>
<!-- Data usage chart dimensions -->
<dimen name="data_usage_chart_height">252dp</dimen>
</resources>
/*
* Copyright (C) 2011 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 org.chromium.third_party.android.datausagechart;
import android.content.res.Resources;
import android.text.SpannableStringBuilder;
/**
* Axis along a {@link ChartView} that knows how to convert between raw point
* and screen coordinate systems.
* Derived from com.android.settings.widget.ChartAxis
*/
public interface ChartAxis {
/** Set range of raw values this axis should cover. */
public boolean setBounds(long min, long max);
/** Set range of screen points this axis should cover. */
public boolean setSize(float size);
/** Convert raw value into screen point. */
public float convertToPoint(long value);
/** Convert screen point into raw value. */
public long convertToValue(float point);
/**
* Build label that describes given raw value. If the label is rounded for
* display, return the rounded value.
*/
public long buildLabel(Resources res, SpannableStringBuilder builder, long value);
/** Return list of tick points for drawing a grid. */
public float[] getTickPoints();
/**
* Test if given raw value should cause the axis to grow or shrink;
* returning positive value to grow and negative to shrink.
*/
public int shouldAdjustAxis(long value);
}
/*
* Copyright (C) 2013 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 org.chromium.third_party.android.datausagechart;
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.View;
import org.chromium.third_party.android.R;
import java.util.Locale;
/**
* Background of {@link ChartView} that renders grid lines as requested by
* {@link ChartAxis#getTickPoints()}.
* This is derived from com.android.settings.widget.ChartGridView.
*/
public class ChartGridView extends View {
private ChartAxis mHoriz;
private ChartAxis mVert;
private Drawable mPrimary;
private Drawable mSecondary;
private Drawable mBorder;
public static String formatDateRange(Context context, long start, long end) {
final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
final StringBuilder builder = new StringBuilder(50);
final java.util.Formatter formatter = new java.util.Formatter(
builder, Locale.getDefault());
return DateUtils.formatDateRange(context, formatter, start, end, flags, null).toString();
}
public ChartGridView(Context context) {
this(context, null, 0);
}
public ChartGridView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChartGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(false);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ChartGridView, defStyle, 0);
mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable);
mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable);
mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable);
a.recycle();
}
void init(ChartAxis horiz, ChartAxis vert) {
if (horiz == null) throw new NullPointerException("missing horiz");
if (vert == null) throw new NullPointerException("missing vert");
mHoriz = horiz;
mVert = vert;
}
@Override
protected void onDraw(Canvas canvas) {
final int width = getWidth();
final int height = getHeight();
final Drawable secondary = mSecondary;
float density = getResources().getDisplayMetrics().density;
final int secondaryHeight = Math.max(1, Math.round(density));
final float[] vertTicks = mVert.getTickPoints();
for (float y : vertTicks) {
final int bottom = (int) Math.min(y + secondaryHeight, height);
secondary.setBounds(0, (int) y, width, bottom);
secondary.draw(canvas);
}
final Drawable primary = mPrimary;
final int primaryWidth = secondaryHeight;
final float[] horizTicks = mHoriz.getTickPoints();
for (float x : horizTicks) {
final int right = (int) Math.min(x + primaryWidth, width);
primary.setBounds((int) x, 0, right, height);
primary.draw(canvas);
}
mBorder.setBounds(0, 0, width, height);
mBorder.draw(canvas);
}
}
\ No newline at end of file
/*
* Copyright (C) 2013 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 org.chromium.third_party.android.datausagechart;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import org.chromium.third_party.android.R;
/**
* {@link NetworkStatsHistory} series to render inside a {@link ChartView},
* using {@link ChartAxis} to map into screen coordinates.
* This is derived from com.android.settings.widget.ChartNetworkSeriesView.
*/
public class ChartNetworkSeriesView extends View {
private static final String TAG = "ChartNetworkSeriesView";
private static final boolean LOGD = false;
private ChartAxis mHoriz;
private ChartAxis mVert;
private Paint mPaintStroke;
private Paint mPaintFill;
private Paint mPaintFillSecondary;
private Paint mPaintEstimate;
private NetworkStatsHistory mStats;
private Path mPathStroke;
private Path mPathFill;
private Path mPathEstimate;
private long mStart;
private long mEnd;
private long mPrimaryLeft;
private long mPrimaryRight;
/** Series will be extended to reach this end time. */
private long mEndTime = Long.MIN_VALUE;
private boolean mPathValid = false;
private boolean mEstimateVisible = false;
private long mMax;
private long mMaxEstimate;
public ChartNetworkSeriesView(Context context) {
this(context, null, 0);
}
public ChartNetworkSeriesView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChartNetworkSeriesView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ChartNetworkSeriesView, defStyle, 0);
final int stroke = a.getColor(R.styleable.ChartNetworkSeriesView_strokeColor, Color.RED);
final int fill = a.getColor(R.styleable.ChartNetworkSeriesView_fillColor, Color.RED);
final int fillSecondary = a.getColor(
R.styleable.ChartNetworkSeriesView_fillColorSecondary, Color.RED);
setChartColor(stroke, fill, fillSecondary);
setWillNotDraw(false);
a.recycle();
mPathStroke = new Path();
mPathFill = new Path();
mPathEstimate = new Path();
}
void init(ChartAxis horiz, ChartAxis vert) {
if (horiz == null) throw new NullPointerException("missing horiz");
if (vert == null) throw new NullPointerException("missing vert");
mHoriz = horiz;
mVert = vert;
}
public void setChartColor(int stroke, int fill, int fillSecondary) {
mPaintStroke = new Paint();
mPaintStroke.setStrokeWidth(4.0f * getResources().getDisplayMetrics().density);
mPaintStroke.setColor(stroke);
mPaintStroke.setStyle(Style.STROKE);
mPaintStroke.setAntiAlias(true);
mPaintFill = new Paint();
mPaintFill.setColor(fill);
mPaintFill.setStyle(Style.FILL);
mPaintFill.setAntiAlias(true);
mPaintFillSecondary = new Paint();
mPaintFillSecondary.setColor(fillSecondary);
mPaintFillSecondary.setStyle(Style.FILL);
mPaintFillSecondary.setAntiAlias(true);
mPaintEstimate = new Paint();
mPaintEstimate.setStrokeWidth(3.0f);
mPaintEstimate.setColor(fillSecondary);
mPaintEstimate.setStyle(Style.STROKE);
mPaintEstimate.setAntiAlias(true);
mPaintEstimate.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 1));
}
public void bindNetworkStats(NetworkStatsHistory stats) {
mStats = stats;
invalidatePath();
invalidate();
}
public void setBounds(long start, long end) {
mStart = start;
mEnd = end;
}
/**
* Set the range to paint with {@link #mPaintFill}, leaving the remaining
* area to be painted with {@link #mPaintFillSecondary}.
*/
public void setPrimaryRange(long left, long right) {
mPrimaryLeft = left;
mPrimaryRight = right;
invalidate();
}
public void invalidatePath() {
mPathValid = false;
mMax = 0;
invalidate();
}
/**
* Erase any existing {@link Path} and generate series outline based on
* currently bound {@link NetworkStatsHistory} data.
*/
private void generatePath() {
if (LOGD) Log.d(TAG, "generatePath()");
mMax = 0;
mPathStroke.reset();
mPathFill.reset();
mPathEstimate.reset();
mPathValid = true;
// bail when not enough stats to render
if (mStats == null || mStats.size() < 2) {
return;
}
final int height = getHeight();
boolean started = false;
float lastX = 0;
float lastY = height;
long lastTime = mHoriz.convertToValue(lastX);
// move into starting position
mPathStroke.moveTo(lastX, lastY);
mPathFill.moveTo(lastX, lastY);
// TODO(bengr): count fractional data from first bucket crossing start;
// currently it only accepts first full bucket.
long totalData = 0;
NetworkStatsHistory.Entry entry = null;
final int start = mStats.getIndexBefore(mStart);
final int end = mStats.getIndexAfter(mEnd);
for (int i = start; i <= end; i++) {
entry = mStats.getValues(i, entry);
final long startTime = entry.bucketStart;
final long endTime = startTime + entry.bucketDuration;
final float startX = mHoriz.convertToPoint(startTime);
final float endX = mHoriz.convertToPoint(endTime);
// skip until we find first stats on screen
if (endX < 0) continue;
// increment by current bucket total
totalData += entry.rxBytes + entry.txBytes;
final float startY = lastY;
final float endY = mVert.convertToPoint(totalData);
if (lastTime != startTime) {
// gap in buckets; line to start of current bucket
mPathStroke.lineTo(startX, startY);
mPathFill.lineTo(startX, startY);
}
// always draw to end of current bucket
mPathStroke.lineTo(endX, endY);
mPathFill.lineTo(endX, endY);
lastX = endX;
lastY = endY;
lastTime = endTime;
}
// when data falls short, extend to requested end time
if (lastTime < mEndTime) {
lastX = mHoriz.convertToPoint(mEndTime);
mPathStroke.lineTo(lastX, lastY);
mPathFill.lineTo(lastX, lastY);
}
if (LOGD) {
final RectF bounds = new RectF();
mPathFill.computeBounds(bounds, true);
Log.d(TAG, "onLayout() rendered with bounds=" + bounds.toString() + " and totalData="
+ totalData);
}
// drop to bottom of graph from current location
mPathFill.lineTo(lastX, height);
mPathFill.lineTo(0, height);
mMax = totalData;
invalidate();
}
public void setEndTime(long endTime) {
mEndTime = endTime;
}
public void setEstimateVisible(boolean estimateVisible) {
mEstimateVisible = false;
invalidate();
}
public long getMaxEstimate() {
return mMaxEstimate;
}
public long getMaxVisible() {
final long maxVisible = mEstimateVisible ? mMaxEstimate : mMax;
if (maxVisible <= 0 && mStats != null) {
// haven't generated path yet; fall back to raw data
final NetworkStatsHistory.Entry entry = mStats.getValues(mStart, mEnd, null);
return entry.rxBytes + entry.txBytes;
} else {
return maxVisible;
}
}
@Override
protected void onDraw(Canvas canvas) {
int save;
if (!mPathValid) {
generatePath();
}
final float primaryLeftPoint = mHoriz.convertToPoint(mPrimaryLeft);
final float primaryRightPoint = mHoriz.convertToPoint(mPrimaryRight);
if (mEstimateVisible) {
save = canvas.save();
canvas.clipRect(0, 0, getWidth(), getHeight());
canvas.drawPath(mPathEstimate, mPaintEstimate);
canvas.restoreToCount(save);
}
save = canvas.save();
canvas.clipRect(0, 0, primaryLeftPoint, getHeight());
canvas.drawPath(mPathFill, mPaintFillSecondary);
canvas.restoreToCount(save);
save = canvas.save();
canvas.clipRect(primaryRightPoint, 0, getWidth(), getHeight());
canvas.drawPath(mPathFill, mPaintFillSecondary);
canvas.restoreToCount(save);
save = canvas.save();
canvas.clipRect(primaryLeftPoint, 0, primaryRightPoint, getHeight());
canvas.drawPath(mPathFill, mPaintFill);
canvas.drawPath(mPathStroke, mPaintStroke);
canvas.restoreToCount(save);
}
}
/*
* Copyright (C) 2011 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 org.chromium.third_party.android.datausagechart;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewDebug;
import android.widget.FrameLayout;
import org.chromium.third_party.android.R;
/**
* Container for two-dimensional chart, drawn with a combination of
* {@link ChartGridView} and {@link ChartNetworkSeriesView} children. The entire chart uses
* {@link ChartAxis} to map between raw values and screen coordinates.
* Derived from com.android.settings.widget.ChartView
*/
public class ChartView extends FrameLayout {
ChartAxis mHoriz;
ChartAxis mVert;
@ViewDebug.ExportedProperty
private int mOptimalWidth = -1;
private float mOptimalWidthWeight = 0;
private Rect mContent = new Rect();
public ChartView(Context context) {
this(context, null, 0);
}
public ChartView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ChartView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ChartView, defStyle, 0);
setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1),
a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0));
a.recycle();
setClipToPadding(false);
setClipChildren(false);
}
void init(ChartAxis horiz, ChartAxis vert) {
if (horiz == null) throw new NullPointerException("missing horiz");
if (vert == null) throw new NullPointerException("missing vert");
mHoriz = horiz;
mVert = vert;
}
public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
mOptimalWidth = optimalWidth;
mOptimalWidthWeight = optimalWidthWeight;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int slack = getMeasuredWidth() - mOptimalWidth;
if (mOptimalWidth > 0 && slack > 0) {
final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight));
widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
b - t - getPaddingBottom());
final int width = mContent.width();
final int height = mContent.height();
// no scrolling yet, so tell dimensions to fill exactly
mHoriz.setSize(width);
mVert.setSize(height);
final Rect parentRect = new Rect();
final Rect childRect = new Rect();
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final LayoutParams params = (LayoutParams) child.getLayoutParams();
parentRect.set(mContent);
if (child instanceof ChartNetworkSeriesView || child instanceof ChartGridView) {
// series are always laid out to fill entire graph area
// Scrolling is not supported for series larger than the content area.
Gravity.apply(params.gravity, width, height, parentRect, childRect);
child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
}
}
}
}
/*
* Copyright (C) 2011 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 org.chromium.third_party.android.datausagechart;
import android.content.res.Resources;
import android.text.SpannableStringBuilder;
/**
* Utility to invert another {@link ChartAxis}.
* Derived from com.android.settings.widget.InvertedChartAxis
*/
public class InvertedChartAxis implements ChartAxis {
private final ChartAxis mWrapped;
private float mSize;
public InvertedChartAxis(ChartAxis wrapped) {
mWrapped = wrapped;
}
@Override
public boolean setBounds(long min, long max) {
return mWrapped.setBounds(min, max);
}
@Override
public boolean setSize(float size) {
mSize = size;
return mWrapped.setSize(size);
}
@Override
public float convertToPoint(long value) {
return mSize - mWrapped.convertToPoint(value);
}
@Override
public long convertToValue(float point) {
return mWrapped.convertToValue(mSize - point);
}
@Override
public long buildLabel(Resources res, SpannableStringBuilder builder, long value) {
return mWrapped.buildLabel(res, builder, value);
}
@Override
public float[] getTickPoints() {
final float[] points = mWrapped.getTickPoints();
for (int i = 0; i < points.length; i++) {
points[i] = mSize - points[i];
}
return points;
}
@Override
public int shouldAdjustAxis(long value) {
return mWrapped.shouldAdjustAxis(value);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment