• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.widget;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.Rect;
22 import android.util.AttributeSet;
23 import android.view.Gravity;
24 import android.view.View;
25 import android.view.ViewDebug;
26 import android.widget.FrameLayout;
27 
28 import com.android.internal.util.Preconditions;
29 import com.android.settings.R;
30 
31 /**
32  * Container for two-dimensional chart, drawn with a combination of
33  * {@link ChartGridView} and {@link ChartSweepView} children. The entire chart uses
34  * {@link ChartAxis} to map between raw values
35  * and screen coordinates.
36  */
37 public class ChartView extends FrameLayout {
38     // TODO: extend something that supports two-dimensional scrolling
39 
40     private static final int SWEEP_GRAVITY = Gravity.TOP | Gravity.START;
41 
42     ChartAxis mHoriz;
43     ChartAxis mVert;
44 
45     @ViewDebug.ExportedProperty
46     private int mOptimalWidth = -1;
47     private float mOptimalWidthWeight = 0;
48 
49     private Rect mContent = new Rect();
50 
ChartView(Context context)51     public ChartView(Context context) {
52         this(context, null, 0);
53     }
54 
ChartView(Context context, AttributeSet attrs)55     public ChartView(Context context, AttributeSet attrs) {
56         this(context, attrs, 0);
57     }
58 
ChartView(Context context, AttributeSet attrs, int defStyle)59     public ChartView(Context context, AttributeSet attrs, int defStyle) {
60         super(context, attrs, defStyle);
61 
62         final TypedArray a = context.obtainStyledAttributes(
63                 attrs, R.styleable.ChartView, defStyle, 0);
64         setOptimalWidth(a.getDimensionPixelSize(R.styleable.ChartView_optimalWidth, -1),
65                 a.getFloat(R.styleable.ChartView_optimalWidthWeight, 0));
66         a.recycle();
67 
68         setClipToPadding(false);
69         setClipChildren(false);
70     }
71 
init(ChartAxis horiz, ChartAxis vert)72     void init(ChartAxis horiz, ChartAxis vert) {
73         mHoriz = Preconditions.checkNotNull(horiz, "missing horiz");
74         mVert = Preconditions.checkNotNull(vert, "missing vert");
75     }
76 
setOptimalWidth(int optimalWidth, float optimalWidthWeight)77     public void setOptimalWidth(int optimalWidth, float optimalWidthWeight) {
78         mOptimalWidth = optimalWidth;
79         mOptimalWidthWeight = optimalWidthWeight;
80         requestLayout();
81     }
82 
83     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)84     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
85         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
86 
87         final int slack = getMeasuredWidth() - mOptimalWidth;
88         if (mOptimalWidth > 0 && slack > 0) {
89             final int targetWidth = (int) (mOptimalWidth + (slack * mOptimalWidthWeight));
90             widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY);
91             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
92         }
93     }
94 
95     @Override
onLayout(boolean changed, int l, int t, int r, int b)96     protected void onLayout(boolean changed, int l, int t, int r, int b) {
97         mContent.set(getPaddingLeft(), getPaddingTop(), r - l - getPaddingRight(),
98                 b - t - getPaddingBottom());
99         final int width = mContent.width();
100         final int height = mContent.height();
101 
102         // no scrolling yet, so tell dimensions to fill exactly
103         mHoriz.setSize(width);
104         mVert.setSize(height);
105 
106         final Rect parentRect = new Rect();
107         final Rect childRect = new Rect();
108 
109         for (int i = 0; i < getChildCount(); i++) {
110             final View child = getChildAt(i);
111             final LayoutParams params = (LayoutParams) child.getLayoutParams();
112 
113             parentRect.set(mContent);
114 
115             if (child instanceof ChartGridView) {
116                 // Grid uses some extra room for labels
117                 Gravity.apply(params.gravity, width, height, parentRect, childRect);
118                 child.layout(childRect.left, childRect.top, childRect.right,
119                         childRect.bottom + child.getPaddingBottom());
120 
121             } else if (child instanceof ChartSweepView) {
122                 layoutSweep((ChartSweepView) child, parentRect, childRect);
123                 child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
124             }
125         }
126     }
127 
layoutSweep(ChartSweepView sweep)128     protected void layoutSweep(ChartSweepView sweep) {
129         final Rect parentRect = new Rect(mContent);
130         final Rect childRect = new Rect();
131 
132         layoutSweep(sweep, parentRect, childRect);
133         sweep.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
134     }
135 
layoutSweep(ChartSweepView sweep, Rect parentRect, Rect childRect)136     protected void layoutSweep(ChartSweepView sweep, Rect parentRect, Rect childRect) {
137         final Rect sweepMargins = sweep.getMargins();
138 
139         // sweep is always placed along specific dimension
140         if (sweep.getFollowAxis() == ChartSweepView.VERTICAL) {
141             parentRect.top += sweepMargins.top + (int) sweep.getPoint();
142             parentRect.bottom = parentRect.top;
143             parentRect.left += sweepMargins.left;
144             parentRect.right += sweepMargins.right;
145             Gravity.apply(SWEEP_GRAVITY, parentRect.width(), sweep.getMeasuredHeight(),
146                     parentRect, childRect);
147 
148         } else {
149             parentRect.left += sweepMargins.left + (int) sweep.getPoint();
150             parentRect.right = parentRect.left;
151             parentRect.top += sweepMargins.top;
152             parentRect.bottom += sweepMargins.bottom;
153             Gravity.apply(SWEEP_GRAVITY, sweep.getMeasuredWidth(), parentRect.height(),
154                     parentRect, childRect);
155         }
156     }
157 }
158