Skip to content

Commit bd084d3

Browse files
authored
Merge pull request #112 from AppDevNext/ish-joshi-master
Added Accessibility Support for Screenreaders
2 parents bd1de3b + b2fee09 commit bd084d3

File tree

9 files changed

+160
-3
lines changed

9 files changed

+160
-3
lines changed

MPChartLib/src/main/java/com/github/mikephil/charting/charts/BarChart.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
import com.github.mikephil.charting.components.YAxis;
99
import com.github.mikephil.charting.data.BarData;
1010
import com.github.mikephil.charting.data.BarEntry;
11+
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
1112
import com.github.mikephil.charting.highlight.BarHighlighter;
1213
import com.github.mikephil.charting.highlight.Highlight;
1314
import com.github.mikephil.charting.interfaces.dataprovider.BarDataProvider;
1415
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
1516
import com.github.mikephil.charting.renderer.BarChartRenderer;
1617

18+
import java.util.Locale;
19+
1720
/**
1821
* Chart that draws bars.
1922
*
@@ -275,4 +278,33 @@ public void setRoundedBarRadius(float mRoundedBarRadius) {
275278
this.mDrawRoundedBars = true;
276279
init();
277280
}
281+
282+
@Override
283+
public String getAccessibilityDescription() {
284+
285+
BarData barData = getBarData();
286+
287+
int entryCount = barData.getEntryCount();
288+
289+
// Find the min and max index
290+
IAxisValueFormatter yAxisValueFormatter = getAxisLeft().getValueFormatter();
291+
String minVal = yAxisValueFormatter.getFormattedValue(barData.getYMin(), null);
292+
String maxVal = yAxisValueFormatter.getFormattedValue(barData.getYMax(), null);
293+
294+
// Data range...
295+
IAxisValueFormatter xAxisValueFormatter = getXAxis().getValueFormatter();
296+
String minRange = xAxisValueFormatter.getFormattedValue(barData.getXMin(), null);
297+
String maxRange = xAxisValueFormatter.getFormattedValue(barData.getXMax(), null);
298+
299+
String entries = entryCount == 1 ? "entry" : "entries";
300+
301+
// Format the values of min and max; to recite them back
302+
303+
String description = String.format(Locale.getDefault(), "The bar chart has %d %s. " +
304+
"The minimum value is %s and maximum value is %s." +
305+
"Data ranges from %s to %s.",
306+
entryCount, entries, minVal, maxVal, minRange, maxRange);
307+
308+
return description;
309+
}
278310
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/BubbleChart.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,9 @@ protected void init() {
4040
public BubbleData getBubbleData() {
4141
return mData;
4242
}
43+
44+
@Override
45+
public String getAccessibilityDescription() {
46+
return "This is bubble chart";
47+
}
4348
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/CandleStickChart.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,9 @@ protected void init() {
4141
public CandleData getCandleData() {
4242
return mData;
4343
}
44+
45+
@Override
46+
public String getAccessibilityDescription() {
47+
return "This is a candlestick chart";
48+
}
4449
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/Chart.java

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.view.View;
2222
import android.view.ViewGroup;
2323
import android.view.ViewParent;
24+
import android.view.accessibility.AccessibilityEvent;
2425

2526
import com.github.mikephil.charting.animation.ChartAnimator;
2627
import com.github.mikephil.charting.animation.Easing.EasingFunction;
@@ -170,6 +171,16 @@ public abstract class Chart<T extends ChartData<? extends IDataSet<? extends Ent
170171
private float mExtraTopOffset = 0.f, mExtraRightOffset = 0.f, mExtraBottomOffset = 0.f, mExtraLeftOffset = 0.f;
171172

172173
/**
174+
* Tag for logging accessibility related content
175+
*/
176+
private String TAG = "abilityTag";
177+
178+
/**
179+
* Additional data on top of dynamically generated description. This can be set by the user.
180+
*/
181+
private String accessibilitySummaryDescription = "";
182+
183+
/**
173184
* default constructor for initialization in code
174185
*/
175186
public Chart(Context context) {
@@ -229,9 +240,11 @@ public void onAnimationUpdate(ValueAnimator animation) {
229240
mInfoPaint.setTextSize(Utils.convertDpToPixel(12f));
230241

231242
if (mLogEnabled) {
232-
Log.i("", "Chart.init()");
233-
}
234-
}
243+
Log.i("", "Chart.init()");
244+
245+
// enable being detected by ScreenReader
246+
setFocusable(true);
247+
}}
235248

236249
// public void initWithDummyData() {
237250
// ColorTemplate template = new ColorTemplate();
@@ -1649,4 +1662,38 @@ private void unbindDrawables(View view) {
16491662
public void setUnbindEnabled(boolean enabled) {
16501663
this.mUnbind = enabled;
16511664
}
1665+
1666+
// region accessibility
1667+
1668+
/**
1669+
*
1670+
* @return accessibility description must be created for each chart
1671+
*/
1672+
public abstract String getAccessibilityDescription();
1673+
1674+
public String getAccessibilitySummaryDescription() {
1675+
return accessibilitySummaryDescription;
1676+
}
1677+
1678+
public void setAccessibilitySummaryDescription(String accessibilitySummaryDescription) {
1679+
this.accessibilitySummaryDescription = accessibilitySummaryDescription;
1680+
}
1681+
1682+
@Override
1683+
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1684+
1685+
boolean completed = super.dispatchPopulateAccessibilityEvent(event);
1686+
Log.d(TAG, "Dispatch called for Chart <View> and completed as " + completed);
1687+
1688+
event.getText().add(getAccessibilityDescription());
1689+
1690+
// Add the user generated summary after the dynamic summary is complete.
1691+
if (!TextUtils.isEmpty(this.getAccessibilitySummaryDescription())) {
1692+
event.getText().add(this.getAccessibilitySummaryDescription());
1693+
}
1694+
1695+
return true;
1696+
}
1697+
1698+
// endregion
16521699
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/CombinedChart.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,8 @@ protected void drawMarkers(Canvas canvas) {
266266
}
267267
}
268268

