/* * Copyright (c) 2015 Jonas Kalderstam. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.nononsenseapps.notepad.ui.widget; import java.text.SimpleDateFormat; import java.util.Date; import com.nononsenseapps.notepad.util.TimeFormatter; import com.nononsenseapps.notepad.R; import com.nononsenseapps.notepad.data.model.sql.Task; import com.nononsenseapps.notepad.ui.editor.TaskDetailFragment; import com.nononsenseapps.notepad.ui.common.TitleNoteTextView; import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Binder; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; /** * This is the service that provides the factory to be bound to the collection * service. */ public class ListWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new ListRemoteViewsFactory(this.getApplicationContext(), intent); } /** * This is the factory that will provide data to the collection widget. */ static class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private Context mContext; // private HeaderCursor mCursor; private Cursor mCursor; private int mAppWidgetId; private SimpleDateFormat mDateFormatter = null; private SimpleDateFormat weekdayFormatter; // private static final String indent = " "; // private long listId = -1; public ListRemoteViewsFactory(Context context, Intent intent) { mContext = context; mAppWidgetId = intent.getIntExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } @Override public void onCreate() { } @Override public void onDestroy() { if (mCursor != null) { mCursor.close(); } } @Override public int getCount() { if (mCursor != null) return mCursor.getCount(); else return 0; } @Override public RemoteViews getViewAt(int position) { // Get widget settings final WidgetPrefs widgetPrefs = new WidgetPrefs(mContext, mAppWidgetId); if (!widgetPrefs.isPresent()) { return null; } // load date formatter if not present if (mDateFormatter == null) { mDateFormatter = TimeFormatter.getLocalFormatterMicro(mContext); } final long listId = widgetPrefs.getLong(ListWidgetConfig.KEY_LIST, ListWidgetConfig.ALL_LISTS_ID); final int theme = widgetPrefs.getInt(ListWidgetConfig.KEY_THEME, ListWidgetConfig.DEFAULT_THEME); final int primaryTextColor = widgetPrefs.getInt( ListWidgetConfig.KEY_TEXTPRIMARY, ListWidgetConfig.DEFAULT_TEXTPRIMARY); final int rows = widgetPrefs.getInt(ListWidgetConfig.KEY_TITLEROWS, ListWidgetConfig.DEFAULT_ROWS); final boolean isCheckboxHidden = widgetPrefs.getBoolean( ListWidgetConfig.KEY_HIDDENCHECKBOX, false); boolean isDateHidden = widgetPrefs.getBoolean( ListWidgetConfig.KEY_HIDDENDATE, false); // TODO rest // boolean isHeader = false; String sTemp = ""; if (weekdayFormatter == null) { weekdayFormatter = TimeFormatter .getLocalFormatterWeekday(mContext); } RemoteViews rv = null; if (mCursor.moveToPosition(position)) { if (mCursor.getLong(0) < 1) { // Header // if (mCursor.getViewType() == HeaderCursor.headerType) { final int itemId = R.layout.widgetlist_header; rv = new RemoteViews(mContext.getPackageName(), itemId); rv.setTextColor(android.R.id.text1, primaryTextColor); rv.setBoolean(itemId, "setClickable", false); sTemp = mCursor.getString(1); if (Task.HEADER_KEY_OVERDUE.equals(sTemp)) { sTemp = mContext .getString(R.string.date_header_overdue); } else if (Task.HEADER_KEY_TODAY.equals(sTemp)) { sTemp = mContext.getString(R.string.date_header_today); } else if (Task.HEADER_KEY_PLUS1.equals(sTemp)) { sTemp = mContext .getString(R.string.date_header_tomorrow); } else if (Task.HEADER_KEY_PLUS2.equals(sTemp) || Task.HEADER_KEY_PLUS3.equals(sTemp) || Task.HEADER_KEY_PLUS4.equals(sTemp)) { sTemp = weekdayFormatter.format(new Date(mCursor .getLong(4))); } else if (Task.HEADER_KEY_LATER.equals(sTemp)) { sTemp = mContext.getString(R.string.date_header_future); } else if (Task.HEADER_KEY_NODATE.equals(sTemp)) { sTemp = mContext.getString(R.string.date_header_none); } else if (Task.HEADER_KEY_COMPLETE.equals(sTemp)) { sTemp = mContext .getString(R.string.date_header_completed); } // Set text rv.setTextViewText(android.R.id.text1, sTemp); } else { final int itemId = R.layout.widgetlist_item; rv = new RemoteViews(mContext.getPackageName(), itemId); // Complete checkbox final int visibleCheckBox; final int hiddenCheckBox; if (theme == ListWidgetConfig.THEME_LIGHT) { hiddenCheckBox = R.id.completedCheckBoxDark; visibleCheckBox = R.id.completedCheckBoxLight; } else { hiddenCheckBox = R.id.completedCheckBoxLight; visibleCheckBox = R.id.completedCheckBoxDark; } rv.setViewVisibility(hiddenCheckBox, View.GONE); rv.setViewVisibility(visibleCheckBox, isCheckboxHidden ? View.GONE : View.VISIBLE); // Spacer rv.setViewVisibility(R.id.itemSpacer, isCheckboxHidden ? View.GONE : View.VISIBLE); // Date if (mCursor.isNull(4)) { rv.setTextViewText(R.id.dueDate, ""); isDateHidden = true; } else { rv.setTextViewText(R.id.dueDate, mDateFormatter .format(new Date(mCursor.getLong(4)))); } rv.setViewVisibility(R.id.dueDate, isDateHidden ? View.GONE : View.VISIBLE); rv.setTextColor(R.id.dueDate, primaryTextColor); // Text rv.setTextColor(android.R.id.text1, primaryTextColor); rv.setInt(android.R.id.text1, "setMaxLines", rows); // Only if task it not locked if (mCursor.getInt(9) != 1) { rv.setTextViewText( android.R.id.text1, TitleNoteTextView.getStyledText( mCursor.getString(1), mCursor.getString(2), 1.0f, 1, 0)); } else { // Just title rv.setTextViewText( android.R.id.text1, TitleNoteTextView.getStyledText( mCursor.getString(1), 1.0f, 1, 0)); } // Set the click intent if (widgetPrefs.getBoolean(ListWidgetConfig.KEY_LOCKSCREEN, false)) { final Intent clickIntent = new Intent(); clickIntent .setAction(Intent.ACTION_EDIT) .setData(Task.getUri(mCursor.getLong(0))) .putExtra(TaskDetailFragment.ARG_ITEM_LIST_ID, listId); rv.setOnClickFillInIntent(R.id.widget_item, clickIntent); } else { final Intent fillInIntent = new Intent(); fillInIntent.setAction(ListWidgetProvider.CLICK_ACTION); fillInIntent.putExtra(ListWidgetProvider.EXTRA_NOTE_ID, mCursor.getLong(0)); fillInIntent.putExtra(ListWidgetProvider.EXTRA_LIST_ID, listId); rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); } // Set complete broadcast // If not on lock screen, send broadcast to complete. // Otherwise, have to open note final Intent completeIntent = new Intent(); if (widgetPrefs.getBoolean(ListWidgetConfig.KEY_LOCKSCREEN, false)) { completeIntent .setAction(Intent.ACTION_EDIT) .setData(Task.getUri(mCursor.getLong(0))) .putExtra(TaskDetailFragment.ARG_ITEM_LIST_ID, listId); } else { completeIntent.setAction( ListWidgetProvider.COMPLETE_ACTION).putExtra( ListWidgetProvider.EXTRA_NOTE_ID, mCursor.getLong(0)); } rv.setOnClickFillInIntent(R.id.completedCheckBoxDark, completeIntent); rv.setOnClickFillInIntent(R.id.completedCheckBoxLight, completeIntent); } } return rv; } @Override public RemoteViews getLoadingView() { // We aren't going to return a default loading view in this sample return null; } @Override public int getViewTypeCount() { return 2; } @Override public long getItemId(int position) { return position; } @Override public boolean hasStableIds() { return true; } @Override public void onDataSetChanged() { // Revert back to our process' identity so we can work with our // content provider final long identityToken = Binder.clearCallingIdentity(); // Refresh the cursor if (mCursor != null) { mCursor.close(); } // (re)load dateformatter in case preferences changed mDateFormatter = TimeFormatter.getLocalFormatterMicro(mContext); // Get widget settings final WidgetPrefs widgetPrefs = new WidgetPrefs(mContext, mAppWidgetId); if (widgetPrefs != null) { final Uri targetUri; final long listId = widgetPrefs.getLong( ListWidgetConfig.KEY_LIST, ListWidgetConfig.ALL_LISTS_ID); final String sortSpec; final String sortType = widgetPrefs.getString( ListWidgetConfig.KEY_SORT_TYPE, mContext.getString(R.string.default_sorttype)); if (sortType.equals(mContext .getString(R.string.const_possubsort)) && listId > 0) { targetUri = Task.URI; sortSpec = Task.Columns.LEFT; } else if (sortType.equals(mContext .getString(R.string.const_modified))) { targetUri = Task.URI; sortSpec = Task.Columns.UPDATED + " DESC"; } // due date sorting else if (sortType.equals(mContext .getString(R.string.const_duedate))) { targetUri = Task.URI_SECTIONED_BY_DATE; sortSpec = null; } // Alphabetic else { targetUri = Task.URI; sortSpec = mContext.getString(R.string.const_as_alphabetic, Task.Columns.TITLE); ; } String listWhere = null; String[] listArg = null; if (listId > 0) { listWhere = Task.Columns.DBLIST + " IS ? AND " + Task.Columns.COMPLETED + " IS NULL"; listArg = new String[] { Long.toString(listId) }; } else { listWhere = Task.Columns.COMPLETED + " IS NULL"; listArg = null; } mCursor = mContext.getContentResolver().query(targetUri, Task.Columns.FIELDS, listWhere, listArg, sortSpec); } // Restore the identity - not sure if it's needed since we're going // to return right here, but it just *seems* cleaner Binder.restoreCallingIdentity(identityToken); } } }