Java tutorial
/* * Copyright 2012 Mike Niyonkuru * * 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 net.niyonkuru.koodroid.ui; import android.content.Context; import android.database.Cursor; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.sql.Date; import java.util.Calendar; import net.niyonkuru.koodroid.R; import net.niyonkuru.koodroid.provider.AccountContract.Subscribers; import net.niyonkuru.koodroid.provider.AccountContract.Usages; import net.niyonkuru.koodroid.util.CalendarUtils; import org.achartengine.ChartFactory; import org.achartengine.GraphicalView; import org.achartengine.chart.BarChart.Type; import org.achartengine.model.SeriesSelection; import org.achartengine.model.XYMultipleSeriesDataset; import org.achartengine.model.XYSeries; import org.achartengine.renderer.SimpleSeriesRenderer; import org.achartengine.renderer.XYMultipleSeriesRenderer; /** * Displays daily {@link Usages} for a subscriber. */ public class DataDetailFragment extends DetailFragment { // private static final String TAG = "DataDetailFragment"; private AlternatingColorAdapter mAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle(null); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); /* load data again to be used by the graph */ getLoaderManager().initLoader(0, null, this); ListView lv = getListView(); LayoutInflater inflater = LayoutInflater.from(mContext); View graph = inflater.inflate(R.layout.usage_graph, lv, false); lv.addHeaderView(graph, null, false); View header = inflater.inflate(R.layout.usage_list_item_labels, lv, false); lv.addHeaderView(header, null, false); lv.setDividerHeight(0); mAdapter = new UsageAdapter(mContext); setListAdapter(mAdapter); setListShown(false); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { String dataUsage = getResources().getString(R.string.parser_usage_service_data); CursorLoader loader = new CursorLoader(mContext, Subscribers.buildUsagesUri(getSubscriber()), UsagesQuery.PROJECTION, Usages.USAGE_SERVICE + "='" + dataUsage + "'", null, Usages.DEFAULT_SORT); loader.setUpdateThrottle(DateUtils.SECOND_IN_MILLIS); return loader; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { if (loader.getId() == 0) { mAdapter.swapCursor(data); if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } else { /* graph data processed here */ new GraphingTask().execute(data); } } private class GraphingTask extends AsyncTask<Cursor, Integer, XYMultipleSeriesDataset> { private XYMultipleSeriesRenderer mRenderer; @Override protected XYMultipleSeriesDataset doInBackground(Cursor... params) { int minX = 1, maxX = 30; mRenderer = getBarRenderer(minX, maxX); return getBarDataset(params[0], minX, maxX); } @Override protected void onPostExecute(XYMultipleSeriesDataset dataset) { if (dataset == null) return; final GraphicalView chart = ChartFactory.getBarChartView(mContext, dataset, mRenderer, Type.DEFAULT); chart.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { SeriesSelection seriesSelection = chart.getCurrentSeriesAndPoint(); if (seriesSelection != null) { int value = (int) seriesSelection.getValue(); String kilobytes = getResources().getQuantityString(R.plurals.kilobytes, value, value); Toast.makeText(mContext, kilobytes, Toast.LENGTH_SHORT).show(); } } }); FrameLayout graphView = (FrameLayout) getView().findViewById(R.id.chart); graphView.removeAllViews(); graphView.addView(chart, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } } private XYMultipleSeriesDataset getBarDataset(Cursor cursor, int x, int maxX) { XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset(); XYSeries series = new XYSeries(null); Calendar cal = Calendar.getInstance(); CalendarUtils.trimTimestamp(cal); if (cursor.isClosed() || !cursor.moveToFirst()) return null; while (x <= maxX) { double count = 0; if (!cursor.isAfterLast()) { /* cursor has data */ Date rowDate = new Date(cal.getTimeInMillis()); Date currDate = Date.valueOf(cursor.getString(UsagesQuery.DATE)); if (rowDate.equals(currDate)) { count = cursor.getDouble(UsagesQuery.COUNT); cursor.moveToNext(); } } cal.add(Calendar.DAY_OF_YEAR, -1); series.add(x++, count); } dataset.addSeries(series); return dataset; } private XYMultipleSeriesRenderer getBarRenderer(int minX, int maxX) { XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer(); renderer.setShowLegend(false); renderer.setShowAxes(false); renderer.setShowGrid(false); renderer.setShowLabels(false); renderer.setInScroll(true); renderer.setZoomEnabled(false, false); renderer.setPanEnabled(false, false); renderer.setBarSpacing(0.1); renderer.setMargins(new int[] { 0, 0, -1, 0 }); /* this avoid a bug that cuts off the first and last bar */ renderer.setXAxisMin(minX - 1); renderer.setXAxisMax(maxX + 1); SimpleSeriesRenderer r = new SimpleSeriesRenderer(); r.setColor(getResources().getColor(R.color.blue)); renderer.addSeriesRenderer(r); return renderer; } @Override public void onLoaderReset(Loader<Cursor> loader) { mAdapter.swapCursor(null); } public class UsageAdapter extends AlternatingColorAdapter { public UsageAdapter(Context context) { super(context); } @Override public void bindView(View view, Context context, Cursor cursor) { ViewHolder holder = (ViewHolder) view.getTag(); if (holder == null) { holder = new ViewHolder(); holder.usage_date = (TextView) view.findViewById(R.id.usage_date); holder.usage_cost = (TextView) view.findViewById(R.id.usage_cost); holder.usage = (TextView) view.findViewById(R.id.usage); view.setTag(holder); } holder.usage_date.setText(cursor.getString(UsagesQuery.DATE)); holder.usage_cost.setText(formatMoney(cursor.getString(UsagesQuery.AMOUNT))); holder.usage.setText(cursor.getString(UsagesQuery.COUNT)); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return LayoutInflater.from(context).inflate(R.layout.usage_list_item, parent, false); } class ViewHolder { TextView usage_date, usage, usage_cost; } } /** * {@link Usages} query parameters */ public interface UsagesQuery { String[] PROJECTION = { Usages._ID, Usages.USAGE_DATE, Usages.USAGE_COUNT, Usages.USAGE_AMOUNT }; int DATE = 1; int COUNT = 2; int AMOUNT = 3; } }