269+
@Override
270+
public String getAccessibilityDescription() {
271+
return "This is a combined chart";
272+
}
269273
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/LineChart.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import android.util.AttributeSet;
66

77
import com.github.mikephil.charting.data.LineData;
8+
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
89
import com.github.mikephil.charting.interfaces.dataprovider.LineDataProvider;
910
import com.github.mikephil.charting.renderer.LineChartRenderer;
1011

12+
import java.util.Locale;
13+
1114
/**
1215
* Chart that draws lines, surfaces, circles, ...
1316
*
@@ -47,4 +50,28 @@ protected void onDetachedFromWindow() {
4750
}
4851
super.onDetachedFromWindow();
4952
}
53+
54+
@Override
55+
public String getAccessibilityDescription() {
56+
LineData lineData = getLineData();
57+
58+
int numberOfPoints = lineData.getEntryCount();
59+
60+
// Min and max values...
61+
IAxisValueFormatter yAxisValueFormmater = getAxisLeft().getValueFormatter();
62+
String minVal = yAxisValueFormmater.getFormattedValue(lineData.getYMin(), null);
63+
String maxVal = yAxisValueFormmater.getFormattedValue(lineData.getYMax(), null);
64+
65+
// Data range...
66+
IAxisValueFormatter xAxisValueFormatter = getXAxis().getValueFormatter();
67+
String minRange = xAxisValueFormatter.getFormattedValue(lineData.getXMin(), null);
68+
String maxRange = xAxisValueFormatter.getFormattedValue(lineData.getXMax(), null);
69+
70+
String entries = numberOfPoints == 1 ? "entry" : "entries";
71+
72+
return String.format(Locale.getDefault(), "The line chart has %d %s. " +
73+
"The minimum value is %s and maximum value is %s." +
74+
"Data ranges from %s to %s.",
75+
numberOfPoints, entries, minVal, maxVal, minRange, maxRange);
76+
}
5077
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/PieChart.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@
66
import android.graphics.Paint;
77
import android.graphics.RectF;
88
import android.graphics.Typeface;
9+
import android.text.TextUtils;
910
import android.util.AttributeSet;
1011

1112
import com.github.mikephil.charting.components.XAxis;
1213
import com.github.mikephil.charting.data.PieData;
14+
import com.github.mikephil.charting.data.PieEntry;
1315
import com.github.mikephil.charting.highlight.Highlight;
1416
import com.github.mikephil.charting.highlight.PieHighlighter;
1517
import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
1618
import com.github.mikephil.charting.renderer.PieChartRenderer;
1719
import com.github.mikephil.charting.utils.MPPointF;
1820
import com.github.mikephil.charting.utils.Utils;
1921

22+
import java.util.ArrayList;
2023
import java.util.List;
24+
import java.util.Locale;
2125

2226
/**
2327
* View that represents a pie chart. Draws cake like slices.
@@ -801,4 +805,27 @@ protected void onDetachedFromWindow() {
801805
}
802806
super.onDetachedFromWindow();
803807
}
808+
809+
@Override
810+
public String getAccessibilityDescription() {
811+
812+
PieData pieData = getData();
813+
814+
int entryCount = pieData.getEntryCount();
815+
816+
StringBuilder builder = new StringBuilder();
817+
818+
builder.append(String.format(Locale.getDefault(), "The pie chart has %d entries.",
819+
entryCount));
820+
821+
for (int i = 0; i < entryCount; i++) {
822+
PieEntry entry = pieData.getDataSet().getEntryForIndex(i);
823+
float percentage = (entry.getValue() / pieData.getYValueSum()) * 100;
824+
builder.append(String.format(Locale.getDefault(), "%s has %.2f percent pie taken",
825+
(TextUtils.isEmpty(entry.getLabel()) ? "No Label" : entry.getLabel()),
826+
percentage));
827+
}
828+
829+
return builder.toString();
830+
}
804831
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/RadarChart.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,4 +382,9 @@ public float getYChartMin() {
382382
public float getYRange() {
383383
return mYAxis.mAxisRange;
384384
}
385+
386+
@Override
387+
public String getAccessibilityDescription() {
388+
return "This is a Radar chart";
389+
}
385390
}

MPChartLib/src/main/java/com/github/mikephil/charting/charts/ScatterChart.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,9 @@ public static ScatterShape[] getAllDefaultShapes() {
7474
return new ScatterShape[]{SQUARE, CIRCLE, TRIANGLE, CROSS, X, CHEVRON_UP, CHEVRON_DOWN};
7575
}
7676
}
77+
78+
@Override
79+
public String getAccessibilityDescription() {
80+
return "This is scatter chart";
81+
}
7782
}

0 commit comments

Comments
 (0)