/* * TV-Browser for Android * Copyright (C) 2013-2014 René Mach (rene@tvbrowser.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to use, copy, modify or merge the Software, * furthermore to publish and distribute the Software free of charge without modifications and to * permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.tvbrowser.widgets; import java.util.Calendar; import java.util.Date; import org.tvbrowser.content.TvBrowserContentProvider; import org.tvbrowser.settings.SettingConstants; import org.tvbrowser.tvbrowser.R; import org.tvbrowser.utils.CompatUtils; import org.tvbrowser.utils.IOUtils; import org.tvbrowser.utils.PrefUtils; import org.tvbrowser.utils.UiUtils; import android.app.AlarmManager; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Binder; import android.os.Bundle; import android.preference.PreferenceManager; import android.text.Spannable; import android.text.TextUtils; import android.text.format.DateFormat; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; /** * Service for showing currently running programs as widget. * * @author René Mach */ public class RunningProgramsRemoteViewsService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new RunningProgramsRemoteViewsFactory(getApplicationContext(),intent.getExtras()); } class RunningProgramsRemoteViewsFactory implements RemoteViewsFactory { private Context mContext; private Cursor mCursor; private int mAppWidgetId; private int mIdIndex; private int mStartTimeIndex; private int mEndTimeIndex; private int mTitleIndex; private int mChannelNameIndex; private int mOrderNumberIndex; private int mLogoIndex; private int mEpisodeIndex; private int mCategoryIndex; private int mMarkingPluginsIndex; private int mMarkingFavoriteIndex; private int mMarkingReminderIndex; private int mMarkingFavoriteReminderIndex; private int mMarkingSyncIndex; private int mVerticalPadding; private boolean mShowChannelName; private boolean mShowChannelLogo; private boolean mShowBigChannelLogo; private boolean mShowEpisode; private boolean mShowCategories; private boolean mShowMarkings; private boolean mShowOrderNumber; private boolean mChannelClickToProgramsList; private float mTextScale; private int[] mUserDefindedColorChannel; private int[] mUserDefindedColorTime; private int[] mUserDefindedColorTitel; private int[] mUserDefindedColorCategoryDefault; private int[] mUserDefindedColorEpisode; private void executeQuery() { IOUtils.close(mCursor); removeAlarm(); if(IOUtils.isDatabaseAccessible(mContext)) { int currentTime = PreferenceManager.getDefaultSharedPreferences(mContext).getInt(mAppWidgetId + "_" + mContext.getString(R.string.WIDGET_CONFIG_RUNNING_TIME), getResources().getInteger(R.integer.widget_config_running_time_default)); String startTimeColumn = TvBrowserContentProvider.DATA_KEY_STARTTIME; if(currentTime == -2) { startTimeColumn = "MIN( "+TvBrowserContentProvider.DATA_KEY_STARTTIME+" ) AS " +TvBrowserContentProvider.DATA_KEY_STARTTIME; } final String[] projection = new String[] { TvBrowserContentProvider.KEY_ID, startTimeColumn, TvBrowserContentProvider.DATA_KEY_ENDTIME, TvBrowserContentProvider.DATA_KEY_TITLE, TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE, TvBrowserContentProvider.DATA_KEY_CATEGORIES, TvBrowserContentProvider.DATA_KEY_MARKING_MARKING, TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE, TvBrowserContentProvider.DATA_KEY_MARKING_REMINDER, TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE_REMINDER, TvBrowserContentProvider.DATA_KEY_MARKING_SYNC, TvBrowserContentProvider.CHANNEL_KEY_NAME, TvBrowserContentProvider.CHANNEL_KEY_LOGO, TvBrowserContentProvider.CHANNEL_KEY_ORDER_NUMBER, TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID }; long time = System.currentTimeMillis(); if(currentTime > -1) { Calendar now = Calendar.getInstance(); if(PrefUtils.getBooleanValue(R.string.RUNNING_PROGRAMS_NEXT_DAY, R.bool.running_programs_next_day_default)) { int test1 = now.get(Calendar.HOUR_OF_DAY) * 60 + now.get(Calendar.MINUTE); if((test1 - currentTime) > 180) { now.add(Calendar.DAY_OF_YEAR, 1); } } now.set(Calendar.HOUR_OF_DAY, currentTime / 60); now.set(Calendar.MINUTE, currentTime % 60); now.set(Calendar.SECOND, 0); now.set(Calendar.MILLISECOND, 0); time = now.getTimeInMillis(); } String where = " ( " + TvBrowserContentProvider.DATA_KEY_STARTTIME + "<=" + time + " AND " + TvBrowserContentProvider.DATA_KEY_ENDTIME + ">" + time + " ) AND NOT " + TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE + " {0} "; if(currentTime == -2) { where = " ( " +TvBrowserContentProvider.DATA_KEY_STARTTIME+ ">=" + time + " ) AND NOT " + TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE + " {0} ) GROUP BY ( " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " "; } mUserDefindedColorChannel = IOUtils.getActivatedColorFor(PrefUtils.getStringValue(R.string.PREF_WIDGET_COLOR_CHANNEL, null)); mUserDefindedColorTime = IOUtils.getActivatedColorFor(PrefUtils.getStringValue(R.string.PREF_WIDGET_COLOR_TIME, R.string.pref_widget_color_time_default)); mUserDefindedColorTitel = IOUtils.getActivatedColorFor(PrefUtils.getStringValue(R.string.PREF_WIDGET_COLOR_TITLE, R.string.pref_widget_color_title_default)); mUserDefindedColorCategoryDefault = IOUtils.getActivatedColorFor(PrefUtils.getStringValue(R.string.PREF_WIDGET_COLOR_CATEGORY, null)); mUserDefindedColorEpisode = IOUtils.getActivatedColorFor(PrefUtils.getStringValue(R.string.PREF_WIDGET_COLOR_EPISODE, null)); String values = PrefUtils.getFilterSelection(mContext); if(values != null && values.trim().length() > 0) { where = where.replace("{0}", values); } else { where = where.replace("{0}", ""); } final long token = Binder.clearCallingIdentity(); try { if(IOUtils.isDatabaseAccessible(getApplicationContext())) { mCursor = getApplicationContext().getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_WITH_CHANNEL, projection, where, null, TvBrowserContentProvider.CHANNEL_KEY_ORDER_NUMBER + ", " + TvBrowserContentProvider.DATA_KEY_STARTTIME); if(mCursor != null) { mIdIndex = mCursor.getColumnIndex(TvBrowserContentProvider.KEY_ID); mStartTimeIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME); mEndTimeIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_ENDTIME); mTitleIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE); mChannelNameIndex = mCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_NAME); mOrderNumberIndex = mCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_ORDER_NUMBER); mLogoIndex = mCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID); mEpisodeIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE); mCategoryIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_CATEGORIES); mMarkingPluginsIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING); mMarkingFavoriteIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE); mMarkingReminderIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_REMINDER); mMarkingFavoriteReminderIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE_REMINDER); mMarkingSyncIndex = mCursor.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_SYNC); final String logoNamePref = PrefUtils.getStringValue(R.string.PREF_WIDGET_CHANNEL_LOGO_NAME, R.string.pref_widget_channel_logo_name_default); mShowEpisode = PrefUtils.getBooleanValue(R.string.PREF_WIDGET_SHOW_EPISODE, R.bool.pref_widget_show_episode_default); mShowCategories = PrefUtils.getBooleanValue(R.string.PREF_WIDGET_SHOW_CATEGORIES, R.bool.pref_widget_show_categories_default); mShowMarkings = PrefUtils.getBooleanValue(R.string.PREF_WIDGET_SHOW_MARKINGS, R.bool.pref_widget_show_markings_default); mShowChannelName = (logoNamePref.equals("0") || logoNamePref.equals("2")); mShowChannelLogo = (logoNamePref.equals("0") || logoNamePref.equals("1") || logoNamePref.equals("3")); mShowBigChannelLogo = logoNamePref.equals("3"); mShowOrderNumber = PrefUtils.getBooleanValue(R.string.PREF_WIDGET_SHOW_SORT_NUMBER, R.bool.pref_widget_show_sort_number_default); mChannelClickToProgramsList = PrefUtils.getBooleanValue(R.string.PREF_WIDGET_CLICK_TO_CHANNEL_TO_LIST, R.bool.pref_widget_click_to_channel_to_list_default); mTextScale = Float.valueOf(PrefUtils.getStringValue(R.string.PREF_WIDGET_TEXT_SCALE, R.string.pref_widget_text_scale_default)); mVerticalPadding = UiUtils.convertDpToPixel((int)(Float.parseFloat(PrefUtils.getStringValue(R.string.PREF_WIDGET_VERTICAL_PADDING_SIZE, R.string.pref_widget_vertical_padding_size_default))/2),mContext.getResources()); if(mCursor.getCount() > 0) { startAlarm(); } } } } finally { Binder.restoreCallingIdentity(token); } } } private void startAlarm() { final Intent update = new Intent(SettingConstants.UPDATE_RUNNING_APP_WIDGET); update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); final PendingIntent pending = PendingIntent.getBroadcast(mContext, (int)mAppWidgetId, update, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE); alarm.setRepeating(AlarmManager.RTC, ((System.currentTimeMillis()/60000) * 60000) + 60100, 60000, pending); } private void removeAlarm() { AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE); final Intent update = new Intent(SettingConstants.UPDATE_RUNNING_APP_WIDGET); update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); PendingIntent pending = PendingIntent.getBroadcast(mContext, (int)mAppWidgetId, update, PendingIntent.FLAG_NO_CREATE); if(pending != null) { alarmManager.cancel(pending); } } public RunningProgramsRemoteViewsFactory(Context context, Bundle extras) { mContext = context; PrefUtils.initialize(context); SettingConstants.initializeLogoMap(context, false); if(extras != null) { mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } else { mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; } } @Override public void onCreate() { mTextScale = 1.0f; executeQuery(); } @Override public void onDataSetChanged() { executeQuery(); } @Override public void onDestroy() { IOUtils.close(mCursor); removeAlarm(); } @Override public int getCount() { if(mCursor != null && !mCursor.isClosed()) { return mCursor.getCount(); } return 0; } @Override public RemoteViews getViewAt(int position) { final RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.running_programs_widget_row); if(mCursor != null && !mCursor.isClosed() && mCursor.getCount() > position) { mCursor.moveToPosition(position); final String id = mCursor.getString(mIdIndex); final long startTime = mCursor.getLong(mStartTimeIndex); final long endTime = mCursor.getLong(mEndTimeIndex); final CharSequence title = WidgetUtils.getColoredString(mCursor.getString(mTitleIndex),mUserDefindedColorTitel); CharSequence name = mCursor.getString(mChannelNameIndex); final String shortName = SettingConstants.SHORT_CHANNEL_NAMES.get(name); String number = null; final CharSequence episodeTitle = (mShowEpisode && !mCursor.isNull(mEpisodeIndex)) ? WidgetUtils.getColoredString(mCursor.getString(mEpisodeIndex),mUserDefindedColorEpisode) : null; Spannable categorySpan = (mShowCategories && !mCursor.isNull(mCategoryIndex)) ? IOUtils.getInfoString(mCursor.getInt(mCategoryIndex), getResources(), true, mUserDefindedColorCategoryDefault[0] == 1 ? mUserDefindedColorCategoryDefault[1] : null) : null; Spannable marking = WidgetUtils.getMarkings(mContext, mCursor, mShowMarkings, mMarkingPluginsIndex, mMarkingFavoriteIndex, mMarkingReminderIndex, mMarkingFavoriteReminderIndex, mMarkingSyncIndex); if(shortName != null) { name = shortName; } if(mShowOrderNumber) { number = mCursor.getString(mOrderNumberIndex); if(number == null) { number = "0"; } number += "."; name = number + " " + name; } Drawable logo = null; int channelKey = mCursor.getInt(mLogoIndex); if(mShowChannelLogo) { if(mShowBigChannelLogo) { logo = SettingConstants.MEDIUM_LOGO_MAP.get(channelKey); } else { logo = SettingConstants.SMALL_LOGO_MAP.get(channelKey); } } final CharSequence time = WidgetUtils.getColoredString(DateFormat.getTimeFormat(mContext).format(new Date(startTime)),mUserDefindedColorTime); CompatUtils.setRemoteViewsPadding(rv, R.id.running_programs_widget_row, 0, mVerticalPadding, 0, mVerticalPadding); rv.setViewVisibility(R.id.running_programs_widget_row_start_time, View.VISIBLE); rv.setViewVisibility(R.id.running_programs_widget_row_channel, View.VISIBLE); if(startTime <= System.currentTimeMillis() && endTime > System.currentTimeMillis()) { final int length = (int)(endTime - startTime) / 60000; final int progress = (int)(System.currentTimeMillis() - startTime) / 60000; rv.setProgressBar(R.id.running_programs_widget_row_progress, length, progress, false); rv.setViewVisibility(R.id.running_programs_widget_row_progress, View.VISIBLE); } else { rv.setViewVisibility(R.id.running_programs_widget_row_progress, View.GONE); } rv.setTextViewText(R.id.running_programs_widget_row_start_time, time); rv.setTextViewText(R.id.running_programs_widget_row_title, marking != null ? TextUtils.concat(title,marking) : title); if(categorySpan != null && categorySpan.toString().trim().length() > 0) { rv.setViewVisibility(R.id.running_programs_widget_row_categories, View.VISIBLE); rv.setTextViewText(R.id.running_programs_widget_row_categories, categorySpan); } else { rv.setViewVisibility(R.id.running_programs_widget_row_categories, View.GONE); } if(mShowChannelName || logo == null) { name = WidgetUtils.getColoredString(name, mUserDefindedColorChannel); rv.setTextViewText(R.id.running_programs_widget_row_channel_name, name); rv.setViewVisibility(R.id.running_programs_widget_row_channel_name, View.VISIBLE); } else if(number != null) { rv.setTextViewText(R.id.running_programs_widget_row_channel_name, number); rv.setViewVisibility(R.id.running_programs_widget_row_channel_name, View.VISIBLE); } else { rv.setViewVisibility(R.id.running_programs_widget_row_channel_name, View.GONE); } if(logo != null && ((BitmapDrawable)logo).getBitmap() != null) { rv.setImageViewBitmap(R.id.running_programs_widget_row_channel_logo, ((BitmapDrawable)logo).getBitmap()); rv.setViewVisibility(R.id.running_programs_widget_row_channel_logo, View.VISIBLE); } else { rv.setViewVisibility(R.id.running_programs_widget_row_channel_logo, View.GONE); } if(episodeTitle != null) { rv.setTextViewText(R.id.running_programs_widget_row_episode, episodeTitle); rv.setViewVisibility(R.id.running_programs_widget_row_episode, View.VISIBLE); } else { rv.setViewVisibility(R.id.running_programs_widget_row_episode, View.GONE); } if(!CompatUtils.isKeyguardWidget(mAppWidgetId, mContext)) { final Intent fillInIntent = new Intent(); fillInIntent.putExtra(SettingConstants.REMINDER_PROGRAM_ID_EXTRA, Long.valueOf(id)); rv.setOnClickFillInIntent(R.id.running_programs_widget_row_program, fillInIntent); if(mChannelClickToProgramsList) { final Intent startTvbProgramList = new Intent(); startTvbProgramList.putExtra(SettingConstants.CHANNEL_ID_EXTRA, channelKey); startTvbProgramList.putExtra(SettingConstants.EXTRA_START_TIME, startTime); startTvbProgramList.putExtra(SettingConstants.EXTRA_END_TIME, endTime); rv.setOnClickFillInIntent(R.id.running_programs_widget_row_channel, startTvbProgramList); } } } else { rv.setTextViewText(R.id.running_programs_widget_row_title, "Unknown"); rv.setViewVisibility(R.id.running_programs_widget_row_start_time, View.GONE); rv.setViewVisibility(R.id.running_programs_widget_row_episode, View.GONE); rv.setViewVisibility(R.id.running_programs_widget_row_progress, View.GONE); rv.setViewVisibility(R.id.running_programs_widget_row_channel, View.GONE); } float titleFontSize = mTextScale * UiUtils.convertPixelsToSp(mContext.getResources().getDimension(R.dimen.title_font_size),mContext); rv.setFloat(R.id.running_programs_widget_row_channel_name, "setTextSize", titleFontSize); rv.setFloat(R.id.running_programs_widget_row_title, "setTextSize", titleFontSize); rv.setFloat(R.id.running_programs_widget_row_start_time, "setTextSize", titleFontSize); rv.setFloat(R.id.running_programs_widget_row_categories, "setTextSize", mTextScale * UiUtils.convertPixelsToSp(mContext.getResources().getDimension(R.dimen.prog_list_categories_font_size),mContext)); rv.setFloat(R.id.running_programs_widget_row_episode, "setTextSize", mTextScale * UiUtils.convertPixelsToSp(mContext.getResources().getDimension(R.dimen.episode_font_size),mContext)); return rv; } @Override public RemoteViews getLoadingView() { return null; } @Override public int getViewTypeCount() { return 1; } @Override public long getItemId(int position) { if(mCursor != null && !mCursor.isClosed() && mCursor.moveToPosition(position)) { return mCursor.getLong(mIdIndex); } return position; } @Override public boolean hasStableIds() { return true; } } }