com.dgsd.android.ShiftTracker.Service.ShiftListWidgetService.java Source code

Java tutorial

Introduction

Here is the source code for com.dgsd.android.ShiftTracker.Service.ShiftListWidgetService.java

Source

/*
 * Copyright 2013 Daniel Grech
 *
 *    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 com.dgsd.android.ShiftTracker.Service;

import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import com.dgsd.android.ShiftTracker.Adapter.WeekAdapter;
import com.dgsd.android.ShiftTracker.BuildConfig;
import com.dgsd.android.ShiftTracker.EditShiftActivity;
import com.dgsd.android.ShiftTracker.Model.Shift;
import com.dgsd.android.ShiftTracker.R;
import com.dgsd.android.ShiftTracker.Util.Prefs;
import com.dgsd.android.ShiftTracker.Util.TimeUtils;
import com.dgsd.android.ShiftTracker.Util.UIUtils;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

public class ShiftListWidgetService extends RemoteViewsService {
    public static final String TAG = ShiftListWidgetService.class.getSimpleName();

    // Minimum delay between queries on the database for widget updates in ms
    private static final int WIDGET_UPDATE_THROTTLE = 500;

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return (new ShiftListUpdateReceiver(this.getApplicationContext(), intent));
    }

    public static class ShiftListUpdateReceiver
            implements RemoteViewsFactory, Loader.OnLoadCompleteListener<Cursor> {

        private Context mContext = null;
        private AppWidgetManager mAppWidgetManager;
        private int mAppWidgetId = -1;
        private CursorLoader mLoader;
        private List<Object> mShiftsAndIds; //Holds either Shifts or Integers representing Julian Days

        private Formatter mFormatter;
        private StringBuilder mStringBuilder = new StringBuilder();
        private boolean mIs24Hour = false;
        private boolean mShowIncomePref;

        private NumberFormat mCurrencyFormatter;

        public ShiftListUpdateReceiver(Context context, Intent intent) {
            this.mContext = context;
            mAppWidgetManager = AppWidgetManager.getInstance(mContext);
            mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);

            mIs24Hour = DateFormat.is24HourFormat(mContext);
            mFormatter = new Formatter(mStringBuilder);

            mCurrencyFormatter = NumberFormat.getCurrencyInstance();

            mShowIncomePref = Prefs.getInstance(context).get(context.getString(R.string.settings_key_show_income),
                    true);
        }

        @Override
        public void onCreate() {
            initLoader();
        }

        public void initLoader() {
            if (BuildConfig.DEBUG)
                Log.d(TAG, "Querying for widget data...");

            if (mLoader != null)
                mLoader.forceLoad();
            else {
                final int startDay = Integer.valueOf(
                        Prefs.getInstance(mContext).get(mContext.getString(R.string.settings_key_start_day), "1"));
                int currentJd = TimeUtils.getCurrentJulianDay();

                mLoader = new WeekAdapter(mContext, null, adjustJulianDay(startDay, currentJd))
                        .getWeeklyLoader(mContext);
                mLoader.setUpdateThrottle(WIDGET_UPDATE_THROTTLE);
                mLoader.registerListener(mAppWidgetId, this);
                mLoader.startLoading();
            }
        }

        @Override
        public void onDestroy() {
            if (mLoader != null)
                mLoader.reset();
        }

        @Override
        public int getCount() {
            return mShiftsAndIds == null ? 0 : mShiftsAndIds.size();
        }

        @Override
        public RemoteViews getLoadingView() {
            return new RemoteViews(mContext.getPackageName(), R.layout.widget_loading);
        }

        @Override
        public RemoteViews getViewAt(int pos) {
            if (pos < 0 || pos > getCount() || mShiftsAndIds == null || mShiftsAndIds.isEmpty())
                return null;

            if (pos < mShiftsAndIds.size() && mShiftsAndIds.get(pos) instanceof Integer) {
                //We've got a header!
                RemoteViews header = new RemoteViews(mContext.getPackageName(), R.layout.list_widget_heading);
                header.setTextViewText(R.id.text,
                        getDayOfWeekString((Integer) mShiftsAndIds.get(pos), TimeUtils.getCurrentJulianDay()));
                return header;
            }

            RemoteViews row = new RemoteViews(mContext.getPackageName(), R.layout.list_widget_shift);

            final Shift shift = (Shift) mShiftsAndIds.get(pos);
            row.setTextViewText(R.id.name, shift.name);
            row.setTextViewText(R.id.time, getTimeText(shift));

            String payText = getPayText(shift);
            if (mShowIncomePref && !TextUtils.isEmpty(payText)) {
                row.setTextViewText(R.id.pay, payText);
                row.setViewVisibility(R.id.pay, View.VISIBLE);
            } else {
                row.setTextViewText(R.id.pay, null);
                row.setViewVisibility(R.id.pay, View.GONE);
            }

            if (TextUtils.isEmpty(shift.note)) {
                row.setViewVisibility(R.id.note, View.GONE);
            } else {
                row.setTextViewText(R.id.note, shift.note);
                row.setViewVisibility(R.id.note, View.VISIBLE);
            }

            Intent intent = new Intent();
            intent.putExtra(EditShiftActivity.EXTRA_SHIFT, shift);
            row.setOnClickFillInIntent(R.id.container, intent);
            return row;
        }

        @Override
        public int getViewTypeCount() {
            return 2; // shifts + header
        }

        @Override
        public long getItemId(int pos) {
            if (mShiftsAndIds == null || pos >= mShiftsAndIds.size())
                return -1;

            Object o = mShiftsAndIds.get(pos);
            if (o instanceof Integer)
                return (Integer) o;
            else
                return ((Shift) o).id;
        }

        @Override
        public boolean hasStableIds() {
            return true;
        }

        @Override
        public void onDataSetChanged() {
            initLoader();
        }

        @Override
        public void onLoadComplete(Loader<Cursor> cursorLoader, Cursor cursor) {
            List<Object> newShifts = new ArrayList<Object>();
            int prevJd = -1;

            if (cursor != null && cursor.moveToFirst()) {
                do {
                    Shift shift = Shift.fromCursor(cursor);
                    final int jdToCompare = shift.julianDay;

                    if (prevJd != jdToCompare)
                        newShifts.add(jdToCompare);

                    newShifts.add(shift);
                    prevJd = shift.julianDay;
                } while (cursor.moveToNext());
            }

            if (cursor != null && !cursor.isClosed())
                cursor.close();

            if (mShiftsAndIds == null || !newShifts.equals(mShiftsAndIds)) {
                mShiftsAndIds = newShifts;
                mAppWidgetManager.notifyAppWidgetViewDataChanged(mAppWidgetId, R.id.list);
            }
        }

        private String getDayOfWeekString(int julianDay, int todayJulianDay) {
            Time time = new Time();
            time.setJulianDay(julianDay);

            time.setJulianDay(julianDay);
            return DateUtils.formatDateTime(mContext, time.toMillis(true), DateUtils.FORMAT_SHOW_DATE
                    | DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_NO_YEAR);
        }

        private String getTimeText(Shift shift) {
            int flags = DateUtils.FORMAT_SHOW_TIME;
            if (mIs24Hour)
                flags |= DateUtils.FORMAT_24HOUR;

            mStringBuilder.setLength(0);
            String time = DateUtils
                    .formatDateRange(mContext, mFormatter, shift.getStartTime(), shift.getEndTime(), flags)
                    .toString();
            time += " (" + UIUtils.getDurationAsHours(shift.getDurationInMinutes()) + ")";
            return time;
        }

        private String getPayText(Shift shift) {
            if (shift.payRate <= 0.01)
                return null;

            return mCurrencyFormatter.format(shift.getIncome());
        }
    }

    private static int adjustJulianDay(int startWeekday, int jd) {
        Time time = new Time();
        time.setJulianDay(jd);
        if (time.weekDay == startWeekday) {
            //Great, no adjustment needed
            return jd;
        } else {
            while (time.weekDay != startWeekday)
                time.setJulianDay(jd--);
            return TimeUtils.getJulianDay(time);
        }
    }
}