1ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey/* 2ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * Copyright (C) 2011 The Android Open Source Project 3ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * 4ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * you may not use this file except in compliance with the License. 6ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * You may obtain a copy of the License at 7ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * 8ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * 10ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * See the License for the specific language governing permissions and 14ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * limitations under the License. 15ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey */ 16ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 17ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkeypackage com.android.settings.widget; 18ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 19ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkeyimport android.content.Context; 20b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkeyimport android.content.res.ColorStateList; 21d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkeyimport android.content.res.Resources; 2252c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkeyimport android.content.res.TypedArray; 23ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkeyimport android.graphics.Canvas; 24d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkeyimport android.graphics.Paint; 2552c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkeyimport android.graphics.drawable.Drawable; 26d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkeyimport android.text.Layout; 27d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkeyimport android.text.StaticLayout; 28d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkeyimport android.text.TextPaint; 2952c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkeyimport android.util.AttributeSet; 30ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkeyimport android.view.View; 31ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 32e6c5003278184c202833209164ddf1ae8c083f12Jeff Sharkeyimport com.android.internal.util.Preconditions; 3352c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkeyimport com.android.settings.R; 34ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 35b37e2887d3112082589997f1bbd802ec282cca6dJason Monkimport static com.android.settings.Utils.formatDateRange; 3639b467482d1bf256a111c757e9b7621c6f523271Jason Monk 37ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey/** 38ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * Background of {@link ChartView} that renders grid lines as requested by 39ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey * {@link ChartAxis#getTickPoints()}. 40ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey */ 41ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkeypublic class ChartGridView extends View { 42ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 4352c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey private ChartAxis mHoriz; 4452c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey private ChartAxis mVert; 45ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 4652c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey private Drawable mPrimary; 4752c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey private Drawable mSecondary; 4852c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey private Drawable mBorder; 49b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 50b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey private int mLabelSize; 51d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey private int mLabelColor; 52d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 53b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey private Layout mLabelStart; 54b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey private Layout mLabelMid; 55b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey private Layout mLabelEnd; 56ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 5752c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey public ChartGridView(Context context) { 5852c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey this(context, null, 0); 5952c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey } 6052c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey 6152c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey public ChartGridView(Context context, AttributeSet attrs) { 6252c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey this(context, attrs, 0); 6352c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey } 6452c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey 6552c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey public ChartGridView(Context context, AttributeSet attrs, int defStyle) { 6652c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey super(context, attrs, defStyle); 67ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 68ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey setWillNotDraw(false); 69ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 7052c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey final TypedArray a = context.obtainStyledAttributes( 7152c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey attrs, R.styleable.ChartGridView, defStyle, 0); 7252c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey 7352c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mPrimary = a.getDrawable(R.styleable.ChartGridView_primaryDrawable); 7452c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mSecondary = a.getDrawable(R.styleable.ChartGridView_secondaryDrawable); 7552c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mBorder = a.getDrawable(R.styleable.ChartGridView_borderDrawable); 76b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 77b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int taId = a.getResourceId(R.styleable.ChartGridView_android_textAppearance, -1); 78b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final TypedArray ta = context.obtainStyledAttributes(taId, 79b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey com.android.internal.R.styleable.TextAppearance); 80b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mLabelSize = ta.getDimensionPixelSize( 81b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey com.android.internal.R.styleable.TextAppearance_textSize, 0); 82b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey ta.recycle(); 83b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 84b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final ColorStateList labelColor = a.getColorStateList( 85b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey R.styleable.ChartGridView_android_textColor); 86b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mLabelColor = labelColor.getDefaultColor(); 8752c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey 8852c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey a.recycle(); 8952c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey } 9052c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey 9152c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey void init(ChartAxis horiz, ChartAxis vert) { 9252c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mHoriz = Preconditions.checkNotNull(horiz, "missing horiz"); 9352c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mVert = Preconditions.checkNotNull(vert, "missing vert"); 94ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey } 95ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 96d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey void setBounds(long start, long end) { 97d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey final Context context = getContext(); 98b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final long mid = (start + end) / 2; 99b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mLabelStart = makeLabel(formatDateRange(context, start, start)); 100b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mLabelMid = makeLabel(formatDateRange(context, mid, mid)); 101b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mLabelEnd = makeLabel(formatDateRange(context, end, end)); 102d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey invalidate(); 103d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey } 104d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 105ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey @Override 106ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey protected void onDraw(Canvas canvas) { 107ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey final int width = getWidth(); 108b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int height = getHeight() - getPaddingBottom(); 109ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 11052c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey final Drawable secondary = mSecondary; 111b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey if (secondary != null) { 112b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int secondaryHeight = secondary.getIntrinsicHeight(); 113b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 114b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final float[] vertTicks = mVert.getTickPoints(); 115b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey for (float y : vertTicks) { 116b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int bottom = (int) Math.min(y + secondaryHeight, height); 117b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey secondary.setBounds(0, (int) y, width, bottom); 118b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey secondary.draw(canvas); 119b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey } 120ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey } 121ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 12252c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey final Drawable primary = mPrimary; 123b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey if (primary != null) { 124b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int primaryWidth = primary.getIntrinsicWidth(); 125b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int primaryHeight = primary.getIntrinsicHeight(); 126b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 127b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final float[] horizTicks = mHoriz.getTickPoints(); 128b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey for (float x : horizTicks) { 129b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int right = (int) Math.min(x + primaryWidth, width); 130b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey primary.setBounds((int) x, 0, right, height); 131b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey primary.draw(canvas); 132b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey } 133ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey } 134ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey 13552c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mBorder.setBounds(0, 0, width, height); 13652c3f4461b806e4f1ce48455ee2ba0ac05dfdab4Jeff Sharkey mBorder.draw(canvas); 137d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 138b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int padding = mLabelStart != null ? mLabelStart.getHeight() / 8 : 0; 139d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 140b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final Layout start = mLabelStart; 141d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey if (start != null) { 142b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int saveCount = canvas.save(); 143d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey canvas.translate(0, height + padding); 144d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey start.draw(canvas); 145b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey canvas.restoreToCount(saveCount); 146b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey } 147b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey 148b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final Layout mid = mLabelMid; 149b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey if (mid != null) { 150b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int saveCount = canvas.save(); 151b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey canvas.translate((width - mid.getWidth()) / 2, height + padding); 152b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey mid.draw(canvas); 153b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey canvas.restoreToCount(saveCount); 154d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey } 155d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 156b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final Layout end = mLabelEnd; 157d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey if (end != null) { 158b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey final int saveCount = canvas.save(); 159d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey canvas.translate(width - end.getWidth(), height + padding); 160d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey end.draw(canvas); 161b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey canvas.restoreToCount(saveCount); 162d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey } 163ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey } 164d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 165b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey private Layout makeLabel(CharSequence text) { 166d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey final Resources res = getResources(); 167d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey final TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 168d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey paint.density = res.getDisplayMetrics().density; 169d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey paint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale); 170d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey paint.setColor(mLabelColor); 171b654846300f79e9e4c605ce62d09f9a05d232feeJeff Sharkey paint.setTextSize(mLabelSize); 172d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey 173d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey return new StaticLayout(text, paint, 174d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey (int) Math.ceil(Layout.getDesiredWidth(text, paint)), 175d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true); 176d39c6e4083f1212519d5dc14f64132a10f2b7c7aJeff Sharkey } 177ab2d8d3a38857b8c155e6c6393c5821f5a341aaeJeff Sharkey} 178