/*
* TV-Browser for Android
* Copyright (C) 2013 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.tvbrowser;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.CRC32;
import java.util.zip.GZIPInputStream;
import org.tvbrowser.content.TvBrowserContentProvider;
import org.tvbrowser.settings.SettingConstants;
import org.tvbrowser.utils.CompatUtils;
import org.tvbrowser.utils.IOUtils;
import org.tvbrowser.utils.PrefUtils;
import org.tvbrowser.utils.ProgramUtils;
import org.tvbrowser.utils.UiUtils;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.SparseArrayCompat;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import android.widget.Toast;
import de.epgpaid.EPGpaidDataConnection;
/**
* The update service for the data of TV-Browser.
*
* @author René Mach
*/
public class TvDataUpdateService extends Service {
public static final String TAG = "TV_DATA_UPDATE_SERVICE";
public static final int TYPE_UPDATE_MANUELL = 1;
public static final int TYPE_UPDATE_AUTO = 2;
private WakeLock mWakeLock;
public static final String KEY_TYPE = "TYPE";
public static final int TYPE_TV_DATA = 1;
public static final int TYPE_CHANNEL = 2;
public static final int TYPE_REMINDER_DOWN = 3;
public static final int TYPE_SYNCHRONIZE_UP = 4;
private static final int LEVEL_BASE = 0;
private static final int LEVEL_MORE = 1;
private static final int LEVEL_PICTURE = 2;
// max size of a data field that can be accepted in bytes
private static final int MAX_DATA_SIZE = 25 * 1024;
private ExecutorService mThreadPool;
private ExecutorService mDataUpdatePool;
private Handler mHandler;
private static final int ID_NOTIFY = 511;
private NotificationCompat.Builder mBuilder;
private int mCurrentDownloadCount;
private int mUnsuccessfulDownloads;
private int mDaysToLoad;
private static Thread ON_START_COMMAND_THEAD;
private Hashtable<String, Hashtable<String, CurrentDataHolder>> mCurrentData;
private Hashtable<String, int[]> mCurrentVersionIDs;
private MemorySizeConstrictedDatabaseOperation mDataDatabaseOperation;
private MemorySizeConstrictedDatabaseOperation mVersionDatabaseOperation;
private ArrayList<String> mSyncFavorites;
private DontWantToSeeExclusion[] mDontWantToSeeValues;
private ArrayList<String> mChannelsNew;
private ArrayList<Integer> mChannelsUpdate;
private Set<String> mEpgPaidChannelIds;
private BroadcastReceiver mReceiverConnectivityChange;
private boolean mIsAutoUpdate;
private boolean mOnlyWifi;
private boolean mIsConnected;
private boolean mConnectionLost;
private boolean mInstableConnectionAcceptable;
private int mCountTimedOutConnections;
private int mInternetConnectionTimeout;
private void checkAndSetConnectionState(long downloadStart) {
doLog("INSTABLE INTERNET CONNECTION ACCEPTABLE: " + mInstableConnectionAcceptable + " " + mInternetConnectionTimeout + " TIMED OUT: " + mCountTimedOutConnections + " IS CONNECTED: " + mIsConnected);
if(!mInstableConnectionAcceptable) {
if(System.currentTimeMillis() - downloadStart > 28000) {
mCountTimedOutConnections++;
}
if(mCountTimedOutConnections > 5) {
mIsConnected = false;
mConnectionLost = true;
}
}
}
private static final Comparator<File> DATA_FILE_OLD_COMPARATOR = new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
final int lIndex = lhs.getName().lastIndexOf("_old_");
final int rIndex = lhs.getName().lastIndexOf("_old_");
int result = 0;
if(lIndex != -1 && rIndex != -1) {
try {
int lVersion = Integer.parseInt(lhs.getName().substring(lIndex+5));
int rVersion = Integer.parseInt(rhs.getName().substring(rIndex+5));
if(lVersion - rVersion < 0) {
result = -1;
}
else if(lVersion - rVersion > 0) {
result = 1;
}
}catch(NumberFormatException nfe) {}
}
else if(lIndex != -1) {
result = -1;
}
else if(rIndex != -1) {
result = 1;
}
return result;
}
};
private static final String GROUP_FILE = "groups.txt";
private static final String DEFAULT_GROUPS_URL = "http://www.tvbrowser.org/listings/";
private static final String[] DEFAULT_GROUPS_URL_MIRRORS = {
"http://tvbrowser.dyndns.tv/",
"http://tvbrowser1.sam-schwedler.de/",
"http://mirror.sperrgebiet.org/tvbrowser",
"http://tvbrowser.qwws.net/"
};
private static final String[] FIELDS_LEVEL_BASE = {
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.DATA_KEY_ENDTIME,
TvBrowserContentProvider.DATA_KEY_TITLE,
TvBrowserContentProvider.DATA_KEY_TITLE_ORIGINAL,
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE,
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE_ORIGINAL,
TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_REGIE,
TvBrowserContentProvider.DATA_KEY_CUSTOM_INFO,
TvBrowserContentProvider.DATA_KEY_CATEGORIES,
TvBrowserContentProvider.DATA_KEY_AGE_LIMIT,
TvBrowserContentProvider.DATA_KEY_WEBSITE_LINK,
TvBrowserContentProvider.DATA_KEY_GENRE,
TvBrowserContentProvider.DATA_KEY_ORIGIN,
TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME,
TvBrowserContentProvider.DATA_KEY_VPS,
TvBrowserContentProvider.DATA_KEY_SCRIPT,
TvBrowserContentProvider.DATA_KEY_REPETITION_FROM,
TvBrowserContentProvider.DATA_KEY_MUSIC,
TvBrowserContentProvider.DATA_KEY_MODERATION,
TvBrowserContentProvider.DATA_KEY_YEAR,
TvBrowserContentProvider.DATA_KEY_REPETITION_ON,
TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER,
TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT,
TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER,
TvBrowserContentProvider.DATA_KEY_PRODUCER,
TvBrowserContentProvider.DATA_KEY_CAMERA,
TvBrowserContentProvider.DATA_KEY_CUT,
TvBrowserContentProvider.DATA_KEY_OTHER_PERSONS,
TvBrowserContentProvider.DATA_KEY_RATING,
TvBrowserContentProvider.DATA_KEY_PRODUCTION_FIRM,
TvBrowserContentProvider.DATA_KEY_AGE_LIMIT_STRING,
TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR,
TvBrowserContentProvider.DATA_KEY_ADDITIONAL_INFO,
TvBrowserContentProvider.DATA_KEY_SERIES,
TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT,
TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT,
TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES,
TvBrowserContentProvider.DATA_KEY_INFO_BLACK_AND_WHITE,
TvBrowserContentProvider.DATA_KEY_INFO_4_TO_3,
TvBrowserContentProvider.DATA_KEY_INFO_16_TO_9,
TvBrowserContentProvider.DATA_KEY_INFO_MONO,
TvBrowserContentProvider.DATA_KEY_INFO_STEREO,
TvBrowserContentProvider.DATA_KEY_INFO_DOLBY_SOURROUND,
TvBrowserContentProvider.DATA_KEY_INFO_DOLBY_DIGITAL_5_1,
TvBrowserContentProvider.DATA_KEY_INFO_SECOND_AUDIO_PROGRAM,
TvBrowserContentProvider.DATA_KEY_INFO_CLOSED_CAPTION,
TvBrowserContentProvider.DATA_KEY_INFO_LIVE,
TvBrowserContentProvider.DATA_KEY_INFO_OMU,
TvBrowserContentProvider.DATA_KEY_INFO_FILM,
TvBrowserContentProvider.DATA_KEY_INFO_SERIES,
TvBrowserContentProvider.DATA_KEY_INFO_NEW,
TvBrowserContentProvider.DATA_KEY_INFO_AUDIO_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_INFO_NEWS,
TvBrowserContentProvider.DATA_KEY_INFO_SHOW,
TvBrowserContentProvider.DATA_KEY_INFO_MAGAZIN,
TvBrowserContentProvider.DATA_KEY_INFO_HD,
TvBrowserContentProvider.DATA_KEY_INFO_DOCUMENTATION,
TvBrowserContentProvider.DATA_KEY_INFO_ART,
TvBrowserContentProvider.DATA_KEY_INFO_SPORT,
TvBrowserContentProvider.DATA_KEY_INFO_CHILDREN,
TvBrowserContentProvider.DATA_KEY_INFO_OTHER,
TvBrowserContentProvider.DATA_KEY_INFO_SIGN_LANGUAGE
};
private static final String[] FIELDS_LEVEL_MORE = {
TvBrowserContentProvider.DATA_KEY_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_ACTORS
};
private static final String[] FIELDS_LEVEL_PICTURE = {
TvBrowserContentProvider.DATA_KEY_PICTURE,
TvBrowserContentProvider.DATA_KEY_PICTURE_COPYRIGHT,
TvBrowserContentProvider.DATA_KEY_PICTURE_DESCRIPTION
};
private static final String[] FIELDS_EPGPAID_POSSIBLE = {
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE,
TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE_ORIGINAL,
TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_REGIE,
TvBrowserContentProvider.DATA_KEY_PRODUCER,
TvBrowserContentProvider.DATA_KEY_CAMERA,
TvBrowserContentProvider.DATA_KEY_SCRIPT,
TvBrowserContentProvider.DATA_KEY_REPETITION_FROM,
TvBrowserContentProvider.DATA_KEY_MUSIC,
TvBrowserContentProvider.DATA_KEY_MODERATION,
TvBrowserContentProvider.DATA_KEY_DESCRIPTION,
TvBrowserContentProvider.DATA_KEY_ACTORS,
TvBrowserContentProvider.DATA_KEY_ADDITIONAL_INFO,
TvBrowserContentProvider.DATA_KEY_SERIES,
TvBrowserContentProvider.DATA_KEY_PICTURE,
TvBrowserContentProvider.DATA_KEY_PICTURE_COPYRIGHT,
TvBrowserContentProvider.DATA_KEY_PICTURE_DESCRIPTION
};
private boolean mShowNotification;
@Override
public void onCreate() {
super.onCreate();
mDaysToLoad = 2;
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.ic_stat_notify);
mBuilder.setOngoing(true);
mHandler = new Handler();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public synchronized int onStartCommand(final Intent intent, int flags, int startId) {
if(!isRunning() && IOUtils.isDatabaseAccessible(this)) {
ON_START_COMMAND_THEAD = new Thread("DATA UPDATE ON START COMMOAND THREAD") {
public void run() {
setPriority(NORM_PRIORITY);
Logging.openLogForDataUpdate(TvDataUpdateService.this);
mInstableConnectionAcceptable = PrefUtils.getBooleanValue(R.string.PREF_DATA_UPDATE_INSTABLE_CONNECTION_ACCEPTABLE, R.bool.pref_data_update_instable_conncetion_acceptable_default);
if(mInstableConnectionAcceptable) {
mInternetConnectionTimeout = 30000;
}
else {
mInternetConnectionTimeout = 15000;
}
doLog("Received intent: " + intent);
if(intent != null) {
doLog("Extra Type: " + intent.getIntExtra(KEY_TYPE, TYPE_TV_DATA));
doLog("Extra Data Update Type: " + intent.getIntExtra(SettingConstants.EXTRA_DATA_UPDATE_TYPE, TYPE_UPDATE_AUTO));
}
boolean isConnected = false;
mOnlyWifi = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_SHARED_GLOBAL, TvDataUpdateService.this).getBoolean(getString(R.string.PREF_AUTO_UPDATE_ONLY_WIFI), getResources().getBoolean(R.bool.pref_auto_update_only_wifi_default));
boolean isInternetConnectionAutoUpdate = false;
mIsAutoUpdate = false;
if(intent != null) {
if(intent.getIntExtra(SettingConstants.EXTRA_DATA_UPDATE_TYPE, TYPE_UPDATE_AUTO) == TYPE_UPDATE_MANUELL) {
mOnlyWifi = false;
}
else {
mIsAutoUpdate = true;
}
isInternetConnectionAutoUpdate = intent.getBooleanExtra(SettingConstants.EXTRA_DATA_UPDATE_TYPE_INTERNET_CONNECTION, false);
}
if(isInternetConnectionAutoUpdate) {
try {
sleep(15000);
} catch (InterruptedException e) {}
}
final ConnectivityManager connMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo lan = CompatUtils.getLanNetworkIfPossible(connMgr);
NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if((wifi != null && wifi.isConnected()) || (lan != null && lan.isConnected())) {
isConnected = true;
}
if(!isConnected && !mOnlyWifi && mobile != null && mobile.isConnected()) {
isConnected = true;
}
if(isConnected && intent != null) {
mCountTimedOutConnections = 0;
mIsConnected = true;
mConnectionLost = false;
mReceiverConnectivityChange = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean isConnected = false;
NetworkInfo lan = CompatUtils.getLanNetworkIfPossible(connMgr);
NetworkInfo wifi = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo mobile = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if((wifi != null && wifi.isConnected()) || (lan != null && lan.isConnected())) {
isConnected = true;
}
if(!isConnected && !mOnlyWifi && mobile != null && mobile.isConnected()) {
isConnected = true;
}
if(!mConnectionLost) {
mConnectionLost = mIsConnected && !isConnected;
}
mIsConnected = isConnected;
}
};
registerReceiver(mReceiverConnectivityChange, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
if(intent.getIntExtra(KEY_TYPE, TYPE_TV_DATA) == TYPE_TV_DATA) {
mDaysToLoad = intent.getIntExtra(getResources().getString(R.string.DAYS_TO_DOWNLOAD), Integer.parseInt(getResources().getString(R.string.days_to_download_default)));
updateTvData();
}
else if(intent.getIntExtra(KEY_TYPE, TYPE_TV_DATA) == TYPE_CHANNEL) {
updateChannels(false);
}
else if(intent.getIntExtra(KEY_TYPE, TYPE_TV_DATA) == TYPE_REMINDER_DOWN) {
startSynchronizeRemindersDown(intent.getBooleanExtra(SettingConstants.SYNCHRONIZE_SHOW_INFO_EXTRA, true));
}
else if(intent.getIntExtra(KEY_TYPE, TYPE_TV_DATA) == TYPE_SYNCHRONIZE_UP) {
if(intent.hasExtra(SettingConstants.SYNCHRONIZE_UP_URL_EXTRA)) {
String address = intent.getStringExtra(SettingConstants.SYNCHRONIZE_UP_URL_EXTRA);
String value = intent.getStringExtra(SettingConstants.SYNCHRONIZE_UP_VALUE_EXTRA);
boolean showInfo = intent.getBooleanExtra(SettingConstants.SYNCHRONIZE_SHOW_INFO_EXTRA, true);
startSynchronizeUp(showInfo, value, address);
}
}
else {
stopSelfInternal();
}
}
else {
mIsConnected = false;
mBuilder.setContentTitle(getResources().getText(R.string.update_notification_title));
startForeground(ID_NOTIFY, mBuilder.build());
doLog("NO UPDATE DONE, NO INTERNET CONNECTION OR NO INTENT, PROCESS EXISTING DATA");
handleStoredDataFromKilledUpdate(isConnected);
}
}
};
ON_START_COMMAND_THEAD.start();
}
return Service.START_STICKY;
}
public static final boolean isRunning() {
return ON_START_COMMAND_THEAD != null && ON_START_COMMAND_THEAD.isAlive();
}
private void acquireWakeLock() {
handleWakeLock(true);
}
private void releaseWakeLock() {
handleWakeLock(false);
}
private synchronized void handleWakeLock(boolean acquire) {
if(mWakeLock != null) {
doLog("TVBUPDATE_LOCK isHeld: " + mWakeLock.isHeld());
if(mWakeLock.isHeld()) {
mWakeLock.release();
doLog("TVBUPDATE_LOCK released");
doLog("TVBUPDATE_LOCK isHeld: " + mWakeLock.isHeld());
}
}
if(acquire) {
final PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if(pm != null) {
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TVBUPDATE_LOCK");
mWakeLock.setReferenceCounted(false);
mWakeLock.acquire(10*60000L);
doLog("TVBUPDATE_LOCK acquired for 2h.");
}
}
}
private void loadEpgPaidChannelIdsForDataUpdate() {
final String userName = PrefUtils.getStringValue(R.string.PREF_EPGPAID_USER, null);
final String password = PrefUtils.getStringValue(R.string.PREF_EPGPAID_PASSWORD, null);
if(userName != null && password != null && userName.trim().length() > 0 && password.trim().length() > 0) {
mEpgPaidChannelIds = PrefUtils.getStringSetValue(R.string.PREF_EPGPAID_DATABASE_CHANNEL_IDS, new HashSet<String>());
}
else {
mEpgPaidChannelIds = new HashSet<String>(0);
}
}
private void handleStoredDataFromKilledUpdate(boolean syncAllowed) {
doLog("handleStoredDataFromKilledUpdate()");
acquireWakeLock();
final NotificationManager notification = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mShowNotification = true;
mUnsuccessfulDownloads = 0;
doLog("Favorite.handleDataUpdateStarted()");
Favorite.handleDataUpdateStarted();
loadEpgPaidChannelIdsForDataUpdate();
final File path = IOUtils.getDownloadDirectory(TvDataUpdateService.this.getApplicationContext());
if(path.isDirectory()) {
File[] oldDataFiles = path.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase(Locale.GERMAN).endsWith(".prog.gz");
}
});
if(oldDataFiles != null && oldDataFiles.length > 0) {
mBuilder.setContentText(getString(R.string.update_data_notification_reload_file));
mBuilder.setProgress(oldDataFiles.length, 0, false);
notification.notify(ID_NOTIFY, mBuilder.build());
final HashMap<String, ChannelUpdate> updateMap = new HashMap<String, TvDataUpdateService.ChannelUpdate>();
final String[] projection = new String[] {TvBrowserContentProvider.KEY_ID,TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE,TvBrowserContentProvider.GROUP_KEY_GROUP_ID};
final SparseArrayCompat<String> groupMap = new SparseArrayCompat<String>();
final String[] groupProjection = new String[] {TvBrowserContentProvider.KEY_ID,TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID};
final Cursor groupCursor = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_GROUPS, groupProjection, null, null, null);
try {
if(IOUtils.prepareAccess(groupCursor)) {
final int keyColumn = groupCursor.getColumnIndex(TvBrowserContentProvider.KEY_ID);
final int dataServiceColumn = groupCursor.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID);
while(groupCursor.moveToNext()) {
int key = groupCursor.getInt(keyColumn);
String dataServiceId = groupCursor.getString(dataServiceColumn);
groupMap.put(key, dataServiceId);
}
}
}finally {
IOUtils.close(groupCursor);
}
DataHandler epgFreeDataHandler = new EPGfreeDataHandler();
DataHandler epgDoanteDataHandler = new EPGdonateDataHandler();
for(int i = 0; i < oldDataFiles.length; i++) {
mBuilder.setProgress(oldDataFiles.length, i+1, false);
notification.notify(ID_NOTIFY, mBuilder.build());
File file = oldDataFiles[i];
String[] fileParts = file.getName().split("_");
String key = "";
for(String filePart : fileParts) {
if(filePart.equals("base") || filePart.contains("16-00") || filePart.contains("00-16")) {
break;
}
key += filePart + "_";
}
if(key.trim().length() > 0) {
key = key.substring(0,key.length()-1);
ChannelUpdate update = updateMap.get(key);
if(update == null) {
final int firstUnderline = key.indexOf("_");
final int secondUnderline = key.indexOf("_",firstUnderline+1);
final String country = key.substring(firstUnderline + 1, secondUnderline);
final String channelId = key.substring(secondUnderline+1);
final String where = TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY + "=\"" + country +"\" AND " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + "=\"" + channelId +"\" AND " + TvBrowserContentProvider.CHANNEL_KEY_SELECTION;
Cursor channel = null;
try {
channel = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, projection, where, null, null);
if(channel != null && channel.moveToFirst()) {
try {
final int firstMinus = key.indexOf("-");
final int secondMinus = key.indexOf("-",firstMinus+1);
String year = key.substring(0,firstMinus);
String month = key.substring(firstMinus+1,secondMinus);
String day = key.substring(secondMinus+1,firstUnderline);
final int channelIntId = channel.getInt(channel.getColumnIndex(TvBrowserContentProvider.KEY_ID));
final String timezone = channel.getString(channel.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE));
final int groupKey = channel.getInt(channel.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID));
Calendar date = Calendar.getInstance(TimeZone.getTimeZone(timezone));
date.set(Integer.parseInt(year), Integer.parseInt(month)-1, Integer.parseInt(day));
String dataServiceId = groupMap.get(groupKey);
DataHandler toUse = epgFreeDataHandler;
if(dataServiceId.equals(SettingConstants.EPG_DONATE_KEY)) {
toUse = epgDoanteDataHandler;
}
update = new ChannelUpdate(toUse, channelIntId, timezone, date.getTimeInMillis());
updateMap.put(key, update);
} catch (Exception e) {
deleteFile(file);
}
}
else {
deleteFile(file);
}
}finally {
IOUtils.close(channel);
}
}
if(update != null) {
update.addDownloadedFile(file);
}
else {
deleteFile(file);
}
}
else {
deleteFile(file);
}
}
if(!updateMap.isEmpty()) {
final UncaughtExceptionHandler handleExc = new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
doLog("UNCAUGHT EXCEPTION Thread: " + thread.getName() + " Throwable " + ex.toString());
}
};
readCurrentVersionIDs();
Set<String> exclusions = PrefUtils.getStringSetValue(R.string.I_DONT_WANT_TO_SEE_ENTRIES, null);
if(exclusions != null) {
mDontWantToSeeValues = new DontWantToSeeExclusion[exclusions.size()];
int i = 0;
for(String exclusion : exclusions) {
mDontWantToSeeValues[i++] = new DontWantToSeeExclusion(exclusion);
}
}
readCurrentData();
mDataUpdatePool = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
mDataDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(TvDataUpdateService.this,TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE);
mVersionDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(TvDataUpdateService.this,TvBrowserContentProvider.CONTENT_URI_DATA_VERSION,10);
/* mDataInsertList = new ArrayList<ContentValues>();
mDataUpdateList = new ArrayList<ContentProviderOperation>();
*/
/* mVersionInsertList = new ArrayList<ContentValues>();
mVersionUpdateList = new ArrayList<ContentProviderOperation>();*/
mCurrentDownloadCount = 0;
mBuilder.setContentText(getString(R.string.update_notification_text));
mBuilder.setProgress(updateMap.size(), 0, false);
notification.notify(ID_NOTIFY, mBuilder.build());
for(String key : updateMap.keySet()) {
updateMap.get(key).startUpdate(notification, updateMap.size(), handleExc);
}
mDataUpdatePool.shutdown();
doLog("WAIT FOR DATA UPDATE FOR: " + updateMap.size() + " MINUTES");
try {
mDataUpdatePool.awaitTermination(updateMap.size(), TimeUnit.MINUTES);
} catch (InterruptedException e) {
doLog("UPDATE DATE INTERRUPTED " + e.getLocalizedMessage());
}
if(!mDataUpdatePool.isTerminated()) {
doLog("NOT HANDLED UPDATES " + mDataUpdatePool.shutdownNow().size());
}
doLog("WAIT FOR DATA UPDATE FOR DONE, DATA: " + mDataUpdatePool.isTerminated());
mShowNotification = false;
if(mDataDatabaseOperation != null) {
mDataDatabaseOperation.finish();
}
if(mVersionDatabaseOperation != null) {
mVersionDatabaseOperation.finish();
}
mBuilder.setProgress(100, 0, true);
notification.notify(ID_NOTIFY, mBuilder.build());
if(mCurrentVersionIDs != null) {
mCurrentVersionIDs.clear();
mCurrentVersionIDs = null;
}
if(mCurrentData != null) {
mCurrentData.clear();
mCurrentData = null;
}
updateMap.clear();
}
}
}
calculateMissingEnds(notification, true, syncAllowed);
}
private void deleteFile(File file) {
if(file != null && !file.delete()) {
file.deleteOnExit();
}
}
private void startSynchronizeRemindersDown(boolean info) {
NotificationManager notification = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
synchronizeRemindersDown(info,notification);
Intent synchronizeRemindersUpDone = new Intent(SettingConstants.REMINDER_DOWN_DONE);
LocalBroadcastManager.getInstance(TvDataUpdateService.this).sendBroadcast(synchronizeRemindersUpDone);
stopSelfInternal();
}
@Override
public void onDestroy() {
doLog("onDestroy() called");
releaseWakeLock();
if(mThreadPool != null && !mThreadPool.isTerminated()) {
int notDownloadedSize = mThreadPool.shutdownNow().size();
doLog("onDestroy(), notDownloadedSize: " + notDownloadedSize);
}
if(mDataUpdatePool != null && !mDataUpdatePool.isTerminated()) {
int notUpdatedSize = mDataUpdatePool.shutdownNow().size();
doLog("onDestroy(), notUpdatedSize: " + notUpdatedSize);
}
if(mDataDatabaseOperation != null) {
mDataDatabaseOperation.cancel();
}
if(mVersionDatabaseOperation != null) {
mVersionDatabaseOperation.cancel();
}
if(mEpgPaidChannelIds != null) {
mEpgPaidChannelIds.clear();
}
if(mReceiverConnectivityChange != null) {
unregisterReceiver(mReceiverConnectivityChange);
mReceiverConnectivityChange = null;
}
mDataDatabaseOperation = null;
mVersionDatabaseOperation = null;
mEpgPaidChannelIds = null;
stopForeground(true);
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).cancel(ID_NOTIFY);
Favorite.handleDataUpdateFinished();
Logging.closeLogForDataUpdate();
super.onDestroy();
}
private void stopSelfInternal() {
if(mReceiverConnectivityChange != null) {
unregisterReceiver(mReceiverConnectivityChange);
mReceiverConnectivityChange = null;
}
if(mConnectionLost && mIsAutoUpdate) {
final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if(pref.getString(getString(R.string.PREF_AUTO_UPDATE_TYPE), getString(R.string.pref_auto_update_type_default)).equals("2")) {
AutoDataUpdateReceiver.reschedule(getApplicationContext(),pref);
}
}
mDataDatabaseOperation = null;
mVersionDatabaseOperation = null;
releaseWakeLock();
if(mCurrentChannelData != null) {
long lastChannelUpdate = PrefUtils.getLongValue(R.string.PREF_LAST_CHANNEL_UPDATE, 0);
Editor edit = PreferenceManager.getDefaultSharedPreferences(TvDataUpdateService.this).edit();
edit.putLong(getString(R.string.PREF_LAST_CHANNEL_UPDATE), System.currentTimeMillis());
if((lastChannelUpdate + (2 * 24 * 60 * 60000L)) < System.currentTimeMillis()) {
Set<String> currentFirstDeletedChannels = PrefUtils.getStringSetValue(R.string.PREF_FIRST_DELETED_CHANNELS, new HashSet<String>());
Set<String> keptDeletedChannels = PrefUtils.getStringSetValue(R.string.PREF_KEPT_DELETED_CHANNELS, new HashSet<String>());
HashSet<String> firstDeletedNew = new HashSet<String>();
HashSet<String> secondDeletedUserChannels = new HashSet<String>();
HashSet<String> keptDeletedChannelsNew = new HashSet<String>();
Set<String> keys = mCurrentChannelData.keySet();
StringBuilder delete = new StringBuilder();
for(String key : keys) {
Object channelValues = mCurrentChannelData.get(key);
String uniqueChannelId = String.valueOf(((Object[])channelValues)[0]);
Integer selection = (Integer)((Object[])channelValues)[2];
if(currentFirstDeletedChannels.contains(uniqueChannelId)) {
if(selection == 1) {Log.d("info2", "ADD " + uniqueChannelId);
secondDeletedUserChannels.add(uniqueChannelId);
}
else {
if(delete.length() > 0) {
delete.append(", ");
}
delete.append(uniqueChannelId);
}
}
else {
firstDeletedNew.add(uniqueChannelId);
}
if(keptDeletedChannels.contains(uniqueChannelId)) {
keptDeletedChannelsNew.add(uniqueChannelId);
}
}
edit.putStringSet(getString(R.string.PREF_FIRST_DELETED_CHANNELS), firstDeletedNew);
edit.putStringSet(getString(R.string.PREF_SECOND_DELETED_CHANNELS), secondDeletedUserChannels);
edit.putStringSet(getString(R.string.PREF_KEPT_DELETED_CHANNELS), keptDeletedChannelsNew);
if(delete.length() > 0) {
delete.insert(0, TvBrowserContentProvider.KEY_ID + " IN ( ");
delete.append(" ) ");
doLog("DELETE REMOVED CHANNELS: " + delete);
int deleteCount = getContentResolver().delete(TvBrowserContentProvider.CONTENT_URI_CHANNELS, delete.toString(), null);
doLog("DELETED REMOVED CHANNELS COUNT: " + deleteCount);
}
}
edit.commit();
mCurrentChannelData.clear();
mCurrentChannelData = null;
}
Logging.closeLogForDataUpdate();
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).cancel(ID_NOTIFY);
stopSelf();
}
private void startSynchronizeUp(boolean info, final String value, final String address) {
NotificationManager notification = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
synchronizeUp(info, value, address, notification);
Intent synchronizeUpDone = new Intent(SettingConstants.SYNCHRONIZE_UP_DONE);
LocalBroadcastManager.getInstance(TvDataUpdateService.this).sendBroadcast(synchronizeUpDone);
stopSelfInternal();
}
private void synchronizeUp(boolean info, final String value, final String address, final NotificationManager notification) {
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_synchronize));
notification.notify(ID_NOTIFY, mBuilder.build());
final String CrLf = "\r\n";
SharedPreferences pref = getSharedPreferences("transportation", Context.MODE_PRIVATE);
String car = pref.getString(SettingConstants.USER_NAME, null);
String bicycle = pref.getString(SettingConstants.USER_PASSWORD, null);
if(car != null && car.trim().length() > 0 && bicycle != null && bicycle.trim().length() > 0) {
String userpass = car.trim() + ":" + bicycle.trim();
String basicAuth = "basic " + Base64.encodeToString(userpass.getBytes(), Base64.NO_WRAP);
URLConnection conn = null;
OutputStream os = null;
InputStream is = null;
try {
URL url = new URL(address);
conn = url.openConnection();
IOUtils.setConnectionTimeoutDefault(conn);
conn.setRequestProperty ("Authorization", basicAuth);
conn.setDoOutput(true);
//String postData = "";
byte[] xmlData = value == null ? getBytesForReminders() : IOUtils.getCompressedData(value.getBytes("UTF-8"));
String message1 = "";
message1 += "-----------------------------4664151417711" + CrLf;
message1 += "Content-Disposition: form-data; name=\"uploadedfile\"; filename=\""+car+".gz\""
+ CrLf;
message1 += "Content-Type: text/plain" + CrLf;
message1 += CrLf;
// the image is sent between the messages in the multipart message.
String message2 = "";
message2 += CrLf + "-----------------------------4664151417711--"
+ CrLf;
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=---------------------------4664151417711");
// might not need to specify the content-length when sending chunked
// data.
conn.setRequestProperty("Content-Length", String.valueOf((message1
.length() + message2.length() + xmlData.length)));
Log.d("info8","open os");
os = conn.getOutputStream();
Log.d("info8",message1);
os.write(message1.getBytes());
// SEND THE IMAGE
int index = 0;
int size = 1024;
do {
Log.d("info8","write:" + index);
if ((index + size) > xmlData.length) {
size = xmlData.length - index;
}
os.write(xmlData, index, size);
index += size;
} while (index < xmlData.length);
Log.d("info8","written:" + index);
Log.d("info8",message2);
os.write(message2.getBytes());
os.flush();
Log.d("info8","open is");
is = conn.getInputStream();
char buff = 512;
int len;
byte[] data = new byte[buff];
do {
Log.d("info8","READ");
len = is.read(data);
if (len > 0) {
Log.d("info8",new String(data, 0, len));
}
} while (len > 0);
Log.d("info8","DONE");
} catch (Exception e) {
/*int response = 0;
if(conn != null) {
try {
response = ((HttpURLConnection)conn).getResponseCode();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}*/
Log.d("info8", "" ,e);
} finally {
Log.d("info8","Close connection");
IOUtils.close(os);
IOUtils.close(is);
IOUtils.disconnect(conn);
}
}
notification.cancel(ID_NOTIFY);
}
private byte[] getBytesForReminders() {
String[] projection = {
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.CHANNEL_TABLE + "." + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID,
TvBrowserContentProvider.GROUP_KEY_GROUP_ID,
TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY,
TvBrowserContentProvider.DATA_KEY_TITLE
};
StringBuilder where = new StringBuilder();
where.append(" ( ").append(TvBrowserContentProvider.DATA_KEY_MARKING_REMINDER).append(" OR ").append(TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE_REMINDER).append(" ) ") ;
final StringBuilder dat = new StringBuilder();
Cursor programs = null; try {
programs = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_WITH_CHANNEL, projection, where.toString(), null, TvBrowserContentProvider.DATA_KEY_STARTTIME);
SparseArrayCompat<SimpleGroupInfo> groupInfo = new SparseArrayCompat<SimpleGroupInfo>();
if(programs!=null && programs.getCount() > 0) {
final CRC32 crc = new CRC32();
programs.moveToPosition(-1);
final int startTimeColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
final int groupKeyColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
final int channelKeyBaseCountryColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY);
final int columnIndexTitle = programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE);
String[] groupProjection = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID,
TvBrowserContentProvider.GROUP_KEY_GROUP_ID
};
Cursor groups = null; try {
groups = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_GROUPS, groupProjection, null, null, null);
if(groups!=null && groups.getCount() > 0) {
groups.moveToPosition(-1);
while(groups.moveToNext()) {
int groupKey = groups.getInt(0);
String dataServiceID = groups.getString(1);
String groupID = groups.getString(2);
String test = SettingConstants.getNumberForDataServiceKey(dataServiceID);
if(test != null) {
dataServiceID = test;
}
groupInfo.put(groupKey, new SimpleGroupInfo(dataServiceID, groupID));
}
}
} finally {IOUtils.close(groups);}
if(groupInfo.size() > 0) {
while(programs.moveToNext()) {
int groupID = programs.getInt(groupKeyColumnIndex);
long startTime = programs.getLong(startTimeColumnIndex) / 60000;
String channelID = programs.getString(1);
String baseCountry = programs.getString(channelKeyBaseCountryColumnIndex);
SimpleGroupInfo info = groupInfo.get(groupID);
String groupId = ":" + info.mGroupID;
if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY).equals(info.mDataServiceID)) {
groupId = "";
}
dat.append(startTime).append(";").append(info.mDataServiceID).append(groupId).append(":").append(baseCountry).append(":").append(channelID);
crc.reset();
try {
crc.update(programs.getString(columnIndexTitle).getBytes("UTF-8"));
dat.append(";").append(crc.getValue());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dat.append("\n");
}
}
}
} finally {IOUtils.close(programs);}
return IOUtils.getCompressedData(dat.toString().getBytes());
}
private void synchronizeRemindersDown(boolean info, final NotificationManager notification) {
if(!SettingConstants.UPDATING_REMINDERS) {
SettingConstants.UPDATING_REMINDERS = true;
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_synchronize_remiders));
notification.notify(ID_NOTIFY, mBuilder.build());
URLConnection connection = null;
BufferedReader read = null;
try {
final URL documentUrl = new URL(SettingConstants.URL_SYNC_BASE + "data/scripts/syncDown.php?type=reminderFromDesktop");
connection = documentUrl.openConnection();
final SharedPreferences pref = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_TRANSPORTATION, TvDataUpdateService.this);
final String car = pref.getString(SettingConstants.USER_NAME, null);
final String bicycle = pref.getString(SettingConstants.USER_PASSWORD, null);
final CRC32 crc = new CRC32();
if(car != null && bicycle != null && car.trim().length() > 0 && bicycle.trim().length() > 0) {
String userpass = car + ":" + bicycle;
String basicAuth = "basic " + Base64.encodeToString(userpass.getBytes(), Base64.NO_WRAP);
connection.setRequestProperty ("Authorization", basicAuth);
read = new BufferedReader(new InputStreamReader(new GZIPInputStream(connection.getInputStream()),"UTF-8"));
String reminder = null;
ArrayList<ContentProviderOperation> updateValuesList = new ArrayList<ContentProviderOperation>();
ArrayList<Intent> markingIntentList = new ArrayList<Intent>();
Hashtable<String, Object> currentGroups = getCurrentGroups();
Hashtable<String, Integer> knownChannels = new Hashtable<String, Integer>();
ArrayList<String> reminderIdList = new ArrayList<String>();
while((reminder = read.readLine()) != null) {
if(reminder != null && reminder.contains(";") && reminder.contains(":")) {
String[] parts = reminder.split(";");
long time = Long.parseLong(parts[0]) * 60000;
String[] idParts = parts[1].split(":");
Object groupInfo = null;
String groupKey = null;
String channelIdKey = null;
if(idParts[0].equals(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_FREE_KEY))) {
groupKey = getGroupsKey(SettingConstants.EPG_FREE_KEY,idParts[1]);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[2];
}
else if(idParts[0].equals(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY))) {
groupKey = getGroupsKey(SettingConstants.EPG_DONATE_KEY,SettingConstants.EPG_DONATE_GROUP_KEY);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[1];
}
if(groupInfo != null) {
String groupChannelKey = getGroupChannelKey(groupKey,channelIdKey);
Integer channelId = knownChannels.get(groupChannelKey);
if(channelId == null) {
String where = " ( " + TvBrowserContentProvider.GROUP_KEY_GROUP_ID + " IS " + (Integer) ((Object[]) groupInfo)[0] + " ) AND ( " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + "=\'" + channelIdKey + "\' ) ";
Cursor channel = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, null, where, null, null);
try {
if(channel.moveToFirst()) {
int channelIdValue = channel.getInt(channel.getColumnIndex(TvBrowserContentProvider.KEY_ID));
channelId = channelIdValue;
knownChannels.put(groupChannelKey, channelId);
}
}finally {
IOUtils.close(channel);
}
}
if(channelId != null) {
String where = " ( " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " = " + channelId + " ) AND ( " + TvBrowserContentProvider.DATA_KEY_STARTTIME + " = " + time + " ) " + " AND ( NOT " + TvBrowserContentProvider.DATA_KEY_REMOVED_REMINDER + " ) ";
Cursor program = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA, null, where, null, null);
try {
if(program.moveToFirst()) {
String title = program.getString(program.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE));
if(parts.length > 2) {
crc.reset();
try {
crc.update(title.getBytes("UTF-8"));
if(Long.parseLong(parts[2]) == crc.getValue()) {
title = null;
}
} catch(Exception uee) {
title = null;
}
}
else {
title = null;
}
if(title == null) {
final boolean marked = program.getInt(program.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_REMINDER)) == 1;
if(!marked) {
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_MARKING_REMINDER, true);
long programID = program.getLong(program.getColumnIndex(TvBrowserContentProvider.KEY_ID));
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, programID));
opBuilder.withValues(values);
updateValuesList.add(opBuilder.build());
Intent intent = new Intent(SettingConstants.MARKINGS_CHANGED);
intent.putExtra(SettingConstants.EXTRA_MARKINGS_ID, programID);
markingIntentList.add(intent);
reminderIdList.add(String.valueOf(programID));
//UiUtils.addReminder(TvDataUpdateService.this, programID, time, TvBrowser.class, true);
}
}
}
}finally {
IOUtils.close(program);
}
}
}
}
}
if(!updateValuesList.isEmpty()) {
if(!reminderIdList.isEmpty()) {
ProgramUtils.addReminderIds(getApplicationContext(), reminderIdList);
ServiceUpdateReminders.startReminderUpdate(TvDataUpdateService.this, true);
}
try {
getContentResolver().applyBatch(TvBrowserContentProvider.AUTHORITY, updateValuesList);
LocalBroadcastManager localBroadcast = LocalBroadcastManager.getInstance(TvDataUpdateService.this);
for(Intent markUpdate : markingIntentList) {
localBroadcast.sendBroadcast(markUpdate);
}
if(info) {
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(TvDataUpdateService.this, R.string.synchronize_reminder_down_done, Toast.LENGTH_SHORT).show();
}
});
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
UiUtils.updateImportantProgramsWidget(TvDataUpdateService.this);
}
else {
if(info) {
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(TvDataUpdateService.this, R.string.synchronize_reminder_down_nothing, Toast.LENGTH_SHORT).show();
}
});
}
}
}
}catch(Exception e) {
Log.d("info", "", e);
} finally {
IOUtils.close(read);
IOUtils.disconnect(connection);
}
SettingConstants.UPDATING_REMINDERS = false;
notification.cancel(ID_NOTIFY);
}
}
private static final String getGroupChannelKey(String groupKey, String channelId) {
return groupKey + "_##_" + channelId;
}
private void syncFavorites(final NotificationManager notification) {
if(mSyncFavorites != null) {
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_synchronize_favorites));
notification.notify(ID_NOTIFY, mBuilder.build());
ArrayList<ContentProviderOperation> updateValuesList = new ArrayList<ContentProviderOperation>();
ArrayList<Intent> markingIntentList = new ArrayList<Intent>();
Hashtable<String, Object> currentGroups = getCurrentGroups();
Hashtable<String, Integer> knownChannels = new Hashtable<String, Integer>();
ArrayList<String> idList = new ArrayList<String>();
final CRC32 crc = new CRC32();
for(String fav : mSyncFavorites) {
if(fav != null && fav.contains(";") && fav.contains(":")) {
String[] parts = fav.split(";");
long time = Long.parseLong(parts[0]) * 60000;
String[] idParts = parts[1].split(":");
Object groupInfo = null;
String groupKey = null;
String channelIdKey = null;
if(idParts[0].equals(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_FREE_KEY))) {
groupKey = getGroupsKey(SettingConstants.EPG_FREE_KEY,idParts[1]);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[2];
}
else if(idParts[0].equals(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY))) {
groupKey = getGroupsKey(SettingConstants.EPG_DONATE_KEY,SettingConstants.EPG_DONATE_GROUP_KEY);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[1];
}
if(groupInfo != null) {
String groupChannelKey = getGroupChannelKey(groupKey,channelIdKey);
Integer channelId = knownChannels.get(groupChannelKey);
if(channelId == null) {
String where = " ( " + TvBrowserContentProvider.GROUP_KEY_GROUP_ID + " IS " + (Integer) ((Object[]) groupInfo)[0] + " ) AND ( " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + "=\'" + channelIdKey + "\' ) ";
Cursor channel = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, null, where, null, null);
try {
if(channel.moveToFirst()) {
int channelIdValue = channel.getInt(channel.getColumnIndex(TvBrowserContentProvider.KEY_ID));
channelId = channelIdValue;
knownChannels.put(groupChannelKey, channelId);
}
}finally {
IOUtils.close(channel);
}
}
if(channelId != null) {
String where = " ( " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " = " + channelId + " ) AND ( " + TvBrowserContentProvider.DATA_KEY_STARTTIME + " = " + time + " ) AND NOT " + TvBrowserContentProvider.DATA_KEY_REMOVED_SYNC + " AND NOT " + TvBrowserContentProvider.DATA_KEY_MARKING_SYNC;
Cursor program = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA, null, where, null, null);
try {
if(program.moveToFirst()) {
String title = program.getString(program.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE));
if(parts.length > 2) {
crc.reset();
try {
crc.update(title.getBytes("UTF-8"));
if(Long.parseLong(parts[2]) == crc.getValue()) {
title = null;
}
} catch(Exception uee) {
title = null;
}
}
else {
title = null;
}
if(title == null) {
boolean markedAsFavorite = program.getInt(program.getColumnIndex(TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE)) == 1;
if(!markedAsFavorite) {
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_MARKING_SYNC, true);
long programID = program.getLong(program.getColumnIndex(TvBrowserContentProvider.KEY_ID));
idList.add(String.valueOf(programID));
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA, programID));
opBuilder.withValues(values);
updateValuesList.add(opBuilder.build());
Intent intent = new Intent(SettingConstants.MARKINGS_CHANGED);
intent.putExtra(SettingConstants.EXTRA_MARKINGS_ID, programID);
markingIntentList.add(intent);
}
}
}
}finally {
IOUtils.close(program);
}
}
}
}
}
if(!updateValuesList.isEmpty()) {
if(!idList.isEmpty()) {
ProgramUtils.addSyncIds(TvDataUpdateService.this, idList);
}
try {
getContentResolver().applyBatch(TvBrowserContentProvider.AUTHORITY, updateValuesList);
LocalBroadcastManager localBroadcast = LocalBroadcastManager.getInstance(TvDataUpdateService.this);
for(Intent markUpdate : markingIntentList) {
localBroadcast.sendBroadcast(markUpdate);
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
UiUtils.updateImportantProgramsWidget(TvDataUpdateService.this);
}
notification.cancel(ID_NOTIFY);
}
mSyncFavorites = null;
}
private Hashtable<String, Object> mCurrentChannelData;
private boolean mHadChannels;
private void updateChannels(final boolean autoUpdate) {
acquireWakeLock();
mBuilder.setProgress(100, 0, true);
mBuilder.setContentTitle(getResources().getText(R.string.channel_notification_title));
mBuilder.setContentText(getResources().getText(R.string.channel_notification_text));
startForeground(ID_NOTIFY, mBuilder.build());
final Editor edit = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_SHARED_GLOBAL, TvDataUpdateService.this).edit();
edit.remove(getString(R.string.PREF_EPGPAID_DATABASE_CHANNEL_IDS));
edit.commit();
mCurrentChannelData = new Hashtable<String, Object>();
mChannelsNew = new ArrayList<String>();
mChannelsUpdate = new ArrayList<Integer>();
final String[] projection = new String[] {TvBrowserContentProvider.KEY_ID,TvBrowserContentProvider.GROUP_KEY_GROUP_ID,TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID,TvBrowserContentProvider.CHANNEL_KEY_NAME,TvBrowserContentProvider.CHANNEL_KEY_SELECTION};
Cursor currentChannels = null;
try {
currentChannels = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, projection, null, null, null);
if(IOUtils.prepareAccess(currentChannels)) {
assert currentChannels != null;
final int idIndex = currentChannels.getColumnIndex(TvBrowserContentProvider.KEY_ID);
final int groupKeyIndex = currentChannels.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
final int channelKeyIndex = currentChannels.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
final int channelNameIndex = currentChannels.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_NAME);
final int channelSelectionIndex = currentChannels.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_SELECTION);
while(currentChannels.moveToNext()) {
String key = IOUtils.getUniqueChannelKey(currentChannels.getString(groupKeyIndex), currentChannels.getString(channelKeyIndex));
mCurrentChannelData.put(key, new Object[] {Integer.valueOf(currentChannels.getInt(idIndex)) , currentChannels.getString(channelNameIndex), Integer.valueOf(currentChannels.getInt(channelSelectionIndex))});
}
}
}finally {
IOUtils.close(currentChannels);
}
mHadChannels = !mCurrentChannelData.isEmpty();
final File path = IOUtils.getDownloadDirectory(TvDataUpdateService.this.getApplicationContext());
final File groups = new File(path,GROUP_FILE);
final File epgPaidChannels = new File(path,"epgPaidData/channels.gz");
if(epgPaidChannels.isFile() && !epgPaidChannels.delete()) {
epgPaidChannels.deleteOnExit();
}
String mirror = getGroupFileMirror();
doLog("LOAD GROUPS FROM '" + mirror + "' to '" + groups + "'");
if(mIsConnected && mirror != null) {
try {
IOUtils.saveUrl(groups.getAbsolutePath(), mirror, mInternetConnectionTimeout);
doLog("START GROUP UPDATE");
updateGroups(groups, path, autoUpdate);
} catch (Throwable t) {
doLog("ERROR AT DOWNLOADING GROUPS ", t);
Intent updateDone = new Intent(SettingConstants.CHANNEL_DOWNLOAD_COMPLETE);
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_SUCCESSFULLY, false);
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_AUTO_UPDATE, autoUpdate);
LocalBroadcastManager.getInstance(TvDataUpdateService.this).sendBroadcast(updateDone);
stopForeground(true);
stopSelfInternal();
}
}
else {
Intent updateDone = new Intent(SettingConstants.CHANNEL_DOWNLOAD_COMPLETE);
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_SUCCESSFULLY, false);
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_AUTO_UPDATE, autoUpdate);
LocalBroadcastManager.getInstance(TvDataUpdateService.this).sendBroadcast(updateDone);
stopForeground(true);
stopSelfInternal();
}
}
private String getGroupFileMirror() {
ArrayList<String> groupUrlList = new ArrayList<String>();
groupUrlList.add(DEFAULT_GROUPS_URL + GROUP_FILE);
for(String url : DEFAULT_GROUPS_URL_MIRRORS) {
groupUrlList.add(url + GROUP_FILE);
}
String choosenMirror = null;
while(choosenMirror == null && !groupUrlList.isEmpty()) {
int index = (int)(Math.random() * groupUrlList.size());
String test = groupUrlList.get(index);
if(mIsConnected && IOUtils.isConnectedToServer(test, 5000)) {
choosenMirror = test;
}
else {
groupUrlList.remove(index);
}
}
return choosenMirror;
}
private final class ChangeableFinalBoolean {
private boolean mValue;
public ChangeableFinalBoolean(boolean value) {
mValue = value;
}
public synchronized boolean getBoolean() {
return mValue;
}
public synchronized void andUpdateBoolean(boolean value) {
mValue = mValue && value;
}
public void setBoolean(boolean value) {
mValue = value;
}
}
private GroupInfo updateGroup(ContentResolver cr, Integer knownId, String dataServiceId, String groupId, String mirrorUrls, ContentValues values) {
GroupInfo result = null;
String fileName = groupId + "_channellist.gz";
String urlFileName = fileName;
String mirrorFileName = groupId + "_mirrorlist.gz";
String mirrorUrlFileName = mirrorFileName;
if(dataServiceId.equals(SettingConstants.EPG_DONATE_KEY)) {
fileName = groupId + "_channels.gz";
urlFileName = "channels.gz";
mirrorUrlFileName = "mirrorlist.gz";
}
if(knownId == null) {
doLog("Insert group '" + groupId + "' into database.");
// The group is not already known, so insert it
Uri insert = cr.insert(TvBrowserContentProvider.CONTENT_URI_GROUPS, values);
doLog("Insert group '" + groupId + "' to URI: " + insert);
int uniqueGroupID = (int)ContentUris.parseId(insert);
String[] urls = loadAvailableMirrorsForGroup(mirrorUrls);
GroupInfo test = new GroupInfo(dataServiceId, urls, urlFileName, fileName, mirrorUrlFileName, mirrorFileName, uniqueGroupID);
if(urls.length > 0) {
doLog("Load channels for group '" + groupId + "' to " + test.getFileName());
result = test;
}
else {
doLog("Update group '" + groupId + "' NO SUCCESS");
}
}
else {
doLog("Update group '" + groupId + "' in database.");
cr.update(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_GROUPS, knownId), values, null, null);
doLog("Update group '" + groupId + "' loadGroupInfoForGroup().");
String[] urls = loadAvailableMirrorsForGroup(mirrorUrls);
GroupInfo test = new GroupInfo(dataServiceId, urls, urlFileName, fileName, mirrorUrlFileName, mirrorFileName, knownId);
if(urls.length > 0) {
doLog("Load channels for group '" + groupId + "' to " + test.getFileName());
result = test;
}
else {
doLog("Update group '" + groupId + "' NO SUCCESS");
}
}
return result;
}
private static final String getGroupsKey(String dataServiceId, String groupId) {
return dataServiceId.trim() + "_##_" + groupId.trim();
}
private Hashtable<String, Object> getCurrentGroups() {
Hashtable<String, Object> currentGroups = new Hashtable<String, Object>();
final String[] projection = new String[] {TvBrowserContentProvider.KEY_ID,TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID,TvBrowserContentProvider.GROUP_KEY_GROUP_ID,TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS};
Cursor currentGroupsQuery = null;
try {
currentGroupsQuery = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_GROUPS, projection, null, null, null);
assert currentGroupsQuery != null;
currentGroupsQuery.moveToPosition(-1);
int keyIndex = currentGroupsQuery.getColumnIndex(TvBrowserContentProvider.KEY_ID);
int dataServiceIndex = currentGroupsQuery.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID);
int groupIndex = currentGroupsQuery.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
int mirrorIndex = currentGroupsQuery.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS);
while(currentGroupsQuery.moveToNext()) {
String key = getGroupsKey(currentGroupsQuery.getString(dataServiceIndex),currentGroupsQuery.getString(groupIndex));
currentGroups.put(key, new Object[] {Integer.valueOf(currentGroupsQuery.getInt(keyIndex)), currentGroupsQuery.getString(mirrorIndex)});
}
}finally {
IOUtils.close(currentGroupsQuery);
}
return currentGroups;
}
private void updateGroups(File groups, final File path, final boolean autoUpdate) {
final ChangeableFinalBoolean success = new ChangeableFinalBoolean(true);
if(groups.isFile()) {
mCountTimedOutConnections = 0;
Hashtable<String, Object> currentGroups = getCurrentGroups();
final NotificationManager notification = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
final ArrayList<GroupInfo> channelMirrors = new ArrayList<GroupInfo>();
final ContentResolver cr = getContentResolver();
mThreadPool = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(groups)));
String line = null;
doLog("Read groups from: " + groups.getName());
while((line = in.readLine()) != null) {
doLog("GROUP LINE: " + line);
final String[] parts = line.split(";");
final String key = SettingConstants.EPG_FREE_KEY + "_##_" + parts[0].trim();
Object currentGroupValues = currentGroups.get(key);
final Integer knownId = currentGroupValues != null ? (Integer)((Object[])currentGroupValues)[0] : null;
final String currentMirrors = currentGroupValues != null ? (String)((Object[])currentGroupValues)[1] : null;
final ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID, SettingConstants.EPG_FREE_KEY);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_ID, parts[0]);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_NAME, parts[1]);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_PROVIDER, parts[2]);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_DESCRIPTION, parts[3]);
boolean useCurrentMirrors = currentMirrors != null;
final StringBuilder builder = new StringBuilder(parts[4]);
if(useCurrentMirrors) {
doLog("CURRENT MIRRORS: " + currentMirrors);
String test = parts[4];
if(!test.endsWith("/")) {
test += "/";
}
useCurrentMirrors = currentMirrors.contains(test);
doLog("USE CURRENT MIRRORS: " + test + " " + useCurrentMirrors);
}
for(int i = 5; i < parts.length; i++) {
builder.append(";");
builder.append(parts[i]);
if(useCurrentMirrors) {
String test = parts[i];
if(!test.endsWith("/")) {
test += "/";
}
useCurrentMirrors = currentMirrors.contains(test);
doLog("USE CURRENT MIRRORS: " + test + " " + useCurrentMirrors);
}
}
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS_DEFAULT, builder.toString());
if(useCurrentMirrors) {
builder.delete(0, builder.length());
builder.append(currentMirrors);
}
doLog("Mirrors for group '" + parts[0] + "': " + builder.toString());
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS, builder.toString());
mThreadPool.execute(new Runnable() {
@Override
public void run() {
GroupInfo test = updateGroup(cr, knownId, SettingConstants.EPG_FREE_KEY, parts[0], builder.toString(), values);
if(test != null) {
doLog("Add group '" + test.getFileName() + "' to download list");
channelMirrors.add(test);
}
else {
success.andUpdateBoolean(false);
}
}
});
}
} catch (Throwable t) {
Log.d("info7", "", t);
} finally {
IOUtils.close(in);
}
final String key = SettingConstants.EPG_DONATE_KEY + "_##_" + SettingConstants.EPG_DONATE_GROUP_KEY;
Object currentGroupValues = currentGroups.get(key);
final Integer knownId = currentGroupValues != null ? (Integer)((Object[])currentGroupValues)[0] : null;
final String currentMirrors = currentGroupValues != null ? (String)((Object[])currentGroupValues)[1] : null;
final ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID, SettingConstants.EPG_DONATE_KEY);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_ID, SettingConstants.EPG_DONATE_GROUP_KEY);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_NAME, "EPGdonate");
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_PROVIDER, "René Mach");
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_DESCRIPTION, "Channels with donate support.");
String mirrors = SettingConstants.EPG_DONATE_DEFAULT_URL;
if(currentMirrors != null && currentMirrors.contains(SettingConstants.EPG_DONATE_DEFAULT_URL)) {
mirrors = currentMirrors;
}
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS, mirrors);
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS_DEFAULT, mirrors);
mThreadPool.execute(new Runnable() {
@Override
public void run() {
GroupInfo test = updateGroup(cr, knownId, SettingConstants.EPG_DONATE_KEY, SettingConstants.EPG_DONATE_GROUP_KEY, values.getAsString(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS), values);
if(test != null) {
doLog("Add group '" + test.getFileName() + "' to download list");
channelMirrors.add(test);
}
else {
success.andUpdateBoolean(false);
}
}
});
mThreadPool.shutdown();
try {
mThreadPool.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if(!mThreadPool.isTerminated()) {
mThreadPool.shutdownNow();
success.setBoolean(false);
}
if(!channelMirrors.isEmpty()) {
mThreadPool = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
mCurrentDownloadCount = 0;
mDataDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(getApplicationContext(), TvBrowserContentProvider.CONTENT_URI_CHANNELS);
mBuilder.setProgress(channelMirrors.size(), 0, false);
notification.notify(ID_NOTIFY, mBuilder.build());
for(final GroupInfo info : channelMirrors) {
doLog("Add group '" + info.getFileName() + "' to channel download ");
mThreadPool.execute(new Thread("DATA UPDATE GROUP CHANNEL ADDING THREAD") {
public void run() {
try {
doLog("Prepare channel download for group: " + info.getFileName());
final File group = new File(path,info.getFileName());
boolean groupSucces = false;
String[] urls = info.getUrls();
ArrayList<Integer> notWorkingIndicies = new ArrayList<Integer>();
for(int i = 0; i < urls.length; i++) {
int index = (int)(Math.random()*urls.length);
int count = 0;
while((notWorkingIndicies.contains(index) && count++ < urls.length) || index >= urls.length) {
index = (int)(Math.random()*urls.length);
}
String url = urls[index];
try {
doLog("Start channel download for group '" + info.getFileName() + "' from: " + url);
long downloadStart = System.currentTimeMillis();
if(mIsConnected && IOUtils.saveUrl(group.getAbsolutePath(), url + info.getUrlFileName(), mInternetConnectionTimeout)) {
doLog("End channel download for group '" + info.getFileName() + "' successfull from: " + url);
groupSucces = addChannels(group,info);
mBuilder.setProgress(channelMirrors.size(), mCurrentDownloadCount++, false);
notification.notify(ID_NOTIFY, mBuilder.build());
if(groupSucces) {
doLog("Load channels for group '" + info.getFileName() + "' successfull from: " + url);
File mirrors = new File(path,info.getMirrorFileName());
if(mIsConnected && IOUtils.saveUrl(mirrors.getAbsolutePath(), url + info.getMirrorUrlFileName(), mInternetConnectionTimeout)) {
updateMirror(mirrors);
}
break;
}
else {
doLog("Not successfull load channels for group '" + info.getFileName() + "' from: " + url);
notWorkingIndicies.add(index);
}
}
else {
checkAndSetConnectionState(downloadStart);
doLog("Not successfull load channels for group '" + info.getFileName() + "' from: " + url);
notWorkingIndicies.add(index);
}
} catch (Exception e) {
groupSucces = false;
}
}
success.andUpdateBoolean(groupSucces);
}catch(Throwable t) {
doLog("ERROR processing channels for group: " + info.getFileName(), t);
}
}
});
}
mThreadPool.shutdown();
try {
mThreadPool.awaitTermination(30, TimeUnit.MINUTES);
} catch (InterruptedException e) {}
if(!mThreadPool.isTerminated()) {
final List<Runnable> unstartedThreads = mThreadPool.shutdownNow();
doLog("Aborted channel download, with undone channel downloads: " + (unstartedThreads != null ? unstartedThreads.size() : 0));
success.setBoolean(false);
}
mDataDatabaseOperation.finish();
success.andUpdateBoolean(mDataDatabaseOperation.wasSuccessfull());
}
else {
success.setBoolean(false);
}
deleteFile(groups);
if(currentGroups != null) {
currentGroups.clear();
currentGroups = null;
}
}
else {
success.setBoolean(false);
}
Editor edit = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit();
if(success.getBoolean()) {
edit.putLong(getString(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST), System.currentTimeMillis());
doLog("DONE: Cannel update successfull");
}
else {
edit.putLong(getString(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST_NO_SUCCESS), System.currentTimeMillis());
doLog("FINISHED: Cannel update NOT successfull");
}
if(!mChannelsUpdate.isEmpty()) {
edit.putString(getString(R.string.PREF_AUTO_CHANNEL_UPDATE_CHANNELS_UPDATED), TextUtils.join(",", mChannelsUpdate));
mChannelsUpdate.clear();
mChannelsUpdate = null;
}
if(!mChannelsNew.isEmpty()) {
ArrayList<Integer> updatedIdsList = new ArrayList<Integer>(mChannelsNew.size());
String[] projection = {TvBrowserContentProvider.KEY_ID};
for(String uniqueChannelKey : mChannelsNew) {
Cursor c = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, projection, TvBrowserContentProvider.GROUP_KEY_GROUP_ID + " = ? AND " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " = ?", IOUtils.getUniqueChannelKeyParts(uniqueChannelKey), TvBrowserContentProvider.KEY_ID);
Log.d("info77", uniqueChannelKey + " " + c.getCount());
try {
if(c.moveToFirst()) {
updatedIdsList.add(c.getInt(c.getColumnIndex(TvBrowserContentProvider.KEY_ID)));
}
}finally {
IOUtils.close(c);
}
}
mChannelsNew.clear();
mChannelsNew = null;
edit.putString(getString(R.string.PREF_AUTO_CHANNEL_UPDATE_CHANNELS_INSERTED), TextUtils.join(",", updatedIdsList));
}
edit.commit();
Intent updateDone = new Intent(SettingConstants.CHANNEL_DOWNLOAD_COMPLETE);
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_SUCCESSFULLY, success.getBoolean());
updateDone.putExtra(SettingConstants.EXTRA_CHANNEL_DOWNLOAD_AUTO_UPDATE, autoUpdate);
LocalBroadcastManager.getInstance(TvDataUpdateService.this).sendBroadcast(updateDone);
stopForeground(true);
stopSelfInternal();
}
private String[] loadAvailableMirrorsForGroup(String mirrorLine) {
String[] mirrors = null;
if(mirrorLine.contains(";")) {
mirrors = mirrorLine.split(";");
}
else {
mirrors = new String[1];
mirrors[0] = mirrorLine;
}
ArrayList<String> mirrorList = new ArrayList<String>();
for(String mirror : mirrors) {
int index = mirror.indexOf("#");
if(index > 0) {
mirror = mirror.substring(0,index);
}
if(mIsConnected && IOUtils.isConnectedToServer(mirror,10000)) {
if(!mirror.endsWith("/")) {
mirror += "/";
}
mirrorList.add(mirror);
}
}
return mirrorList.toArray(new String[mirrorList.size()]);
}
private class GroupInfo {
private String[] mUrlArr;
private int mUniqueGroupID;
private String mFileName;
private String mUrlFileName;
private String mMirrorFileName;
private String mMirrorUrlFileName;
private String mDataServiceId;
public GroupInfo(String dataServiceId, String[] urls, String urlFileName, String fileName, String mirrorUrlFileName, String mirrorFileName, int uniqueGroupID) {
mDataServiceId = dataServiceId;
mUrlArr = urls;
mUniqueGroupID = uniqueGroupID;
mUrlFileName = urlFileName;
mFileName = fileName;
mMirrorUrlFileName = mirrorUrlFileName;
mMirrorFileName = mirrorFileName;
}
public String[] getUrls() {
return mUrlArr;
}
public int getUniqueGroupID() {
return mUniqueGroupID;
}
public String getFileName() {
return mFileName;
}
public String getUrlFileName() {
return mUrlFileName;
}
public String getMirrorFileName() {
return mMirrorFileName;
}
public String getMirrorUrlFileName() {
return mMirrorUrlFileName;
}
public String getDataServiceId() {
return mDataServiceId;
}
}
// Cursor contains the channel group
public boolean addChannels(File group, GroupInfo info) {
boolean returnValue = false;
if(group.isFile()) {
BufferedReader read = null;
try {
read = new BufferedReader(new InputStreamReader(IOUtils.decompressStream(new FileInputStream(group)),"ISO-8859-1"));
String line;
boolean returnValueOnceSet = false;
// final ArrayList<ContentValues> insertValuesList = new ArrayList<ContentValues>();
// final ArrayList<ContentProviderOperation> updateValuesList = new ArrayList<ContentProviderOperation>();
while((line = read.readLine()) != null) {
String[] parts = line.split(";");
if(!returnValueOnceSet) {
returnValue = true;
returnValueOnceSet = true;
}
String baseCountry = null;
String timeZone = null;
String channelId = null;
String name = null;
String copyright = null;
String website = null;
String logoUrl = null;
String allCountries = null;
int category = 0;
if(info.getDataServiceId().equals(SettingConstants.EPG_FREE_KEY)) {
baseCountry = parts[0];
timeZone = parts[1];
channelId = parts[2];
name = parts[3];
copyright = parts[4];
website = parts[5];
logoUrl = parts[6];
category = Integer.parseInt(parts[7]);
allCountries = baseCountry;
}
else if(info.getDataServiceId().equals(SettingConstants.EPG_DONATE_KEY)) {
allCountries = baseCountry = parts[1];
if(baseCountry.contains("$")) {
String[] countries = baseCountry.split("$");
baseCountry = countries[0];
}
timeZone = "UTC";
channelId = parts[0];
name = parts[2];
copyright = parts[4];
website = parts[5];
logoUrl = parts[3];
category = Integer.parseInt(parts[6]);
}
if(baseCountry != null && name != null) {
StringBuilder fullName = new StringBuilder();
int i = 8;
if(parts.length > i) {
do {
fullName.append(parts[i]);
fullName.append(";");
}while(!parts[i++].endsWith("\""));
fullName.deleteCharAt(fullName.length()-1);
}
if(fullName.length() == 0) {
fullName.append(name);
}
String joinedChannel = "";
if(parts.length > i) {
allCountries = parts[i++];
}
if(parts.length > i) {
joinedChannel = parts[i];
}
String key = info.mUniqueGroupID + "_##_" + channelId.trim();
Object channelValues = mCurrentChannelData.remove(key);
// String where = TvBrowserContentProvider.GROUP_KEY_GROUP_ID + " = " + info.mUniqueGroupID + " AND " + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " = '" + channelId + "'";
//ContentResolver cr = getContentResolver();
//Cursor query = cr.query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, projection, where, null, null);
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_ID, info.getUniqueGroupID());
values.put(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, channelId);
values.put(TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY, baseCountry);
values.put(TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE, timeZone);
values.put(TvBrowserContentProvider.CHANNEL_KEY_NAME, name);
values.put(TvBrowserContentProvider.CHANNEL_KEY_COPYRIGHT, copyright);
values.put(TvBrowserContentProvider.CHANNEL_KEY_WEBSITE, website);
values.put(TvBrowserContentProvider.CHANNEL_KEY_LOGO_URL, logoUrl);
values.put(TvBrowserContentProvider.CHANNEL_KEY_CATEGORY, category);
values.put(TvBrowserContentProvider.CHANNEL_KEY_FULL_NAME, fullName.toString().replaceAll("\"", ""));
values.put(TvBrowserContentProvider.CHANNEL_KEY_ALL_COUNTRIES, allCountries);
values.put(TvBrowserContentProvider.CHANNEL_KEY_JOINED_CHANNEL_ID, joinedChannel);
if(mIsConnected && logoUrl != null && logoUrl.length() > 0) {
try {
byte[] blob = IOUtils.loadUrl(logoUrl, 10000);
values.put(TvBrowserContentProvider.CHANNEL_KEY_LOGO, blob);
}catch(Exception e1) {}
}
if(channelValues == null) {
doLog("Add channel to database INSERT: " + name);
//insertValuesList.add(values);
mDataDatabaseOperation.addInsert(values);
if(mHadChannels) {
mChannelsNew.add(IOUtils.getUniqueChannelKey(String.valueOf(info.getUniqueGroupID()), channelId));
}
}
else {
doLog("Add channel to database UPDATE: " + name);
Integer uniqueChannelId = (Integer)((Object[])channelValues)[0];
// update channel
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_CHANNELS, uniqueChannelId));
opBuilder.withValues(values);
mDataDatabaseOperation.addUpdate(opBuilder.build());
//updateValuesList.add(opBuilder.build());
if(!((String)((Object[])channelValues)[1]).trim().equals(name.trim())) {
mChannelsUpdate.add(uniqueChannelId);
}
}
}
else {
returnValue = false;
}
}
//returnValue = handleDatabaseInsertAndUpdate(insertValuesList, updateValuesList, returnValue);
} catch (FileNotFoundException e) {
returnValue = false;
e.printStackTrace();
} catch (IOException e) {
returnValue = false;
e.printStackTrace();
} finally {
IOUtils.close(read);
}
deleteFile(group);
}
return returnValue;
}
/*
private synchronized boolean handleDatabaseInsertAndUpdate(final ArrayList<ContentValues> insertValuesList, final ArrayList<ContentProviderOperation> updateValuesList, boolean returnValue) {
if(insertValuesList != null && !insertValuesList.isEmpty()) {
if(insertValuesList.size() > getContentResolver().bulkInsert(TvBrowserContentProvider.CONTENT_URI_CHANNELS, insertValuesList.toArray(new ContentValues[insertValuesList.size()]))) {
returnValue = false;
}
}
if(updateValuesList != null && !updateValuesList.isEmpty()) {
try {
if(updateValuesList.size() > getContentResolver().applyBatch(TvBrowserContentProvider.AUTHORITY, updateValuesList).length) {
returnValue = false;
}
} catch (Exception e) {
returnValue = false;
}
}
return returnValue;
}*/
private byte[] getXmlBytes(boolean syncFav, boolean syncMarkings) {
StringBuilder where = new StringBuilder();
if(syncFav) {
where.append(" ( ").append(TvBrowserContentProvider.DATA_KEY_MARKING_FAVORITE).append(" ) ");
}
if(syncMarkings) {
if(where.length() > 0) {
where.append(" OR ");
}
where.append(" ( ").append(TvBrowserContentProvider.DATA_KEY_MARKING_MARKING).append(" ) ");
}
String[] projection = {
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.CHANNEL_TABLE + "." + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID,
TvBrowserContentProvider.GROUP_KEY_GROUP_ID,
TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY,
TvBrowserContentProvider.DATA_KEY_TITLE
};
final StringBuilder dat = new StringBuilder();
Cursor programs = null; try {
programs = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_WITH_CHANNEL, projection, where.toString(), null, TvBrowserContentProvider.DATA_KEY_STARTTIME);
SparseArrayCompat<SimpleGroupInfo> groupInfo = new SparseArrayCompat<SimpleGroupInfo>();
if(programs!=null && programs.getCount() > 0) {
final CRC32 crc = new CRC32();
programs.moveToPosition(-1);
String[] groupProjection = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.GROUP_KEY_DATA_SERVICE_ID,
TvBrowserContentProvider.GROUP_KEY_GROUP_ID
};
Cursor groups = null; try {
groups = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_GROUPS, groupProjection, null, null, null);
if(groups!=null && groups.getCount() > 0) {
groups.moveToPosition(-1);
while(groups.moveToNext()) {
int groupKey = groups.getInt(0);
String dataServiceID = groups.getString(1);
String groupID = groups.getString(2);
String test = SettingConstants.getNumberForDataServiceKey(dataServiceID);
if(test != null) {
dataServiceID = test;
}
groupInfo.put(groupKey, new SimpleGroupInfo(dataServiceID, groupID));
}
}
} finally {IOUtils.close(groups);}
if(groupInfo.size() > 0) {
final int startTimeColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
final int groupKeyColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
final int channelKeyBaseCountryColumnIndex = programs.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_BASE_COUNTRY);
final int columnIndexTitle = programs.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE);
while(programs.moveToNext()) {
int groupID = programs.getInt(groupKeyColumnIndex);
long startTime = programs.getLong(startTimeColumnIndex) / 60000;
String channelID = programs.getString(1);
String baseCountry = programs.getString(channelKeyBaseCountryColumnIndex);
SimpleGroupInfo info = groupInfo.get(groupID);
String groupId = ":" + info.mGroupID;
if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY).equals(info.mDataServiceID)) {
groupId = "";
}
crc.reset();
dat.append(startTime).append(";").append(info.mDataServiceID).append(groupId).append(":").append(baseCountry).append(":").append(channelID);
try {
crc.update(programs.getString(columnIndexTitle).getBytes("UTF-8"));
dat.append(";").append(crc.getValue());
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dat.append("\n");
}
}
}
} finally {IOUtils.close(programs);}
return IOUtils.getCompressedData(dat.toString().getBytes());
}
public void backSyncPrograms(final NotificationManager notification) {
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_synchronize));
notification.notify(ID_NOTIFY, mBuilder.build());
final String CrLf = "\r\n";
SharedPreferences pref = getSharedPreferences("transportation", Context.MODE_PRIVATE);
String car = pref.getString(SettingConstants.USER_NAME, null);
String bicycle = pref.getString(SettingConstants.USER_PASSWORD, null);
boolean syncFav = PrefUtils.getBooleanValue(R.string.PREF_SYNC_FAV_TO_DESKTOP, R.bool.pref_sync_fav_to_desktop_default);
boolean syncMarkings = PrefUtils.getBooleanValue(R.string.PREF_SYNC_MARKED_TO_DESKTOP, R.bool.pref_sync_marked_to_desktop_default);
if((syncFav || syncMarkings) && car != null && bicycle != null && car.trim().length() > 0 && bicycle.trim().length() > 0) {
String userpass = car.trim() + ":" + bicycle.trim();
String basicAuth = "basic " + Base64.encodeToString(userpass.getBytes(), Base64.NO_WRAP);
URLConnection conn = null;
OutputStream os = null;
InputStream is = null;
try {
URL url = new URL(SettingConstants.URL_SYNC_BASE + "data/scripts/syncUp.php?type=favortiesFromApp");
conn = url.openConnection();
IOUtils.setConnectionTimeoutDefault(conn);
conn.setRequestProperty ("Authorization", basicAuth);
conn.setDoOutput(true);
byte[] xmlData = getXmlBytes(syncFav, syncMarkings);
String message1 = "";
message1 += "-----------------------------4664151417711" + CrLf;
message1 += "Content-Disposition: form-data; name=\"uploadedfile\"; filename=\""+car+".gz\""
+ CrLf;
message1 += "Content-Type: text/plain" + CrLf;
message1 += CrLf;
// the image is sent between the messages in the multipart message.
String message2 = "";
message2 += CrLf + "-----------------------------4664151417711--"
+ CrLf;
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=---------------------------4664151417711");
// might not need to specify the content-length when sending chunked
// data.
conn.setRequestProperty("Content-Length", String.valueOf((message1
.length() + message2.length() + xmlData.length)));
Log.d("info8","open os");
os = conn.getOutputStream();
Log.d("info8",message1);
os.write(message1.getBytes());
// SEND THE IMAGE
int index = 0;
int size = 1024;
do {
Log.d("info8","write:" + index);
if ((index + size) > xmlData.length) {
size = xmlData.length - index;
}
os.write(xmlData, index, size);
index += size;
} while (index < xmlData.length);
Log.d("info8","written:" + index);
Log.d("info8",message2);
os.write(message2.getBytes());
os.flush();
Log.d("info8","open is");
is = conn.getInputStream();
char buff = 512;
int len;
byte[] data = new byte[buff];
do {
Log.d("info8","READ");
len = is.read(data);
if (len > 0) {
Log.d("info8",new String(data, 0, len));
}
} while (len > 0);
Log.d("info8","DONE");
} catch (Exception e) {
Log.d("info8", "" ,e);
} finally {
Log.d("info8","Close connection");
IOUtils.close(os);
IOUtils.close(is);
IOUtils.disconnect(conn);
}
}
notification.cancel(ID_NOTIFY);
}
private void loadAccessAndFavoriteSync() {
URLConnection connection = null;
BufferedReader read = null;
try {
URL documentUrl = new URL(SettingConstants.URL_SYNC_BASE + "data/scripts/syncDown.php?type=favoritesFromDesktop");
connection = documentUrl.openConnection();
SharedPreferences pref = getSharedPreferences("transportation", Context.MODE_PRIVATE);
String car = pref.getString(SettingConstants.USER_NAME, null);
String bicycle = pref.getString(SettingConstants.USER_PASSWORD, null);
if(PrefUtils.getBooleanValue(R.string.PREF_SYNC_FAV_FROM_DESKTOP, R.bool.pref_sync_fav_from_desktop_default) && car != null && bicycle != null && car.trim().length() > 0 && bicycle.trim().length() > 0) {
String userpass = car.trim() + ":" + bicycle.trim();
String basicAuth = "basic " + Base64.encodeToString(userpass.getBytes(), Base64.NO_WRAP);
connection.setRequestProperty ("Authorization", basicAuth);
read = new BufferedReader(new InputStreamReader(IOUtils.decompressStream(connection.getInputStream()),"UTF-8"));
String dateValue = read.readLine();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Date syncDate = dateFormat.parse(dateValue.trim());
if(syncDate.getTime() > System.currentTimeMillis()) {
mSyncFavorites = new ArrayList<String>();
String line = null;
while((line = read.readLine()) != null) {
mSyncFavorites.add(line);
}
}
}
}catch(Throwable t) {
}finally {
IOUtils.close(read);
IOUtils.disconnect(connection);
}
}
/**
* Calculate the end times of programs that are missing end time in the data.
*/
private void calculateMissingEnds(NotificationManager notification, boolean updateFavorites, boolean syncAllowed) {
try {
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_notification_calculate));
notification.notify(ID_NOTIFY, mBuilder.build());
// Only ID, channel ID, start and end time are needed for update, so use only these columns
String[] projection = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID,
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.DATA_KEY_ENDTIME,
TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME,
TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE,
TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES
};
long lastKnownDate = SettingConstants.DATA_LAST_DATE_NO_DATA;
ArrayList<ContentProviderOperation> updateValuesList = new ArrayList<ContentProviderOperation>();
Cursor c = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_WITH_CHANNEL, projection, null, null, TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + " , " + TvBrowserContentProvider.DATA_KEY_STARTTIME + " DESC");
try {
// only if there are data update it
if(IOUtils.prepareAccess(c)) {
int nettoColumn = c.getColumnIndex(TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME);
int keyIDColumn = c.getColumnIndex(TvBrowserContentProvider.KEY_ID);
int channelKeyColumn = c.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
int startTimeColumn = c.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
int endTimeColumn = c.getColumnIndex(TvBrowserContentProvider.DATA_KEY_ENDTIME);
int timeZoneColumn = c.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE);
int durationColumn = c.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES);
long lastStartTime = -1;
int lastChannelKey = -1;
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar cal = null;
while(c.moveToNext()) {
long progID = c.getLong(keyIDColumn);
int channelKey = c.getInt(channelKeyColumn);
long meStart = c.getLong(startTimeColumn);
long end = c.getLong(endTimeColumn);
long nettoPlayTime = 0;
long duration = c.getLong(durationColumn);
if(c.isNull(nettoColumn)) {
nettoPlayTime = c.getLong(nettoColumn) * 60000;
}
if(lastChannelKey == channelKey) {
cal = Calendar.getInstance(TimeZone.getTimeZone(c.getString(timeZoneColumn)));
// if end not set or netto play time larger than next start or next time not end time
if(end == 0 || (nettoPlayTime > (lastStartTime - meStart))/* || (lastProgram && end != nextStart && ((nextStart - meStart) < (3 * 60 * 60000)))*/) {
if(nettoPlayTime > (lastStartTime - meStart)) {
lastStartTime = meStart + nettoPlayTime;
}
else if((lastStartTime - meStart) >= (12 * 60 * 60000)) {
lastStartTime = meStart + (long)(2.5 * 60 * 60000);
}
utc.setTimeInMillis((((long)(cal.getTimeInMillis() / 60000)) * 60000));
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_ENDTIME, lastStartTime);
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((lastStartTime-meStart)/60000));
cal.setTimeInMillis(lastStartTime);
int startHour = cal.get(Calendar.HOUR_OF_DAY);
int startMinute = cal.get(Calendar.MILLISECOND);
// Normalize start hour and minute to 2014-12-31 to have the same time base on all occasions
utc.setTimeInMillis((((long)(IOUtils.normalizeTime(cal, startHour, startMinute, 30).getTimeInMillis() / 60000)) * 60000));
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, utc.get(Calendar.HOUR_OF_DAY) * 60 + utc.get(Calendar.MINUTE));
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE, progID));
opBuilder.withValues(values);
updateValuesList.add(opBuilder.build());
}
else if(end != 0 && duration == 0) {
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((end-meStart)/60000));
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE, progID));
opBuilder.withValues(values);
updateValuesList.add(opBuilder.build());
}
}
else {
lastKnownDate = Math.max(meStart, lastKnownDate);
}
lastChannelKey = channelKey;
lastStartTime = meStart;
}
}
}finally {
IOUtils.close(c);
}
if(!updateValuesList.isEmpty()) {
getContentResolver().applyBatch(TvBrowserContentProvider.AUTHORITY, updateValuesList);
}
Editor edit = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_SHARED_GLOBAL, TvDataUpdateService.this).edit();
edit.putLong(getString(R.string.PREF_LAST_KNOWN_DATA_DATE), lastKnownDate);
edit.commit();
}catch(Throwable t) {
Log.d("info13", "", t);
}
finishUpdate(notification,updateFavorites,syncAllowed);
}
private void finishUpdate(NotificationManager notification, boolean updateFavorites, boolean syncAllowed) {
doLog("FINISH DATA UPDATE");
TvBrowserContentProvider.INFORM_FOR_CHANGES = true;
getContentResolver().notifyChange(TvBrowserContentProvider.CONTENT_URI_DATA, null);
if(updateFavorites) {
updateFavorites(notification);
}
if(syncAllowed && mIsConnected) {
syncFavorites(notification);
boolean fromRemider = PrefUtils.getBooleanValue(R.string.PREF_SYNC_REMINDERS_FROM_DESKTOP, R.bool.pref_sync_reminders_from_desktop_default);
boolean toRemider = PrefUtils.getBooleanValue(R.string.PREF_SYNC_REMINDERS_TO_DESKTOP, R.bool.pref_sync_reminders_to_desktop_default);
if(fromRemider) {
synchronizeRemindersDown(false, notification);
}
if(toRemider) {
synchronizeUp(false, null, SettingConstants.URL_SYNC_BASE + "data/scripts/syncUp.php?type=reminderFromApp", notification);
}
if(PrefUtils.getBooleanValue(R.string.PREF_NEWS_SHOW, R.bool.pref_news_show_default)) {
long lastNewsUpdate = PrefUtils.getLongValue(R.string.NEWS_DATE_LAST_DOWNLOAD, 0);
long daysSinceLastNewsUpdate = (System.currentTimeMillis() - lastNewsUpdate) / (24 * 60 * 60000L);
if(daysSinceLastNewsUpdate > 3 && (Math.random() * 7 < daysSinceLastNewsUpdate)) {
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_load_news));
notification.notify(ID_NOTIFY, mBuilder.build());
NewsReader.readNews(TvDataUpdateService.this, mHandler);
}
}
}
PrefUtils.updateDataMetaData(TvDataUpdateService.this);
try {
doLog("FIRST KNOWN DATA ID: " + PrefUtils.getLongValueWithDefaultKey(R.string.META_DATA_ID_FIRST_KNOWN, R.integer.meta_data_id_default));
doLog("FIRST KNOWN DATA DATE: " + new Date(PrefUtils.getLongValueWithDefaultKey(R.string.META_DATA_DATE_FIRST_KNOWN, R.integer.meta_data_date_known_default)));
doLog("LAST KNOWN DATA ID: " + PrefUtils.getLongValueWithDefaultKey(R.string.META_DATA_ID_LAST_KNOWN, R.integer.meta_data_id_default));
doLog("LAST KNOWN DATA DATE: " + new Date(PrefUtils.getLongValueWithDefaultKey(R.string.META_DATA_DATE_LAST_KNOWN, R.integer.meta_data_date_known_default)));
}catch(Throwable tt) {
doLog(tt.toString());
}
Intent inform = new Intent(SettingConstants.DATA_UPDATE_DONE);
inform.putExtra(SettingConstants.EXTRA_DATA_DATE_LAST_KNOWN, PrefUtils.getLongValue(R.string.PREF_LAST_KNOWN_DATA_DATE, SettingConstants.DATA_LAST_DATE_NO_DATA));
TvDataUpdateService.this.sendBroadcast(inform);
mDontWantToSeeValues = null;
// Data update complete inform user
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(TvDataUpdateService.this, R.string.update_complete, Toast.LENGTH_LONG).show();
}
});
doLog("Unsuccessful downloads: " + String.valueOf(mUnsuccessfulDownloads));
Editor edit = PreferenceManager.getDefaultSharedPreferences(TvDataUpdateService.this).edit();
edit.putLong(getString(R.string.LAST_DATA_UPDATE), System.currentTimeMillis());
edit.commit();
Favorite.handleDataUpdateFinished();
stopForeground(true);
if(IOUtils.isInteractive(TvDataUpdateService.this)) {
UiUtils.updateImportantProgramsWidget(getApplicationContext());
UiUtils.updateRunningProgramsWidget(getApplicationContext());
}
int autoChannelUpdateFrequency = PrefUtils.getStringValueAsInt(R.string.PREF_AUTO_CHANNEL_UPDATE_FREQUENCY, R.string.pref_auto_channel_update_frequency_default);
doLog("Can update channels: " + syncAllowed + " autoChannelUpdateFrequency: " + autoChannelUpdateFrequency + " last successfull auto channel update: " + new Date(PrefUtils.getLongValue(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST, 0)) + " last unsuccessfull channel update: " + new Date(PrefUtils.getLongValue(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST_NO_SUCCESS, 0)));
if(syncAllowed && mIsConnected && autoChannelUpdateFrequency != -1 && ((PrefUtils.getLongValue(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST, 0) + (autoChannelUpdateFrequency * 24 * 60 * 60000L)) < System.currentTimeMillis()) && ((PrefUtils.getLongValue(R.string.PREF_AUTO_CHANNEL_UPDATE_LAST_NO_SUCCESS, 0) + (2 * 24 * 60 * 60000L)) < System.currentTimeMillis())) {
updateChannels(true);
}
else {
stopSelfInternal();
}
}
private AtomicInteger mFavoriteUpdateCount;
private void updateFavorites(final NotificationManager notification) {
final Favorite[] favorites = Favorite.getAllFavorites(TvDataUpdateService.this);
mBuilder.setProgress(favorites.length, 0, false);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_favorites));
notification.notify(ID_NOTIFY, mBuilder.build());
ExecutorService updateFavorites = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
mFavoriteUpdateCount = new AtomicInteger(1);
for(final Favorite favorite : favorites) {
if(!updateFavorites.isShutdown()) {
updateFavorites.execute(new Thread("DATA UPDATE FAVORITE UPDATE THREAD") {
@Override
public void run() {
Favorite.handleFavoriteMarking(TvDataUpdateService.this, favorite, Favorite.TYPE_MARK_REMOVE);
Favorite.handleFavoriteMarking(TvDataUpdateService.this, favorite, Favorite.TYPE_MARK_ADD);
mBuilder.setProgress(favorites.length, mFavoriteUpdateCount.getAndIncrement(), false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
});
}
}
updateFavorites.shutdown();
try {
updateFavorites.awaitTermination(favorites.length, TimeUnit.MINUTES);
} catch (InterruptedException e) {}
notification.cancel(ID_NOTIFY);
backSyncPrograms(notification);
}
public void doLog(String value) {
doLog(value, null);
}
public void doLog(String value, Throwable t) {
if(t != null) {
final StringBuilder message = new StringBuilder(value).append("\n");
message.append(t.toString()).append("\n");
final StackTraceElement[] els = t.getStackTrace();
for(StackTraceElement el : els) {
message.append(el.toString()).append("\n");
}
}
Logging.log("info7", value, Logging.TYPE_DATA_UPDATE, TvDataUpdateService.this);
}
private void doLogData(String msg) {
Log.d("info5", msg);
}
private String reloadMirrors(String groupID, File path) {
String groupTxt = getGroupFileMirror();
String mirrorLine = "";
if(mIsConnected && groupTxt != null) {
File groups = new File(path,GROUP_FILE);
BufferedReader in = null;
try {
IOUtils.saveUrl(groups.getAbsolutePath(), groupTxt, mInternetConnectionTimeout);
if(groups.isFile()) {
in = new BufferedReader(new InputStreamReader(new FileInputStream(groups)));
String line = null;
while((line = in.readLine()) != null && mirrorLine.trim().length() == 0) {
if(line.startsWith(groupID + ";")) {
String[] parts = line.split(";");
StringBuilder builder = new StringBuilder(parts[4]);
for(int i = 5; i < parts.length; i++) {
builder.append(";");
builder.append(parts[i]);
}
mirrorLine = builder.toString();
}
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
IOUtils.close(in);
}
deleteFile(groups);
}
return mirrorLine;
}
private static final class MirrorDownload {
private String mDownloadURL;
private String mFileName;
public MirrorDownload(String downloadURL, String fileName) {
mDownloadURL = downloadURL;
mFileName = fileName;
}
public String getDownloadURL() {
return mDownloadURL;
}
public String getFileName() {
return mFileName;
}
}
private void updateTvData() {
final UncaughtExceptionHandler handleExc = new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
doLog("UNCAUGHT EXCEPTION Thread: " + thread.getName() + " Throwable " + ex.toString());
}
};
acquireWakeLock();
mShowNotification = true;
mUnsuccessfulDownloads = 0;
mCountTimedOutConnections = 0;
doLog("Favorite.handleDataUpdateStarted()");
Favorite.handleDataUpdateStarted();
loadEpgPaidChannelIdsForDataUpdate();
final File path = IOUtils.getDownloadDirectory(TvDataUpdateService.this.getApplicationContext());
File[] oldDataFiles = path.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().toLowerCase(Locale.GERMAN).endsWith(".gz");
}
});
for(File oldFile : oldDataFiles) {
deleteFile(oldFile);
}
int[] levels = null;
Set<String> exclusions = PrefUtils.getStringSetValue(R.string.I_DONT_WANT_TO_SEE_ENTRIES, null);
if(exclusions != null) {
mDontWantToSeeValues = new DontWantToSeeExclusion[exclusions.size()];
int i = 0;
for(String exclusion : exclusions) {
mDontWantToSeeValues[i++] = new DontWantToSeeExclusion(exclusion);
}
}
if(PrefUtils.getBooleanValue(R.string.LOAD_FULL_DATA, R.bool.load_full_data_default)) {
if(PrefUtils.getBooleanValue(R.string.LOAD_PICTURE_DATA, R.bool.load_picture_data_default)) {
levels = new int[5];
}
else {
levels = new int[3];
}
for(int j = 0; j < levels.length; j++) {
levels[j] = j;
}
}
else if (PrefUtils.getBooleanValue(R.string.LOAD_PICTURE_DATA, R.bool.load_picture_data_default)) {
levels = new int[3];
levels[0] = 0;
levels[1] = 3;
levels[2] = 4;
}
else {
levels = new int[1];
levels[0] = 0;
}
mCurrentDownloadCount = 0;
mBuilder.setContentTitle(getResources().getText(R.string.update_notification_title));
mBuilder.setContentText(getResources().getText(R.string.update_notification_text));
startForeground(ID_NOTIFY, mBuilder.build());
final NotificationManager notification = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
//notification.notify(NOTIFY_ID, mBuilder.build());*/
doLog("loadAccessAndFavoriteSync()");
loadAccessAndFavoriteSync();
TvBrowserContentProvider.INFORM_FOR_CHANGES = false;
ContentResolver cr = getContentResolver();
StringBuilder where = new StringBuilder(TvBrowserContentProvider.CHANNEL_KEY_SELECTION);
// where.append(" = 1");
final ArrayList<ChannelUpdate> updateList = new ArrayList<ChannelUpdate>();
int downloadCountTemp = 0;
doLog("readCurrentVersionIDs()");
readCurrentVersionIDs();
DataHandler epgFreeDataHandler = new EPGfreeDataHandler();
DataHandler epgDonateDataHandler = new EPGdonateDataHandler();
ArrayList<MirrorDownload> downloadMirrorList = new ArrayList<MirrorDownload>();
Calendar to = Calendar.getInstance();
to.add(Calendar.DAY_OF_MONTH, mDaysToLoad);
doLog("End date of data to download: " + to.getTime());
Cursor channelCursor = null;
try {
channelCursor = cr.query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, null, where.toString(), null, TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
doLog("channelCursor: " + channelCursor);
boolean donationInfoLoaded = false;
if(channelCursor!=null && channelCursor.moveToFirst()) {
int lastGroup = -1;
Mirror mirror = null;
String groupId = null;
Summary summary = null;
String channelName = null;
do {
try {
int groupKey = channelCursor.getInt(channelCursor.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID));
int channelKey = channelCursor.getInt(channelCursor.getColumnIndex(TvBrowserContentProvider.KEY_ID));
String timeZone = channelCursor.getString(channelCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_TIMEZONE));
channelName = channelCursor.getString(channelCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_NAME));
doLog("Load info for channel " + channelName);
if(lastGroup != groupKey) {
summary = null;
mirror = null;
groupId = null;
doLog("Content URI for data update " + ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_GROUPS, groupKey));
Cursor group = null;
try {
group = cr.query(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_GROUPS, groupKey), null, null, null, null);
doLog("Cursor size for groupKey: " + group.getCount());
final int columnIndexId = group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_ID);
final int columnIndexMirrors = group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS);
final int columnIndexMirrorsDefault = group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS_DEFAULT);
if(group != null && group.getCount() > 0) {
group.moveToFirst();
groupId = group.getString(columnIndexId);
String mirrorURL = group.getString(columnIndexMirrors);
String mirrorURLsDefault = group.isNull(columnIndexMirrorsDefault) ? "" : group.getString(columnIndexMirrorsDefault);
Log.d("info21", "GROUPID " + groupId + " " + mirrorURL);
doLog("DEFAULT MIRRORS for group '" + groupId + "': " + mirrorURLsDefault);
doLog("Available mirrorURLs for group '" + groupId + "': " + mirrorURL);
doLog("Group info for '" + groupId + "' groupKey: " + groupKey + " group name: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_NAME)) + " group provider: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_PROVIDER)) + " group description: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_DESCRIPTION)));
if(!mirrorURL.toLowerCase(Locale.GERMAN).startsWith("http://") && !mirrorURL.toLowerCase(Locale.GERMAN).startsWith("https://")) {
doLog("RELOAD MIRRORS FOR '" + groupId);
mirrorURL = reloadMirrors(groupId, path);
doLog("Available mirrorURLs for group '" + groupId + "': " + mirrorURL);
doLog("Group info for '" + groupId + "' groupKey: " + groupKey + " group name: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_NAME)) + " group provider: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_PROVIDER)) + " group description: " + group.getString(group.getColumnIndex(TvBrowserContentProvider.GROUP_KEY_GROUP_DESCRIPTION)));
}
boolean checkOnlyConnection = false;
if(groupId.equals(SettingConstants.EPG_DONATE_GROUP_KEY)) {
checkOnlyConnection = true;
}
String[] defaultMirrors = mirrorURLsDefault.split(";");
for(String defaultMirror : defaultMirrors) {
if(!mirrorURL.contains(defaultMirror)) {
mirrorURL += ";" + defaultMirror;
}
}
Mirror[] mirrors = Mirror.getMirrorsFor(mirrorURL);
Log.d("info21", "MIRRORS AVAILABLE " + mirrors);
mirror = Mirror.getMirrorToUseForGroup(mirrors, groupId, this, checkOnlyConnection);
doLog("Choosen mirror for group '" + groupId + "': " + mirror);
Log.d("info21", "MIRROR CHOOSEN " + mirror);
if(mirror != null) {
String url = mirror.getUrl() + groupId + "_mirrorlist.gz";
String fileName = groupId + "_mirrorlist.gz";
String summaryUrl = mirror.getUrl() + groupId + "_summary.gz";
String summaryFileName = groupId + "_summary.gz";
if(checkOnlyConnection) {
if(mIsConnected && !donationInfoLoaded) {
Editor edit = PreferenceManager.getDefaultSharedPreferences(TvDataUpdateService.this).edit();
edit.putLong(getString(R.string.EPG_DONATE_LAST_DATA_DOWNLOAD), System.currentTimeMillis());
if(PrefUtils.getLongValue(R.string.EPG_DONATE_FIRST_DATA_DOWNLOAD, -1) == -1) {
edit.putLong(getString(R.string.EPG_DONATE_FIRST_DATA_DOWNLOAD), System.currentTimeMillis());
}
File donationInfo = new File(path,groupId+"_donationinfo.gz");
IOUtils.saveUrl(donationInfo.getAbsolutePath(), mirror.getUrl() + "donationinfo.gz");
if(donationInfo.isFile()) {
Properties donationProp = new Properties();
GZIPInputStream in = null;
try {
in = new GZIPInputStream(new FileInputStream(donationInfo));
donationProp.load(in);
} catch(IOException e) {
// ignore just load the info next time
} finally {
IOUtils.close(in);
}
edit.putString(getString(R.string.EPG_DONATE_CURRENT_DONATION_PERCENT), donationProp.getProperty(SettingConstants.EPG_DONATE_DONATION_INFO_PERCENT_KEY,"-1"));
String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
String donationAmount = donationProp.getProperty(SettingConstants.EPG_DONATE_DONATION_INFO_AMOUNT_KEY_PREFIX+year, null);
if(donationAmount != null) {
edit.putString(getString(R.string.EPG_DONATE_CURRENT_DONATION_AMOUNT_PREFIX)+"_"+year, donationAmount);
}
if(!donationInfo.delete()) {
donationInfo.deleteOnExit();
}
}
edit.commit();
donationInfoLoaded = true;
}
url = mirror.getUrl() + "mirrors.gz";
fileName = groupId + "_mirrors.gz";
summaryUrl = mirror.getUrl() + "summary.gz";
Log.d("info21", "SUMMARY " + summaryUrl);
}
doLog("Download summary from: " + summaryUrl);
summary = readSummary(new File(path,summaryFileName),summaryUrl, groupId);
doLog("To download: " + url);
downloadMirrorList.add(new MirrorDownload(url, fileName));
}
}
}finally {
IOUtils.close(group);
}
}
doLog("Summary downloaded: " + (summary != null));
if(summary != null && mirror != null) {
String channelID = channelCursor.getString(channelCursor.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID));
Calendar now = Calendar.getInstance();
now.add(Calendar.DAY_OF_MONTH, -2);
if(summary instanceof EPGfreeSummary) {
doLog("Load summary info for: " + channelID);
ChannelFrame frame = ((EPGfreeSummary)summary).getChannelFrame(channelID);
doLog("Summary frame with ID '" + channelID + "' read: " + (frame != null));
if(frame != null) {
Calendar startDate = ((EPGfreeSummary)summary).getStartDate();
Calendar testDate = Calendar.getInstance();
testDate.setTimeInMillis(startDate.getTimeInMillis());
testDate.set(Calendar.HOUR_OF_DAY, 0);
doLog("Start date of data for frame with ID '" + channelID + "': " + startDate.getTime());
for(int i = 0; i < frame.getDayCount(); i++) {
startDate.add(Calendar.DAY_OF_YEAR, 1);
testDate.add(Calendar.DAY_OF_YEAR, 1);
if(testDate.compareTo(now) >= 0 && testDate.compareTo(to) <= 0) {
int[] version = frame.getVersionForDay(i);
doLog("Version found for frame with ID '" + channelID + "': " + (version != null));
if(version != null) {
long daysSince1970 = startDate.getTimeInMillis() / 24 / 60 / 60000;
String versionKey = channelKey + "_" + daysSince1970;
ChannelUpdate channelUpdate = new ChannelUpdate(epgFreeDataHandler, channelKey, timeZone, startDate.getTimeInMillis());
for(int level : levels) {
int testVersion = 0;
int[] versionInfo = mCurrentVersionIDs.get(versionKey);
if(versionInfo != null) {
testVersion = versionInfo[level+1];
}
doLog("Currently known version for '" + channelID + "' for level '" + level + "' and days since 1970 '" + daysSince1970 + "': " + testVersion);
if(version.length > level && version[level] > testVersion) {
String month = String.valueOf(startDate.get(Calendar.MONTH)+1);
String day = String.valueOf(startDate.get(Calendar.DAY_OF_MONTH));
if(month.length() == 1) {
month = "0" + month;
}
if(day.length() == 1) {
day = "0" + day;
}
doLog("Version for day unknown for '" + channelID + "'");
StringBuilder dateFile = new StringBuilder();
dateFile.append(mirror.getUrl());
dateFile.append(startDate.get(Calendar.YEAR));
dateFile.append("-");
dateFile.append(month);
dateFile.append("-");
dateFile.append(day);
dateFile.append("_");
dateFile.append(frame.getCountry());
dateFile.append("_");
dateFile.append(frame.getChannelID());
dateFile.append("_");
dateFile.append(SettingConstants.EPG_FREE_LEVEL_NAMES[level]);
dateFile.append("_full.prog.gz");
doLog("Download data for '" + channelID + "' from " + dateFile.toString() + " for level: " + level);
channelUpdate.addURL(dateFile.toString());
}
}
doLogData(" CHANNEL UPDATE TO DOWNLOAD " + channelUpdate.getChannelID() + " " + channelUpdate.getDate() + " " + channelUpdate.toDownload());
if(channelUpdate.toDownload()) {
updateList.add(channelUpdate);
downloadCountTemp += channelUpdate.size();
}
}
}
}
}
}
else if(summary instanceof EPGdonateSummary) {
Set<Object> keys = ((EPGdonateSummary)summary).keySet();
boolean loadMoreData = levels.length >= 3;
boolean loadPictureData = levels.length >= 5;
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
utc.set(2014, 12, 31, 0, 0, 0);
utc.set(Calendar.MILLISECOND, 0);
for(Object key : keys) {
if(key instanceof String && ((String)key).contains(channelID) && ((String)key).contains("_")) {
String stringKey = (String)key;
//Log.d("info21", "KEY " + key);
Object value = ((EPGdonateSummary)summary).get(stringKey);
if(value instanceof String) {
String stringValue = (String)value;
//Log.d("info21", "stringValue " + stringValue);
long startMilliseconds = Long.parseLong(stringKey.substring(0,stringKey.indexOf("_"))) * 60000L;
//Log.d("info21", "onTime " + ((startMilliseconds >= now.getTimeInMillis() && startMilliseconds <= to.getTimeInMillis())));
if(startMilliseconds >= now.getTimeInMillis() && startMilliseconds <= to.getTimeInMillis()) {
ChannelUpdate channelUpdate = new ChannelUpdate(epgDonateDataHandler, channelKey, timeZone, startMilliseconds);
long daysSince1970 = startMilliseconds / 24 / 60 / 60000L;
String versionKey = channelKey + "_" + daysSince1970;
int[] versionInfo = mCurrentVersionIDs.get(versionKey);
if(versionInfo == null) {
versionInfo = new int[] {0,0,0,0,0,0};
}
String[] versionParts = stringValue.split(",");
Log.d("info21", "versionInfo " + versionInfo[1] + " " + versionInfo[3] + " " + versionInfo[5]);
if(versionInfo[1] < Integer.parseInt(versionParts[0])) {
Log.d("info21", "ADDING " + mirror.getUrl() + stringKey + SettingConstants.EPG_DONATE_LEVEL_NAMES[0] + ".gz");
channelUpdate.addURL(mirror.getUrl() + stringKey + SettingConstants.EPG_DONATE_LEVEL_NAMES[0] + ".gz");
}
if(loadMoreData && versionInfo[3] < Integer.parseInt(versionParts[1])) {
channelUpdate.addURL(mirror.getUrl() + stringKey + SettingConstants.EPG_DONATE_LEVEL_NAMES[1] + ".gz");
}
if(loadPictureData && versionInfo[5] < Integer.parseInt(versionParts[2])) {
channelUpdate.addURL(mirror.getUrl() + stringKey + SettingConstants.EPG_DONATE_LEVEL_NAMES[2] + ".gz");
}
if(channelUpdate.toDownload()) {
Log.d("info21", "ADDING " + stringValue);
updateList.add(channelUpdate);
downloadCountTemp += channelUpdate.size();
}
}
}
}
}
}
}
lastGroup = groupKey;
}catch(Exception e) {
StringBuilder stackTrace = new StringBuilder("PROBLEM FOR CHANNEL: ");
stackTrace.append(channelName);
stackTrace.append(" ");
stackTrace.append(e.getLocalizedMessage());
stackTrace.append("\n");
for(StackTraceElement element : e.getStackTrace()) {
stackTrace.append(element.getLineNumber()).append(" ").append(element.getFileName()).append(" ").append(element.getClassName()).append(" ").append(element.getMethodName());
stackTrace.append("\n");
}
doLog(stackTrace.toString());
Log.d("info21", stackTrace.toString());
}
}while(channelCursor.moveToNext());
}
} finally {IOUtils.close(channelCursor);}
final int downloadCount = downloadMirrorList.size() + downloadCountTemp;
doLog("Data files to load " + downloadCount);
mThreadPool = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
mDataUpdatePool = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 2));
mBuilder.setProgress(downloadCount, 0, false);
notification.notify(ID_NOTIFY, mBuilder.build());
for(final MirrorDownload mirror : downloadMirrorList) {
final File mirrorFile = new File(path,mirror.getFileName());
if(!mThreadPool.isShutdown()) {
mThreadPool.execute(new Thread("DATA UPDATE MIRROR UPDATE THREAD") {
public void run() {
setUncaughtExceptionHandler(handleExc);
if(mIsConnected) {
try {
IOUtils.saveUrl(mirrorFile.getAbsolutePath(), mirror.getDownloadURL(), mInternetConnectionTimeout);
updateMirror(mirrorFile);
mCurrentDownloadCount++;
if(mShowNotification) {
mBuilder.setProgress(downloadCount, mCurrentDownloadCount, false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
} catch (Exception e) {
mUnsuccessfulDownloads++;
}
}
}
});
}
}
//mDontWantToSeeValues = null;
Log.d("info5", "updateCount " + downloadCountTemp);
mDataDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(TvDataUpdateService.this,TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE);
mVersionDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(TvDataUpdateService.this,TvBrowserContentProvider.CONTENT_URI_DATA_VERSION,10);
/* mDataInsertList = new ArrayList<ContentValues>();
mDataUpdateList = new ArrayList<ContentProviderOperation>();*/
/*mVersionInsertList = new ArrayList<ContentValues>();
mVersionUpdateList = new ArrayList<ContentProviderOperation>();
*/
if(downloadCountTemp > 0) {
readCurrentData();
for(final ChannelUpdate update : updateList) {
if(!mThreadPool.isShutdown()) {
mThreadPool.execute(new Thread("DATA UPDATE DATA DOWNLOAD THEAD") {
public void run() {
setUncaughtExceptionHandler(handleExc);
update.download(path, notification, downloadCount);
}
});
}
}
}
mThreadPool.shutdown();
if(!mThreadPool.isTerminated()) {
try {
mThreadPool.awaitTermination(updateList.size(), TimeUnit.MINUTES);
} catch (InterruptedException e) {
doLog("DOWNLOAD WAITING INTERRUPTED " + e.getLocalizedMessage());
}
}
mDataUpdatePool.shutdown();
doLog("WAIT FOR DATA UPDATE FOR: " + updateList.size() + " MINUTES");
if(!mDataUpdatePool.isTerminated()) {
try {
mDataUpdatePool.awaitTermination(updateList.size(), TimeUnit.MINUTES);
} catch (InterruptedException e) {
doLog("UPDATE DATE INTERRUPTED " + e.getLocalizedMessage());
}
}
doLog("WAIT FOR DATA UPDATE FOR DONE, DOWNLOAD: " + mThreadPool.isTerminated() + " DATA: " + mDataUpdatePool.isTerminated());
mShowNotification = false;
if(mDataDatabaseOperation != null) {
mDataDatabaseOperation.finish();
}
if(mVersionDatabaseOperation != null) {
mVersionDatabaseOperation.finish();
}
// insert(mDataInsertList);
// insertVersion(mVersionInsertList);
// update(mDataUpdateList);
// update(mVersionUpdateList);
/* mDataInsertList = null;
mDataUpdateList = null;
*/
/*mVersionInsertList = null;
mVersionUpdateList = null;*/
mBuilder.setProgress(100, 0, true);
notification.notify(ID_NOTIFY, mBuilder.build());
if(mCurrentVersionIDs != null) {
mCurrentVersionIDs.clear();
mCurrentVersionIDs = null;
}
if(mCurrentData != null) {
mCurrentData.clear();
mCurrentData = null;
}
if(downloadCountTemp > 0 || !PrefUtils.getBooleanValue(R.string.PREF_EPGPAID_FIRST_DOWNLOAD_DONE, false)) {
to.setTimeZone(TimeZone.getTimeZone("UTC"));
to.set(Calendar.HOUR_OF_DAY, 23);
to.set(Calendar.MINUTE, 59);
to.set(Calendar.SECOND, 59);
to.set(Calendar.MILLISECOND, 999);
updateEpgPaidData(path, notification, to.getTimeInMillis());
}
if(updateList.size() > 0) {
calculateMissingEnds(notification,true,true);
}
else {
finishUpdate(notification,false,true);
}
}
private void readEpgPaidChannelIds(final File channels) {
BufferedReader channelsIn = null;
try {
channelsIn = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(channels)),"UTF-8"));
String line = null;
final String[] projection = {
TvBrowserContentProvider.KEY_ID
};
final Hashtable<String, Object> currentGroups = getCurrentGroups();
final HashSet<String> epgPaidChannelDatabaseKeys = new HashSet<String>();
while((line = channelsIn.readLine()) != null) {
String[] idParts = line.split("_");
if(idParts.length == 2) {
String channelIdKey = null;
Object groupInfo = null;
if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_FREE_KEY).equals(idParts[0].trim())) {
final String[] channelParts = idParts[1].split("-");
final String groupKey = getGroupsKey(SettingConstants.EPG_FREE_KEY,channelParts[0]);
groupInfo = currentGroups.get(groupKey);
channelIdKey = channelParts[1];
}
else if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY).equals(idParts[0].trim())) {
final String groupKey = getGroupsKey(SettingConstants.EPG_DONATE_KEY,SettingConstants.EPG_DONATE_GROUP_KEY);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[1].trim();
}
if(channelIdKey != null && groupInfo != null) {
final StringBuilder selection = new StringBuilder();
selection.append(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID).append("='").append(channelIdKey).append("'");
selection.append(" AND ");
selection.append(TvBrowserContentProvider.GROUP_KEY_GROUP_ID).append(" IS ").append(((Integer)((Object[])groupInfo)[0]).intValue());
final Cursor data = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_CHANNELS, projection, selection.toString(), null, null);
try {
if(IOUtils.prepareAccessFirst(data)) {
final String channelId = String.valueOf(data.getInt(data.getColumnIndex(TvBrowserContentProvider.KEY_ID)));
epgPaidChannelDatabaseKeys.add(channelId);
}
}finally {
IOUtils.close(data);
}
}
}
}
final Editor edit = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_SHARED_GLOBAL, TvDataUpdateService.this).edit();
edit.putStringSet(getString(R.string.PREF_EPGPAID_DATABASE_CHANNEL_IDS), epgPaidChannelDatabaseKeys);
edit.commit();
}catch(Exception e2) {
}
}
private void updateEpgPaidData(File pathBase, NotificationManager notification, long endDateTime) {
final Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
utc.set(Calendar.HOUR_OF_DAY, 0);
utc.set(Calendar.MINUTE, 0);
utc.set(Calendar.SECOND, 0);
utc.set(Calendar.MILLISECOND, 0);
utc.add(Calendar.DAY_OF_YEAR, PrefUtils.getStringValueAsInt(R.string.PREF_EPGPAID_DOWNLOAD_MAX, R.string.pref_epgpaid_download_max_default)+1);
endDateTime = Math.min(endDateTime, utc.getTimeInMillis());
final Calendar yesterday = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
yesterday.set(Calendar.HOUR_OF_DAY, 0);
yesterday.set(Calendar.MINUTE, 0);
yesterday.set(Calendar.SECOND, 0);
yesterday.set(Calendar.MILLISECOND, 0);
yesterday.add(Calendar.DAY_OF_YEAR, -1);
doLog("UPDATE EPGpaidData");
final File epgPaidPath = new File(pathBase, "epgPaidData");
if(!epgPaidPath.isFile()) {
epgPaidPath.mkdirs();
}
mBuilder.setProgress(100, 0, true);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_epgpaid_prepare));
notification.notify(ID_NOTIFY, mBuilder.build());
final EPGpaidDataConnection epgPaidConnection = new EPGpaidDataConnection();
final Hashtable<String, Long> currentDataIds = new Hashtable<String, Long>();
final File fileSummaryCurrent = new File(epgPaidPath,"summary.gz");
final Properties propertiesCurrent = IOUtils.readPropertiesFile(fileSummaryCurrent);
final long endCutOff = endDateTime/60000L;
final long startCutOff = yesterday.getTimeInMillis()/60000L;
doLog("EPGpaidData endDate: " + new Date(endDateTime));
doLog("EPGpaidData propertiesCurrent path: " + fileSummaryCurrent.getAbsolutePath());
doLog("EPGpaidData propertiesCurrent size: " + propertiesCurrent.size());
final String userName = PrefUtils.getStringValue(R.string.PREF_EPGPAID_USER, null);
final String password = PrefUtils.getStringValue(R.string.PREF_EPGPAID_PASSWORD, null);
if(userName != null && password != null
&& userName.trim().length() > 0 && password.trim().length() > 0
&& epgPaidConnection.login(userName, password, getApplicationContext())) {
if(!PrefUtils.getBooleanValue(R.string.PREF_EPGPAID_FIRST_DOWNLOAD_DONE, false)) {
final Editor edit = PrefUtils.getSharedPreferences(PrefUtils.TYPE_PREFERENCES_SHARED_GLOBAL, getApplicationContext()).edit();
edit.putBoolean(getString(R.string.PREF_EPGPAID_FIRST_DOWNLOAD_DONE), true);
edit.commit();
}
doLog("EPGpaid login successfull");
final File channels = new File(epgPaidPath,"channels.gz");
final File oldChannels = new File(epgPaidPath,"channels.gz_old");
if(oldChannels.isFile()) {
oldChannels.delete();
}
channels.renameTo(oldChannels);
if(epgPaidConnection.download(channels.getName(), channels)) {
readEpgPaidChannelIds(channels);
if(oldChannels.isFile()) {
oldChannels.delete();
}
BufferedReader channelsIn = null;
try {
channelsIn = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(channels)),"UTF-8"));
String line = null;
final String[] projection = {
TvBrowserContentProvider.KEY_ID,
TvBrowserContentProvider.DATA_KEY_STARTTIME,
TvBrowserContentProvider.DATA_KEY_TITLE
};
Hashtable<String, Object> currentGroups = getCurrentGroups();
ArrayList<String> downloadChannels = new ArrayList<String>();
while((line = channelsIn.readLine()) != null) {
String[] idParts = line.split("_");
if(idParts.length == 2) {
String channelIdKey = null;
Object groupInfo = null;
if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_FREE_KEY).equals(idParts[0].trim())) {
final String[] channelParts = idParts[1].split("-");
final String groupKey = getGroupsKey(SettingConstants.EPG_FREE_KEY,channelParts[0]);
groupInfo = currentGroups.get(groupKey);
channelIdKey = channelParts[1];
}
else if(SettingConstants.getNumberForDataServiceKey(SettingConstants.EPG_DONATE_KEY).equals(idParts[0].trim())) {
final String groupKey = getGroupsKey(SettingConstants.EPG_DONATE_KEY,SettingConstants.EPG_DONATE_GROUP_KEY);
groupInfo = currentGroups.get(groupKey);
channelIdKey = idParts[1].trim();
}
if(channelIdKey != null && groupInfo != null) {
final StringBuilder selection = new StringBuilder();
selection.append(TvBrowserContentProvider.CHANNEL_TABLE + "." + TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID).append("='").append(channelIdKey).append("'");
selection.append(" AND ");
selection.append(TvBrowserContentProvider.GROUP_KEY_GROUP_ID).append(" IS ").append(((Integer)((Object[])groupInfo)[0]).intValue());
selection.append(" AND ");
selection.append(TvBrowserContentProvider.DATA_KEY_STARTTIME).append("<=").append(endDateTime);
final Cursor data = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_WITH_CHANNEL, projection, selection.toString(), null, TvBrowserContentProvider.DATA_KEY_STARTTIME);
try {
if(IOUtils.prepareAccess(data)) {
downloadChannels.add(line);
final int columnIndexId = data.getColumnIndex(TvBrowserContentProvider.KEY_ID);
final int columnIndexStartTime = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_STARTTIME);
final int columnIndexTitle = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE);
while(data.moveToNext()) {
final long id = data.getLong(columnIndexId);
final long startTime = data.getLong(columnIndexStartTime);
final String title = data.getString(columnIndexTitle).replaceAll("\\p{punct}|\\s+", "_").replaceAll("_+", "_");
currentDataIds.put(line.trim()+";"+startTime+";"+title, id);
doLog("KEY " + line.trim()+";"+startTime+";"+title + " " + id);
}
}
}finally {
IOUtils.close(data);
}
}
}
}
if(!downloadChannels.isEmpty()) {
final File fileSummaryNew = new File(epgPaidPath,"summary_new.gz");
epgPaidConnection.download(fileSummaryCurrent.getName(), fileSummaryNew);
final Properties propertiesNew = IOUtils.readPropertiesFile(fileSummaryNew);
final ArrayList<EPGpaidDownloadFile> downloadFiles = new ArrayList<EPGpaidDownloadFile>();
Set<Object> newData = propertiesNew.keySet();
for(Object key : newData) {
String keyString = key.toString();
for(String channelId : downloadChannels) {
final long dataDate = Long.parseLong(keyString.substring(0,keyString.indexOf("_")));
if(keyString.contains(channelId) && startCutOff <= dataDate && dataDate <= endCutOff) {
String currentVersion = propertiesCurrent.getProperty(keyString,"0,0,0");
currentVersion = currentVersion.substring(0,currentVersion.indexOf(","));
String newVersion = propertiesNew.getProperty(key.toString(),"0,0,0");
newVersion = newVersion.substring(0,newVersion.indexOf(","));
doLog(keyString + " currentVersion " + currentVersion + " newVersion " + newVersion);
final EPGpaidDownloadFile downloadFile = new EPGpaidDownloadFile(Integer.parseInt(newVersion),Integer.parseInt(currentVersion),key.toString()+"base.gz");
if(downloadFile.mVersion > downloadFile.mOldVersion) {
downloadFiles.add(downloadFile);
}
break;
}
}
}
mBuilder.setProgress(downloadFiles.size(), 0, false);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_epgpaid_download));
notification.notify(ID_NOTIFY, mBuilder.build());
int count = 0;
for(EPGpaidDownloadFile download : downloadFiles) {
File target = new File(epgPaidPath,download.mFileName);
File old = new File(epgPaidPath,download.mFileName+"_old_"+(download.mOldVersion));
for(int i = download.mOldVersion-1; i >= 0; i--) {
File previous = new File(epgPaidPath,download.mFileName+"_old_"+i);
if(previous.isFile() && !previous.delete()) {
previous.deleteOnExit();
}
}
if(target.isFile()) {
target.renameTo(old);
}
epgPaidConnection.download(download.mFileName, target);
if(!target.isFile()) {
old.renameTo(target);
}
count++;
if(count % 2 == 0) {
mBuilder.setProgress(downloadFiles.size(), count, false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
}
if(fileSummaryNew.isFile()) {
fileSummaryNew.delete();
}
}
}catch(IOException ioe) {
}finally {
IOUtils.close(channelsIn);
}
}
else if(oldChannels.isFile()) {
oldChannels.renameTo(channels);
doLog("EPGpaid channels could not be loaded");
}
epgPaidConnection.logout();
}
else {
final File channels = new File(epgPaidPath,"channels.gz");
if(!channels.isFile() || (System.currentTimeMillis() - channels.lastModified() > 30*24*60*60000L)) {
final File oldChannels = new File(epgPaidPath,"channels.gz_old");
if(oldChannels.isFile()) {
oldChannels.delete();
}
if(channels.isFile()) {
channels.renameTo(oldChannels);
}
if(mIsConnected && IOUtils.saveUrl(channels.getAbsolutePath(), "https://www.epgpaid.de/download/channels.gz", mInternetConnectionTimeout)) {
readEpgPaidChannelIds(channels);
}
else if(oldChannels.isFile()) {
oldChannels.renameTo(channels);
}
}
doLog("EPGpaid login NOT successfull");
}
final File[] dataFiles = epgPaidPath.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
boolean result = file.getName().toLowerCase(Locale.GERMAN).contains("_base.gz");
if(result) {
final long fileDate = Long.parseLong(file.getName().substring(0, file.getName().indexOf("_")));
result = file.getName().toLowerCase(Locale.GERMAN).endsWith("_base.gz") &&
(startCutOff <= fileDate && fileDate <= endCutOff);
if(fileDate < startCutOff && !file.delete()) {
file.deleteOnExit();
}
}
return result;
}
});
if(dataFiles.length > 0) {
mDataDatabaseOperation = new MemorySizeConstrictedDatabaseOperation(TvDataUpdateService.this,TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE);
final EPGpaidDataHandler handler = new EPGpaidDataHandler();
int count = 0;
mBuilder.setProgress(dataFiles.length, 0, false);
mBuilder.setContentText(getResources().getText(R.string.update_data_notification_epgpaid_process));
notification.notify(ID_NOTIFY, mBuilder.build());
for(final File dataFile : dataFiles) {
doLog("updateDataFromFile " + dataFile.getAbsolutePath());
EPGpaidResult result = handler.readContentValues(dataFile, currentDataIds);
doLog("loadVersion " + result.mVersion);
final int index = dataFile.getName().lastIndexOf("_base.gz");
if(index > 0) {
propertiesCurrent.setProperty(dataFile.getName().substring(0,index+1), result.mVersion+",0,0");
}
if(result.mHadUnknownIds) {
doLog("EPGpaid Missing IDs try to load old data");
File[] oldFiles = epgPaidPath.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.getName().startsWith(dataFile.getName()) && file.getName().contains("_old_");
}
});
doLog("EPGpaid old data count: " + oldFiles.length);
Arrays.sort(oldFiles, DATA_FILE_OLD_COMPARATOR);
for(int i = oldFiles.length-1; i >= 0; i--) {
result = handler.readContentValues(oldFiles[i], currentDataIds);
}
}
count++;
if(count % 2 == 0) {
mBuilder.setProgress(dataFiles.length, count, false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
}
mDataDatabaseOperation.finish();
}
IOUtils.storeProperties(propertiesCurrent, fileSummaryCurrent, "");
}
private static final class CurrentDataHolder {
long mProgramID;
boolean mDontWantToSee;
String mTitle;
}
private void readCurrentVersionIDs() {
if(mCurrentVersionIDs != null) {
mCurrentVersionIDs.clear();
}
else {
mCurrentVersionIDs = new Hashtable<String, int[]>();
}
Cursor ids = null; try {
ids = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA_VERSION, null, null, null, TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
if(ids.getCount() > 0) {
ids.moveToPosition(-1);
int keyColumn = ids.getColumnIndex(TvBrowserContentProvider.KEY_ID);
int channelIDColumn = ids.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
int daysSince1970Column = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_DAYS_SINCE_1970);
int baseVersionColumn = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_BASE_VERSION);
int more0016Column = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_MORE0016_VERSION);
int more1600Column = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_MORE1600_VERSION);
int picture0016Column = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_PICTURE0016_VERSION);
int picture1600Column = ids.getColumnIndex(TvBrowserContentProvider.VERSION_KEY_PICTURE1600_VERSION);
while(ids.moveToNext()) {
int[] versionInfo = new int[6];
versionInfo[0] = ids.getInt(keyColumn);
versionInfo[1] = ids.getInt(baseVersionColumn);
versionInfo[2] = ids.getInt(more0016Column);
versionInfo[3] = ids.getInt(more1600Column);
versionInfo[4] = ids.getInt(picture0016Column);
versionInfo[5] = ids.getInt(picture1600Column);
String id = ids.getInt(channelIDColumn) + "_" + ids.getInt(daysSince1970Column);
mCurrentVersionIDs.put(id, versionInfo);
}
}
} finally {IOUtils.close(ids);}
}
private void readCurrentData() {
try {
IOUtils.deleteOldData(TvDataUpdateService.this);
}catch(Throwable t) {
doLog(t.toString());
}
if(mCurrentData != null) {
mCurrentData.clear();
}
else {
mCurrentData = new Hashtable<String, Hashtable<String,CurrentDataHolder>>();
}
String[] projection = {TvBrowserContentProvider.KEY_ID, TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, TvBrowserContentProvider.DATA_KEY_UNIX_DATE, TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID, TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID, TvBrowserContentProvider.DATA_KEY_TITLE, TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE};
Cursor data = getContentResolver().query(TvBrowserContentProvider.CONTENT_URI_DATA, projection, null, null, TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID + ", " + TvBrowserContentProvider.DATA_KEY_UNIX_DATE + ", " + TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID + ", " + TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID);
try {
Hashtable<String, CurrentDataHolder> current = null;
String currentKey = null;
int keyColumn = data.getColumnIndex(TvBrowserContentProvider.KEY_ID);
int frameIDColumn = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID);
int frameIdStringColumn = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID);
int channelColumn = data.getColumnIndex(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
int unixDateColumn = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_UNIX_DATE);
int titleColumn = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_TITLE);
int dontWantToSeeColumn = data.getColumnIndex(TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE);
if(IOUtils.prepareAccess(data)) {
try {
while(!data.isClosed() && data.moveToNext()) {
long programKey = data.getInt(keyColumn);
String frameID = null;
if(!data.isNull(frameIdStringColumn)) {
frameID = data.getString(frameIdStringColumn);
}
else if(!data.isNull(frameIDColumn)) {
frameID = String.valueOf(data.getInt(frameIDColumn));
}
if(frameID != null && mCurrentData != null) {
int channelID = data.getInt(channelColumn);
long unixDate = data.getLong(unixDateColumn);
String testKey = channelID + "_" + unixDate;
if(currentKey == null || !currentKey.equals(testKey)) {
currentKey = testKey;
current = mCurrentData.get(testKey);
if(current == null) {
current = new Hashtable<String, CurrentDataHolder>();
mCurrentData.put(currentKey, current);
}
}
CurrentDataHolder holder = new CurrentDataHolder();
holder.mProgramID = programKey;
holder.mTitle = data.getString(titleColumn);
holder.mDontWantToSee = data.getInt(dontWantToSeeColumn) == 1;
current.put(frameID, holder);
}
}
}catch(IllegalStateException e) {
}catch(NullPointerException e) {}
}
}finally {
IOUtils.close(data);
}
}
private void updateMirror(File mirrorFile) {
if(mirrorFile.isFile()) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(IOUtils.decompressStream(new FileInputStream(mirrorFile)),"ISO-8859-1"));
StringBuilder mirrors = new StringBuilder();
String line = null;
doLog("Update mirrors from: " + mirrorFile.getName());
while((line = in.readLine()) != null) {
if(line.toLowerCase(Locale.GERMAN).startsWith("http://") || line.toLowerCase(Locale.GERMAN).startsWith("https://")) {
String[] parts = line.split(";");
if(!parts[0].endsWith("/")) {
parts[0] += "/";
}
mirrors.append(parts[0]);
mirrors.append("#");
mirrors.append(parts[1]);
mirrors.append(";");
doLog("Mirror line in file :'" + mirrorFile.getName() + "': " + line);
}
}
if(mirrors.length() > 0) {
mirrors.deleteCharAt(mirrors.length()-1);
}
doLog("Complete mirrors for database for file '" + mirrorFile.getName() + "' " + mirrors.toString());
if(mirrors.length() > 0) {
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.GROUP_KEY_GROUP_MIRRORS, mirrors.toString());
getContentResolver().update(TvBrowserContentProvider.CONTENT_URI_GROUPS, values, TvBrowserContentProvider.GROUP_KEY_GROUP_ID + " = \"" + mirrorFile.getName().substring(0, mirrorFile.getName().lastIndexOf("_"))+"\"", null);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
deleteFile(mirrorFile);
}
}
private Summary readSummary(final File path, final String summaryurl, String groupKey) {
Summary summary = new EPGfreeSummary();
if(groupKey.equals(SettingConstants.EPG_DONATE_GROUP_KEY)) {
summary = new EPGdonateSummary();
}
if(mIsConnected) {
InputStream in = null;
try {
IOUtils.saveUrl(path.getAbsolutePath(), summaryurl, mInternetConnectionTimeout);
if(path.isFile()) {
if(summary instanceof EPGfreeSummary) {
in = new BufferedInputStream(IOUtils.decompressStream(new FileInputStream(path)));
//noinspection ResultOfMethodCallIgnored
in.read(); // read version
long daysSince1970 = ((in.read() & 0xFF) << 16 ) | ((in.read() & 0xFF) << 8) | (in.read() & 0xFF);
((EPGfreeSummary)summary).setStartDaySince1970(daysSince1970);
((EPGfreeSummary)summary).setLevels(in.read());
int frameCount = (in.read() & 0xFF << 8) | (in.read() & 0xFF);
for(int i = 0; i < frameCount; i++) {
int byteCount = in.read();
byte[] value = new byte[byteCount];
//noinspection ResultOfMethodCallIgnored
in.read(value);
String country = new String(value);
byteCount = in.read();
value = new byte[byteCount];
//noinspection ResultOfMethodCallIgnored
in.read(value);
String channelID = new String(value);
int dayCount = in.read();
ChannelFrame frame = new ChannelFrame(country, channelID, dayCount);
for(int day = 0; day < dayCount; day++) {
int[] values = new int[((EPGfreeSummary)summary).getLevels()];
for(int j = 0; j < values.length; j++) {
values[j] = in.read();
}
frame.add(day, values);
}
((EPGfreeSummary)summary).addChannelFrame(frame);
}
}
else if(summary instanceof EPGdonateSummary) {
in = new GZIPInputStream(new FileInputStream(path));
((EPGdonateSummary)summary).load(in);
}
}
} catch (Exception ignored) {}
finally {
IOUtils.close(in);
deleteFile(path);
}
}
return summary;
}
private static final void addArrayToList(ArrayList<String> list, String[] values) {
if(values != null && list != null) {
Collections.addAll(list, values);
}
}
private static final void removeEpgPaidFieldsIfNecessary(ArrayList<String> columnList, String channelId, Set<String> epgPaidChannelIds) {
if(columnList != null && channelId != null && epgPaidChannelIds != null && epgPaidChannelIds.contains(channelId)) {
for(String field : FIELDS_EPGPAID_POSSIBLE) {
columnList.remove(field);
}
}
}
private class UrlFileHolder {
private File mDownloadFile;
private String mDownloadURL;
public UrlFileHolder(File downloadFile, String downloadURL) {
mDownloadFile = downloadFile;
mDownloadURL = downloadURL;
}
public File getDownloadFile() {
return mDownloadFile;
}
public short getFrameCount(short currentCount) {
if(currentCount == 254 && mDownloadURL != null && mIsConnected) {
final String url = mDownloadURL.substring(0, mDownloadURL.indexOf(".prog.gz")) + "_additional.prog.gz";
final String fileName = mDownloadFile.getAbsolutePath().substring(0, mDownloadFile.getAbsolutePath().indexOf(".prog.gz")) + "_additional.prog.gz";
doLog("Download additional data file from '" + url + "'");
BufferedInputStream in = null;
try {
IOUtils.saveUrl(fileName, url, mInternetConnectionTimeout);
doLog("Read frame count from '" + fileName + "'");
in = new BufferedInputStream(IOUtils.decompressStream(new FileInputStream(fileName)));
//noinspection ResultOfMethodCallIgnored
in.read(); // read version
currentCount = (short) (((in.read() & 0xFF) << 8) | (in.read() & 0xFF));
} catch (IOException ignored) {
} finally {
IOUtils.close(in);
}
deleteFile(new File(fileName));
}
return currentCount;
}
}
private class DataInfo {
private byte mFileVersion;
private byte mDataVersion;
private short mFrameCount;
public DataInfo(byte fileVersion, byte dataVersion, short frameCount) {
mFileVersion = fileVersion;
mDataVersion = dataVersion;
mFrameCount = frameCount;
}
public byte getFileVersion() {
return mFileVersion;
}
public byte getDataVersion() {
return mDataVersion;
}
public short getFrameCount() {
return mFrameCount;
}
}
private interface DataHandler {
public Object[] readValuesFromDataFile(ChannelUpdate update, DataInputStream in, int level) throws Throwable;
public DataInfo readDataInfo(ChannelUpdate update, DataInputStream in, UrlFileHolder dataUrlFileHolder) throws IOException;
public void updateVersionTableInternal(ChannelUpdate update);
}
private class EPGfreeDataHandler implements DataHandler {
@Override
public Object[] readValuesFromDataFile(ChannelUpdate update, DataInputStream in, int level)
throws IOException {
short id = (short)(in.read() & 0xFF);
int count = (short)(in.read() & 0xFF);
if(count == 0) {
byte[] addBytes = new byte[(((in.read() & 0xFF) << 8) | (in.read() & 0xFF))];
//noinspection ResultOfMethodCallIgnored
in.read(addBytes);
id = (short)((in.read() & 0xFF) + IOUtils.getIntForBytes(addBytes));
count = (short)(in.read() & 0xFF);
}
ArrayList<String> columnList = new ArrayList<String>();
switch(level) {
case LEVEL_BASE: {
addArrayToList(columnList,FIELDS_LEVEL_BASE);
if(update.mContainsDescription) {
addArrayToList(columnList,FIELDS_LEVEL_MORE);
}
if(update.mContainsPicture) {
addArrayToList(columnList,FIELDS_LEVEL_PICTURE);
}
}break;
case LEVEL_MORE: addArrayToList(columnList,FIELDS_LEVEL_MORE);break;
case LEVEL_PICTURE: addArrayToList(columnList,FIELDS_LEVEL_PICTURE);break;
}
removeEpgPaidFieldsIfNecessary(columnList, String.valueOf(update.getChannelID()), mEpgPaidChannelIds);
ContentValues values = update.mContentValueList.get(String.valueOf(id));
boolean isNew = false;
if(values == null) {
values = new ContentValues();
update.mContentValueList.put(String.valueOf(id), values);
isNew = true;
}
if(!values.containsKey(TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID)) {
values.put(TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID, id);
values.put(TvBrowserContentProvider.DATA_KEY_UNIX_DATE, update.getDate());
values.put(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, update.getChannelID());
}
byte[] fieldInfoBuffer = new byte[4];
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance(update.getTimeZone());
for(byte field = 0; field < count; field++) {
//noinspection ResultOfMethodCallIgnored
in.read(fieldInfoBuffer);
byte fieldType = fieldInfoBuffer[0];
int dataCount = ((fieldInfoBuffer[1] & 0xFF) << 16) | ((fieldInfoBuffer[2] & 0xFF) << 8) | (fieldInfoBuffer[3] & 0xFF);//((in.read() & 0xFF) << 16) | ((in.read() & 0xFF) << 8) | (in.read() & 0xFF);
byte[] data = null;
/* only read data fields with maximum size of MAX_DATA_SIZE
* into memory for usage to prevent OutOfMemoryErrors
*/
if(dataCount <= MAX_DATA_SIZE) {
data = new byte[dataCount];
int read = 0;
while(read < dataCount) {
read += in.read(data, read, dataCount-read);
}
}
else {
fieldType = Byte.MAX_VALUE;
/* read all bytes from stream of too big data
* field to set right start of next field
*/
while(dataCount > 0 && in.read() != -1) {
dataCount--;
}
}
String columnName = null;
if(data != null) {
switch(fieldType) {
case 1: {
int startTime = IOUtils.getIntForBytes(data);
utc.setTimeInMillis(update.getDate());
cal.set(Calendar.DAY_OF_MONTH, utc.get(Calendar.DAY_OF_MONTH));
cal.set(Calendar.MONTH, utc.get(Calendar.MONTH));
cal.set(Calendar.YEAR, utc.get(Calendar.YEAR));
cal.set(Calendar.HOUR_OF_DAY, startTime / 60);
cal.set(Calendar.MINUTE, startTime % 60);
cal.set(Calendar.SECOND, 30);
long time = (((long)(cal.getTimeInMillis() / 60000)) * 60000);
utc.setTimeInMillis(time);
values.put(columnName = TvBrowserContentProvider.DATA_KEY_STARTTIME, time);
// Normalize start hour and minute to 2014-12-31 to have the same time base on all occasions
utc.setTimeInMillis((((long)(IOUtils.normalizeTime(cal, startTime, 30).getTimeInMillis() / 60000)) * 60000));
values.put(TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT, utc.get(Calendar.HOUR_OF_DAY)*60 + utc.get(Calendar.MINUTE));
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT);
}break;
case 2: {
int endTime = IOUtils.getIntForBytes(data);
utc.setTimeInMillis(update.getDate());
cal.set(Calendar.DAY_OF_MONTH, utc.get(Calendar.DAY_OF_MONTH));
cal.set(Calendar.MONTH, utc.get(Calendar.MONTH));
cal.set(Calendar.YEAR, utc.get(Calendar.YEAR));
cal.set(Calendar.HOUR_OF_DAY, endTime / 60);
cal.set(Calendar.MINUTE, endTime % 60);
cal.set(Calendar.SECOND, 30);
Long o = values.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
if(o != null) {
if(o > cal.getTimeInMillis()) {
cal.add(Calendar.DAY_OF_YEAR, 1);
}
}
long time = (((long)(cal.getTimeInMillis() / 60000)) * 60000);
utc.setTimeInMillis(time);
values.put(columnName = TvBrowserContentProvider.DATA_KEY_ENDTIME, time);
// Normalize start hour and minute to 2014-12-31 to have the same time base on all occasions
utc.setTimeInMillis((((long)(IOUtils.normalizeTime(cal, endTime, 30).getTimeInMillis() / 60000)) * 60000));
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, utc.get(Calendar.HOUR_OF_DAY)*60 + utc.get(Calendar.MINUTE));
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT);
}break;
case 3: values.put(columnName = TvBrowserContentProvider.DATA_KEY_TITLE, new String(data));break;
case 4: values.put(columnName = TvBrowserContentProvider.DATA_KEY_TITLE_ORIGINAL, new String(data));break;
case 5: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE, new String(data));break;
case 6: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE_ORIGINAL, new String(data));break;
case 7: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION, new String(data));break;
case 8: values.put(columnName = TvBrowserContentProvider.DATA_KEY_DESCRIPTION, new String(data));break;
case 0xA: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ACTORS, new String(data));break;
case 0xB: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REGIE, new String(data));break;
case 0xC: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CUSTOM_INFO, new String(data));break;
case 0xD: {
int categories = IOUtils.getIntForBytes(data);
values.put(columnName = TvBrowserContentProvider.DATA_KEY_CATEGORIES, categories);
for(int i = 0; i < IOUtils.INFO_CATEGORIES_ARRAY.length; i++) {
values.put(TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY[i], IOUtils.infoSet(categories, IOUtils.INFO_CATEGORIES_ARRAY[i]));
columnList.remove(TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY[i]);
}
}break;
case 0xE: values.put(columnName = TvBrowserContentProvider.DATA_KEY_AGE_LIMIT, IOUtils.getIntForBytes(data));break;
case 0xF: values.put(columnName = TvBrowserContentProvider.DATA_KEY_WEBSITE_LINK, new String(data));break;
case 0x10: values.put(columnName = TvBrowserContentProvider.DATA_KEY_GENRE, new String(data));break;
case 0x11: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ORIGIN, new String(data));break;
case 0x12: values.put(columnName = TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME, IOUtils.getIntForBytes(data));break;
case 0x13: values.put(columnName = TvBrowserContentProvider.DATA_KEY_VPS, IOUtils.getIntForBytes(data));break;
case 0x14: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SCRIPT, new String(data));break;
case 0x15: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REPETITION_FROM, new String(data));break;
case 0x16: values.put(columnName = TvBrowserContentProvider.DATA_KEY_MUSIC, new String(data));break;
case 0x17: values.put(columnName = TvBrowserContentProvider.DATA_KEY_MODERATION, new String(data));break;
case 0x18: values.put(columnName = TvBrowserContentProvider.DATA_KEY_YEAR, IOUtils.getIntForBytes(data));break;
case 0x19: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REPETITION_ON, new String(data));break;
case 0x1A: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE, data);break;
case 0x1B: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE_COPYRIGHT, new String(data));break;
case 0x1C: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE_DESCRIPTION, new String(data));break;
case 0x1D: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER, IOUtils.getIntForBytes(data));break;
case 0x1E: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT, IOUtils.getIntForBytes(data));break;
case 0x1F: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER, IOUtils.getIntForBytes(data));break;
case 0x20: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PRODUCER, new String(data));break;
case 0x21: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CAMERA, new String(data));break;
case 0x22: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CUT, new String(data));break;
case 0x23: values.put(columnName = TvBrowserContentProvider.DATA_KEY_OTHER_PERSONS, new String(data));break;
case 0x24: values.put(columnName = TvBrowserContentProvider.DATA_KEY_RATING, IOUtils.getIntForBytes(data));break;
case 0x25: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PRODUCTION_FIRM, new String(data));break;
case 0x26: values.put(columnName = TvBrowserContentProvider.DATA_KEY_AGE_LIMIT_STRING, new String(data));break;
case 0x27: values.put(columnName = TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR, IOUtils.getIntForBytes(data));break;
case 0x28: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ADDITIONAL_INFO, new String(data));break;
case 0x29: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SERIES, new String(data));break;
}
if(columnName != null) {
columnList.remove(columnName);
}
}
data = null;
}
if(values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) && !values.containsKey(TvBrowserContentProvider.DATA_KEY_ENDTIME)) {
values.put(TvBrowserContentProvider.DATA_KEY_ENDTIME, 0);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, 0);
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, 0);
columnList.remove(TvBrowserContentProvider.DATA_KEY_ENDTIME);
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT);
columnList.remove(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES);
}
else if(values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME)) {
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((values.getAsLong(TvBrowserContentProvider.DATA_KEY_ENDTIME)-values.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME)) / 60000));
columnList.remove(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES);
}
for(String columnName : columnList) {
if(columnName.equals(TvBrowserContentProvider.DATA_KEY_CATEGORIES) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_AGE_LIMIT) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_VPS) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_YEAR) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_RATING) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR)) {
values.put(columnName, (Integer)null);
}
else if(columnName.equals(TvBrowserContentProvider.DATA_KEY_PICTURE)) {
values.put(columnName, (byte[])null);
}
else if(columnNameFromInfo(columnName)) {
values.put(columnName, 0);
}
else {
values.put(columnName, (String)null);
}
}
return new Object[] {String.valueOf(id),isNew};
}
@Override
public DataInfo readDataInfo(ChannelUpdate update, DataInputStream in, UrlFileHolder dataUrlFileHolder) throws IOException{
/* EPGfree data
* fileInfoBuffer[0] contains file version
* fileInfoBuffer[1] contains data version
* fileInfoBuffer[2] contains frame count
*/
byte[] fileInfoBuffer = new byte[3];
//noinspection ResultOfMethodCallIgnored
in.read(fileInfoBuffer);
return new DataInfo(fileInfoBuffer[0],fileInfoBuffer[1],dataUrlFileHolder.getFrameCount((short)(fileInfoBuffer[2] & 0xFF)));
}
@Override
public void updateVersionTableInternal(ChannelUpdate update) {
long daysSince1970 = update.getDate() / 24 / 60 / 60000;
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, update.getChannelID());
values.put(TvBrowserContentProvider.VERSION_KEY_DAYS_SINCE_1970, daysSince1970);
for(String fileName : update.mVersionMap.keySet()) {
Byte dataVersion = update.mVersionMap.get(fileName);
if(dataVersion != null) {
if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_FREE_LEVEL_NAMES[0])) {
values.put(TvBrowserContentProvider.VERSION_KEY_BASE_VERSION,dataVersion);
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_FREE_LEVEL_NAMES[1])) {
values.put(TvBrowserContentProvider.VERSION_KEY_MORE0016_VERSION,dataVersion);
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_FREE_LEVEL_NAMES[2])) {
values.put(TvBrowserContentProvider.VERSION_KEY_MORE1600_VERSION,dataVersion);
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_FREE_LEVEL_NAMES[3])) {
values.put(TvBrowserContentProvider.VERSION_KEY_PICTURE0016_VERSION,dataVersion);
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_FREE_LEVEL_NAMES[4])) {
values.put(TvBrowserContentProvider.VERSION_KEY_PICTURE1600_VERSION,dataVersion);
}
}
}
int[] versionInfo = mCurrentVersionIDs.get(update.getChannelID() + "_" + daysSince1970);
if(versionInfo == null && mVersionDatabaseOperation != null) {
mVersionDatabaseOperation.addInsert(values);
//addVersionInsert(values);
}
else if(mVersionDatabaseOperation != null) {
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_VERSION, versionInfo[0]));
opBuilder.withValues(values);
mVersionDatabaseOperation.addUpdate(opBuilder.build());
//addVersionUpdate(opBuilder.build());
}
}
}
private class EPGpaidDataHandler {
public final EPGpaidResult readContentValues(File file, Hashtable<String, Long> currentDataIds) {
DataInputStream in = null;
final EPGpaidResult result = new EPGpaidResult((byte)0);
try {
in = new DataInputStream(new BufferedInputStream(IOUtils.decompressStream(new FileInputStream(file))));
byte fileVersion = in.readByte();
result.setVersion(in.readByte());
final DataInfo dataInfo = new DataInfo(fileVersion,result.mVersion,in.readShort());
String[] fileParts = file.getName().split("_");
final Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
utc.setTimeInMillis(Long.parseLong(file.getName().substring(0, file.getName().indexOf("_"))) * 60000L);
final long date = utc.getTimeInMillis();
if(dataInfo.getFrameCount() == 0) {
result.setHadUnknownIds();
}
for(int i = 0; i < dataInfo.getFrameCount(); i++) {
// read program id
/*String id =*/ in.readUTF();
byte count = in.readByte();
int startMinutes = 0;
long startTime = -1;
String titleKey = null;
String key = fileParts[1]+"_"+fileParts[2];
ContentValues values = new ContentValues();
String shortDescription = null;
String description = null;
for(byte field = 0; field < count; field++) {
byte fieldType = (byte)in.read();
switch(fieldType) {
case 1: {
startMinutes = in.readShort();
startTime = date + (startMinutes * 60000L);
values.put(TvBrowserContentProvider.DATA_KEY_STARTTIME, startTime);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT, startMinutes);
}break;
case 2: {
int endMinutes = in.readShort();
long endTime = date + (endMinutes * 60000L);
if(endMinutes <= startMinutes) {
endTime += (1440 * 60000L);
}
if(endMinutes >= 1440) {
endMinutes -= 1440;
}
values.put(TvBrowserContentProvider.DATA_KEY_ENDTIME, endTime);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, endMinutes);
}break;
case 3: {
titleKey = in.readUTF();
values.put(TvBrowserContentProvider.DATA_KEY_TITLE, titleKey);
titleKey = titleKey.replaceAll("\\p{Punct}|\\s+", "_").replaceAll("_+", "_");
}break;
case 4: values.put(TvBrowserContentProvider.DATA_KEY_TITLE_ORIGINAL, in.readUTF());break;
case 5: values.put(TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE, in.readUTF());break;
case 6: values.put(TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE_ORIGINAL, in.readUTF());break;
case 7: shortDescription = in.readUTF();break;
case 8: description = in.readUTF();break;
case 0xA: values.put(TvBrowserContentProvider.DATA_KEY_ACTORS, in.readUTF());break;
case 0xB: values.put(TvBrowserContentProvider.DATA_KEY_REGIE, in.readUTF());break;
case 0xC: values.put(TvBrowserContentProvider.DATA_KEY_CUSTOM_INFO, in.readUTF());break;
case 0xD: {
int categories = in.readInt();
values.put(TvBrowserContentProvider.DATA_KEY_CATEGORIES, categories);
for(int j = 0; j < IOUtils.INFO_CATEGORIES_ARRAY.length; j++) {
values.put(TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY[j], IOUtils.infoSet(categories, IOUtils.INFO_CATEGORIES_ARRAY[j]));
}
}break;
case 0xE: values.put(TvBrowserContentProvider.DATA_KEY_AGE_LIMIT, in.readByte());break;
case 0xF: values.put(TvBrowserContentProvider.DATA_KEY_WEBSITE_LINK, in.readUTF());break;
case 0x10: values.put(TvBrowserContentProvider.DATA_KEY_GENRE, in.readUTF());break;
case 0x11: values.put(TvBrowserContentProvider.DATA_KEY_ORIGIN, in.readUTF());break;
case 0x12: values.put(TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME, in.readShort());break;
case 0x13: values.put(TvBrowserContentProvider.DATA_KEY_VPS, in.readShort());break;
case 0x14: values.put(TvBrowserContentProvider.DATA_KEY_SCRIPT, in.readUTF());break;
case 0x15: values.put(TvBrowserContentProvider.DATA_KEY_REPETITION_FROM, in.readUTF());break;
case 0x16: values.put(TvBrowserContentProvider.DATA_KEY_MUSIC, in.readUTF());break;
case 0x17: values.put(TvBrowserContentProvider.DATA_KEY_MODERATION, in.readUTF());break;
case 0x18: values.put(TvBrowserContentProvider.DATA_KEY_YEAR, in.readShort());break;
case 0x19: values.put(TvBrowserContentProvider.DATA_KEY_REPETITION_ON, in.readUTF());break;
case 0x1A: { byte[] data = null;
int dataCount = in.readInt();
/* only read data fields with maximum size of MAX_DATA_SIZE
* into memory for usage to prevent OutOfMemoryErrors
*/
if(dataCount <= MAX_DATA_SIZE) {
data = new byte[dataCount];
int read = 0;
while(read < dataCount) {
read += in.read(data, read, dataCount-read);
}
}
else {
fieldType = Byte.MAX_VALUE;
/* read all bytes from stream of too big data
* field to set right start of next field
*/
while(dataCount > 0 && in.read() != -1) {
dataCount--;
}
}
if(data != null) {
values.put(TvBrowserContentProvider.DATA_KEY_PICTURE, data);
}
}break;
case 0x1B: values.put(TvBrowserContentProvider.DATA_KEY_PICTURE_COPYRIGHT, in.readUTF());break;
case 0x1C: values.put(TvBrowserContentProvider.DATA_KEY_PICTURE_DESCRIPTION, in.readUTF());break;
case 0x1D: values.put(TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER, in.readInt());break;
case 0x1E: values.put(TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT, in.readShort());break;
case 0x1F: values.put(TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER, in.readShort());break;
case 0x20: values.put(TvBrowserContentProvider.DATA_KEY_PRODUCER, in.readUTF());break;
case 0x21: values.put(TvBrowserContentProvider.DATA_KEY_CAMERA, in.readUTF());break;
case 0x22: values.put(TvBrowserContentProvider.DATA_KEY_CUT, in.readUTF());break;
case 0x23: values.put(TvBrowserContentProvider.DATA_KEY_OTHER_PERSONS, in.readUTF());break;
case 0x24: values.put(TvBrowserContentProvider.DATA_KEY_RATING, in.readShort());break;
case 0x25: values.put(TvBrowserContentProvider.DATA_KEY_PRODUCTION_FIRM, in.readUTF());break;
case 0x26: values.put(TvBrowserContentProvider.DATA_KEY_AGE_LIMIT_STRING, in.readUTF());break;
case 0x27: values.put(TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR, in.readShort());break;
case 0x28: values.put(TvBrowserContentProvider.DATA_KEY_ADDITIONAL_INFO, in.readUTF());break;
case 0x29: values.put(TvBrowserContentProvider.DATA_KEY_SERIES, in.readUTF());break;
}
}
if(shortDescription != null) {
values.put(TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION, shortDescription);
}
if(description != null) {
values.put(TvBrowserContentProvider.DATA_KEY_DESCRIPTION, description);
if(shortDescription == null) {
values.put(TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION, "");
}
}
if(titleKey != null) {
key += ";" + startTime + ";" + titleKey;
Long programId = currentDataIds.remove(key);
if(programId != null) {
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE, programId));
opBuilder.withValues(values);
mDataDatabaseOperation.addUpdate(opBuilder.build());
}
else {
result.setHadUnknownIds();
}
}
}
}catch(IOException ioe) {
result.setHadUnknownIds();
Log.d("info8", "", ioe);
//ioe.printStackTrace();
}finally {
IOUtils.close(in);
}
return result;
}
}
private class EPGdonateDataHandler implements DataHandler {
@Override
public Object[] readValuesFromDataFile(ChannelUpdate update, DataInputStream in, int level) throws IOException {
String id = in.readUTF();
byte count = in.readByte();
ArrayList<String> columnList = new ArrayList<String>();
switch(level) {
case LEVEL_BASE: {
addArrayToList(columnList,FIELDS_LEVEL_BASE);
if(update.mContainsDescription) {
addArrayToList(columnList,FIELDS_LEVEL_MORE);
}
if(update.mContainsPicture) {
addArrayToList(columnList,FIELDS_LEVEL_PICTURE);
}
}break;
case LEVEL_MORE: addArrayToList(columnList,FIELDS_LEVEL_MORE);break;
case LEVEL_PICTURE: addArrayToList(columnList,FIELDS_LEVEL_PICTURE);break;
}
removeEpgPaidFieldsIfNecessary(columnList, String.valueOf(update.getChannelID()), mEpgPaidChannelIds);
ContentValues values = update.mContentValueList.get(id);
boolean isNew = false;
if(values == null) {
values = new ContentValues();
update.mContentValueList.put(id, values);
isNew = true;
}
if(!values.containsKey(TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID)) {
values.put(TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID, id);
values.put(TvBrowserContentProvider.DATA_KEY_UNIX_DATE, update.getDate());
values.put(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, update.getChannelID());
}
int startMinutes = 0;
for(byte field = 0; field < count; field++) {
byte fieldType = (byte)in.read();
String columnName = null;
switch(fieldType) {
case 1: {
startMinutes = in.readShort();
long startTime = update.getDate() + (startMinutes * 60000L);
values.put(columnName = TvBrowserContentProvider.DATA_KEY_STARTTIME, startTime);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT, startMinutes);
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_START_MINUTE_AFTER_MIDNIGHT);
}break;
case 2: {
int endMinutes = in.readShort();
long endTime = update.getDate() + (endMinutes * 60000L);
if(endMinutes <= startMinutes) {
endTime += (1440 * 60000L);
}
if(endMinutes >= 1440) {
endMinutes -= 1440;
}
values.put(columnName = TvBrowserContentProvider.DATA_KEY_ENDTIME, endTime);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, endMinutes);
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT);
}break;
case 3: values.put(columnName = TvBrowserContentProvider.DATA_KEY_TITLE, in.readUTF());break;
case 4: values.put(columnName = TvBrowserContentProvider.DATA_KEY_TITLE_ORIGINAL, in.readUTF());break;
case 5: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE, in.readUTF());break;
case 6: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_TITLE_ORIGINAL, in.readUTF());break;
case 7: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SHORT_DESCRIPTION, in.readUTF());break;
case 8: values.put(columnName = TvBrowserContentProvider.DATA_KEY_DESCRIPTION, in.readUTF());break;
case 0xA: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ACTORS, in.readUTF());break;
case 0xB: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REGIE, in.readUTF());break;
case 0xC: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CUSTOM_INFO, in.readUTF());break;
case 0xD: {
int categories = in.readInt();
values.put(columnName = TvBrowserContentProvider.DATA_KEY_CATEGORIES, categories);
for(int i = 0; i < IOUtils.INFO_CATEGORIES_ARRAY.length; i++) {
values.put(TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY[i], IOUtils.infoSet(categories, IOUtils.INFO_CATEGORIES_ARRAY[i]));
columnList.remove(TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY[i]);
}
}break;
case 0xE: values.put(columnName = TvBrowserContentProvider.DATA_KEY_AGE_LIMIT, in.readByte());break;
case 0xF: values.put(columnName = TvBrowserContentProvider.DATA_KEY_WEBSITE_LINK, in.readUTF());break;
case 0x10: values.put(columnName = TvBrowserContentProvider.DATA_KEY_GENRE, in.readUTF());break;
case 0x11: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ORIGIN, in.readUTF());break;
case 0x12: values.put(columnName = TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME, in.readShort());break;
case 0x13: values.put(columnName = TvBrowserContentProvider.DATA_KEY_VPS, in.readShort());break;
case 0x14: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SCRIPT, in.readUTF());break;
case 0x15: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REPETITION_FROM, in.readUTF());break;
case 0x16: values.put(columnName = TvBrowserContentProvider.DATA_KEY_MUSIC, in.readUTF());break;
case 0x17: values.put(columnName = TvBrowserContentProvider.DATA_KEY_MODERATION, in.readUTF());break;
case 0x18: values.put(columnName = TvBrowserContentProvider.DATA_KEY_YEAR, in.readShort());break;
case 0x19: values.put(columnName = TvBrowserContentProvider.DATA_KEY_REPETITION_ON, in.readUTF());break;
case 0x1A: { byte[] data = null;
int dataCount = in.readInt();
/* only read data fields with maximum size of MAX_DATA_SIZE
* into memory for usage to prevent OutOfMemoryErrors
*/
if(dataCount <= MAX_DATA_SIZE) {
data = new byte[dataCount];
int read = 0;
while(read < dataCount) {
read += in.read(data, read, dataCount-read);
}
}
else {
fieldType = Byte.MAX_VALUE;
/* read all bytes from stream of too big data
* field to set right start of next field
*/
while(dataCount > 0 && in.read() != -1) {
dataCount--;
}
}
if(data != null) {
values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE, data);
}
}break;
case 0x1B: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE_COPYRIGHT, in.readUTF());break;
case 0x1C: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PICTURE_DESCRIPTION, in.readUTF());break;
case 0x1D: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER, in.readInt());break;
case 0x1E: values.put(columnName = TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT, in.readShort());break;
case 0x1F: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER, in.readShort());break;
case 0x20: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PRODUCER, in.readUTF());break;
case 0x21: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CAMERA, in.readUTF());break;
case 0x22: values.put(columnName = TvBrowserContentProvider.DATA_KEY_CUT, in.readUTF());break;
case 0x23: values.put(columnName = TvBrowserContentProvider.DATA_KEY_OTHER_PERSONS, in.readUTF());break;
case 0x24: values.put(columnName = TvBrowserContentProvider.DATA_KEY_RATING, in.readShort());break;
case 0x25: values.put(columnName = TvBrowserContentProvider.DATA_KEY_PRODUCTION_FIRM, in.readUTF());break;
case 0x26: values.put(columnName = TvBrowserContentProvider.DATA_KEY_AGE_LIMIT_STRING, in.readUTF());break;
case 0x27: values.put(columnName = TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR, in.readShort());break;
case 0x28: values.put(columnName = TvBrowserContentProvider.DATA_KEY_ADDITIONAL_INFO, in.readUTF());break;
case 0x29: values.put(columnName = TvBrowserContentProvider.DATA_KEY_SERIES, in.readUTF());break;
}
if(columnName != null) {
columnList.remove(columnName);
}
}
if(values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) && !values.containsKey(TvBrowserContentProvider.DATA_KEY_ENDTIME)) {
values.put(TvBrowserContentProvider.DATA_KEY_ENDTIME, 0);
values.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, 0);
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, 0);
columnList.remove(TvBrowserContentProvider.DATA_KEY_ENDTIME);
columnList.remove(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT);
columnList.remove(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES);
}
else if(values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME)) {
values.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((values.getAsLong(TvBrowserContentProvider.DATA_KEY_ENDTIME)-values.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME)) / 60000));
columnList.remove(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES);
}
for(String columnName : columnList) {
if(columnName.equals(TvBrowserContentProvider.DATA_KEY_CATEGORIES) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_AGE_LIMIT) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_NETTO_PLAY_TIME) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_VPS) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_YEAR) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_EPISODE_NUMBER) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_EPISODE_COUNT) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_SEASON_NUMBER) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_RATING) ||
columnName.equals(TvBrowserContentProvider.DATA_KEY_LAST_PRODUCTION_YEAR)) {
values.put(columnName, (Integer)null);
}
else if(columnName.equals(TvBrowserContentProvider.DATA_KEY_PICTURE)) {
values.put(columnName, (byte[])null);
}
else if(columnNameFromInfo(columnName)) {
values.put(columnName, 0);
}
else {
values.put(columnName, (String)null);
}
}
return new Object[] {id,isNew};
}
@Override
public DataInfo readDataInfo(ChannelUpdate update, DataInputStream in, UrlFileHolder urlFileHolder) throws IOException {
byte fileVersion = in.readByte();
byte dataVersion = in.readByte();
return new DataInfo(fileVersion,dataVersion,in.readShort());
}
@Override
public void updateVersionTableInternal(ChannelUpdate update) {
long daysSince1970 = update.getDate() / 24 / 60 / 60000;
ContentValues values = new ContentValues();
values.put(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID, update.getChannelID());
values.put(TvBrowserContentProvider.VERSION_KEY_DAYS_SINCE_1970, daysSince1970);
for(String fileName : update.mVersionMap.keySet()) {
Byte dataVersion = update.mVersionMap.get(fileName);
Log.d("info21","ADD VERSION INFO " + fileName + " " + update.getChannelID() + "_" + daysSince1970 + " " + dataVersion);
if(dataVersion != null) {
if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_DONATE_LEVEL_NAMES[0])) {
values.put(TvBrowserContentProvider.VERSION_KEY_BASE_VERSION,dataVersion.intValue());
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_DONATE_LEVEL_NAMES[1])) {
values.put(TvBrowserContentProvider.VERSION_KEY_MORE1600_VERSION,dataVersion.intValue());
}
else if(fileName.toLowerCase(Locale.GERMAN).contains(SettingConstants.EPG_DONATE_LEVEL_NAMES[2])) {
values.put(TvBrowserContentProvider.VERSION_KEY_PICTURE1600_VERSION,dataVersion.intValue());
}
}
}
int[] versionInfo = mCurrentVersionIDs.get(update.getChannelID() + "_" + daysSince1970);
Log.d("info21","currentInfo " + versionInfo + " BASE " + values.getAsByte(TvBrowserContentProvider.VERSION_KEY_BASE_VERSION));
if(versionInfo == null && mVersionDatabaseOperation != null) {
mVersionDatabaseOperation.addInsert(values);
//addVersionInsert(values);
}
else if(mVersionDatabaseOperation != null) {
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_VERSION, versionInfo[0]));
opBuilder.withValues(values);
mVersionDatabaseOperation.addUpdate(opBuilder.build());
//addVersionUpdate(opBuilder.build());
}
}
}
/**
* Helper class for data update.
* Stores url, channel ID, timezone and date of a channel.
*
* @author René Mach
*/
private class ChannelUpdate {
private ArrayList<String> mUrlList;
private long mChannelID;
private String mTimeZone;
private long mDate;
private HashMap<String, ContentValues> mContentValueList;
private HashMap<String, Byte> mVersionMap;
private ArrayList<ContentValues> mInsertValuesList;
private LongSparseArray<ContentValues> mUpdateValueMap;
private boolean mContainsPicture;
private boolean mContainsDescription;
private DataHandler mDataHandler;
/**
*
* @param dataHandler
* @param channelID
* @param timezone
* @param date Start time in milliseconds since 1970 for UTC 0 o'clock.
*/
public ChannelUpdate(DataHandler dataHandler, long channelID, String timezone, long date) {
mDataHandler = dataHandler;
mChannelID = channelID;
if(timezone.startsWith("GMT+01:00")) {
mTimeZone = "CET";
}
else if(timezone.equals("GMT")) {
mTimeZone = "WET";
}
else {
mTimeZone = timezone;
}
mDate = date;
mUrlList = new ArrayList<String>();
mContentValueList = new HashMap<String, ContentValues>(0);
mInsertValuesList = new ArrayList<ContentValues>();
mVersionMap = new HashMap<String, Byte>();
mUpdateValueMap = new LongSparseArray<ContentValues>();
mContainsDescription = false;
mContainsPicture = false;
}
public void addURL(String url) {
mUrlList.add(url);
mContainsDescription = url.contains("_more");
mContainsPicture = url.contains("_picture");
}
public long getChannelID() {
return mChannelID;
}
public TimeZone getTimeZone() {
return TimeZone.getTimeZone(mTimeZone);
}
public long getDate() {
return mDate;
}
public boolean toDownload() {
return !mUrlList.isEmpty();
}
public int size() {
return mUrlList.size();
}
private ArrayList<UrlFileHolder> mDownloadList;
public void addDownloadedFile(File file) {
if(mDownloadList == null) {
mDownloadList = new ArrayList<UrlFileHolder>();
}
mDownloadList.add(new UrlFileHolder(file, null));
}
public void startUpdate(final NotificationManager notification, final int downloadCount, final UncaughtExceptionHandler handleExc) {
if(!mDataUpdatePool.isShutdown()) {
mDataUpdatePool.execute(new Thread("CHANNEL UPDATE HANDLE START UPDATE") {
@Override
public void run() {
setUncaughtExceptionHandler(handleExc);
for(UrlFileHolder updateFile : mDownloadList) {
handleDownload(updateFile);
}
handleData();
if(mShowNotification) {
mCurrentDownloadCount++;
mBuilder.setProgress(downloadCount, mCurrentDownloadCount, false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
}
});
}
}
public void download(File path, final NotificationManager notification, final int downloadCount) {
final ArrayList<UrlFileHolder> downloadList = new ArrayList<UrlFileHolder>();
for(String url : mUrlList) {
File updateFile = new File(path,url.substring(url.lastIndexOf("/")+1));
if(mIsConnected) {
try {
long downloadStart = System.currentTimeMillis();
if(IOUtils.saveUrl(updateFile.getAbsolutePath(), url, mInternetConnectionTimeout)) {
downloadList.add(new UrlFileHolder(updateFile, url));
}
else {
mUnsuccessfulDownloads++;
}
checkAndSetConnectionState(downloadStart);
} catch (Exception e) {
mUnsuccessfulDownloads++;
}
}
}
if(!mDataUpdatePool.isShutdown()) {
mDataUpdatePool.execute(new Thread("CHANNEL UPDATE HANDLE DOWNLOAD") {
@Override
public void run() {
for(UrlFileHolder updateFile : downloadList) {
handleDownload(updateFile);
if(mShowNotification) {
mCurrentDownloadCount++;
mBuilder.setProgress(downloadCount, mCurrentDownloadCount, false);
notification.notify(ID_NOTIFY, mBuilder.build());
}
}
handleData();
}
});
}
}
private void handleData() {
if(!mInsertValuesList.isEmpty()) {
Collections.sort(mInsertValuesList, new Comparator<ContentValues>() {
@Override
public int compare(ContentValues lhs, ContentValues rhs) {
if(lhs.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) && rhs.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME)) {
long lStart = lhs.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
long rStart = rhs.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
if(lStart < rStart) {
return -1;
}
else if(lStart > rStart) {
return 1;
}
}
return 0;
}
});
ContentValues toAdd = mInsertValuesList.get(0);
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar cal = Calendar.getInstance(getTimeZone());
for(int i = 1; i < mInsertValuesList.size()-1; i++) {
if(toAdd.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME)) {
if(!toAdd.containsKey(TvBrowserContentProvider.DATA_KEY_ENDTIME) || toAdd.getAsLong(TvBrowserContentProvider.DATA_KEY_ENDTIME) == 0) {
long meStart = toAdd.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
int j = i;
while(j < mInsertValuesList.size() && meStart == mInsertValuesList.get(j).getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME)) {
j++;
}
if(j < mInsertValuesList.size()) {
long nextStart = mInsertValuesList.get(j).getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
if((nextStart - meStart) >= (12 * 60 * 60000)) {
nextStart = meStart + (long)(2.5 * 60 * 60000);
}
cal.setTimeInMillis(nextStart);
int startHour = cal.get(Calendar.HOUR_OF_DAY);
int startMinute = cal.get(Calendar.MILLISECOND);
// Normalize start hour and minute to 2014-12-31 to have the same time base on all occasions
utc.setTimeInMillis((((long)(IOUtils.normalizeTime(cal, startHour, startMinute, 30).getTimeInMillis() / 60000)) * 60000));
toAdd.put(TvBrowserContentProvider.DATA_KEY_UTC_END_MINUTE_AFTER_MIDNIGHT, utc.get(Calendar.HOUR_OF_DAY)*60 + utc.get(Calendar.MINUTE));
toAdd.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((nextStart - meStart)/60000));
toAdd.put(TvBrowserContentProvider.DATA_KEY_ENDTIME, nextStart);
}
}
else {
long meStart = toAdd.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME);
long meEnd = toAdd.getAsLong(TvBrowserContentProvider.DATA_KEY_ENDTIME);
toAdd.put(TvBrowserContentProvider.DATA_KEY_DURATION_IN_MINUTES, (int)((meEnd - meStart)/60000));
}
}
toAdd = mInsertValuesList.get(i);
}
for(ContentValues values : mInsertValuesList) {
if(values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) && mDataDatabaseOperation != null) {
mDataDatabaseOperation.addInsert(values);
//addInsert(values);
}
}
}
if(mUpdateValueMap!=null) {
for(int i=0; i<mUpdateValueMap.size(); i++) {
final long programID = mUpdateValueMap.keyAt(i);
ContentValues value = mUpdateValueMap.get(programID);
if(value != null && mDataDatabaseOperation != null) {
ContentProviderOperation.Builder opBuilder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE, programID));
opBuilder.withValues(value);
mDataDatabaseOperation.addUpdate(opBuilder.build());
//addUpdate(opBuilder.build());
}
}
}
mDataHandler.updateVersionTableInternal(this);
clear();
}
public void clear() {
mContentValueList.clear();
mVersionMap.clear();
mUpdateValueMap.clear();
mInsertValuesList.clear();
if(mDownloadList != null) {
mDownloadList.clear();
mDownloadList = null;
}
mContentValueList = null;
mVersionMap = null;
mUpdateValueMap = null;
mInsertValuesList = null;
}
private void handleDownload(UrlFileHolder dataUrlFileHolder) {
File dataFile = dataUrlFileHolder.getDownloadFile();
Log.d("info21", "FILE " + dataFile.getAbsolutePath());
if(dataFile.isFile()) {
doLog("Read data from file: " +dataFile.getAbsolutePath());
DataInputStream in = null;
try {
ByteArrayOutputStream temp = null;
try {
in = new DataInputStream(new BufferedInputStream(IOUtils.decompressStream(new FileInputStream(dataFile))));
temp = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int count = 0;
int readCount = 0;
while((count = in.read(buffer)) > 0) {
temp.write(buffer, readCount, count);
}
IOUtils.close(in);
in = new DataInputStream(new ByteArrayInputStream(temp.toByteArray()));
}catch(IOException ignored) {
} finally {
IOUtils.close(temp);
}
final DataInfo dataInfo = mDataHandler.readDataInfo(this, in, dataUrlFileHolder);
doLog("Frame count of data file: '" +dataFile.getName() + "': " + dataInfo.getFrameCount() + " CURRENT DATA STATE: " + (mCurrentData != null));
ArrayList<String> missingFrameIDs = null;
String key = getChannelID() + "_" + getDate();
Hashtable<String, CurrentDataHolder> current = mCurrentData.get(key);
int level = LEVEL_BASE;
if(dataFile.getName().contains("_more")) {
level = LEVEL_MORE;
}
else if(dataFile.getName().contains("_picture")) {
level = LEVEL_PICTURE;
}
doLogData(" LEVEL " + level);
if(current != null && level == LEVEL_BASE) {
Set<String> keySet = current.keySet();
missingFrameIDs = new ArrayList<String>(keySet.size());
for(String frameID : keySet) {
missingFrameIDs.add(frameID);
}
doLog("CURRENT FRAMES COUNT FOR '" + dataFile.getName() + "' " + missingFrameIDs.size());
}
for(int i = 0; i < dataInfo.getFrameCount(); i++) {
try {
Object[] info = mDataHandler.readValuesFromDataFile(this, in, level);
String frameID = (String)info[0];
boolean isNew = (Boolean)info[1];
ContentValues contentValues = mContentValueList.get(frameID);
if(contentValues == null) {
break;
}
long programID = -1;
CurrentDataHolder value = null;
if(current != null) {
value = current.get(frameID);
if(value != null) {
programID = value.mProgramID;
}
}
if(contentValues.size() > 0) {
if(missingFrameIDs != null) {
missingFrameIDs.remove(frameID);
}
if(programID >= 0) {
if(level == LEVEL_BASE && mDontWantToSeeValues != null) {
String title = contentValues.getAsString(TvBrowserContentProvider.DATA_KEY_TITLE);
if(title != null) {
if(title.equals(value.mTitle)) {
contentValues.put(TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE, value.mDontWantToSee ? 1 : 0);
}
else if(UiUtils.filter(TvDataUpdateService.this, title, mDontWantToSeeValues)) {
contentValues.put(TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE, 1);
}
}
}
// program known update it
if(isNew && isValidDataContent(contentValues)) {
mUpdateValueMap.put(Long.valueOf(programID), contentValues);
}
}
else if(contentValues.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) && contentValues.get(TvBrowserContentProvider.DATA_KEY_STARTTIME) != null) {
// program unknown insert it
if(level == LEVEL_BASE && mDontWantToSeeValues != null) {
String title = contentValues.getAsString(TvBrowserContentProvider.DATA_KEY_TITLE);
if(UiUtils.filter(TvDataUpdateService.this, title, mDontWantToSeeValues)) {
contentValues.put(TvBrowserContentProvider.DATA_KEY_DONT_WANT_TO_SEE, 1);
}
}
if(isNew && isValidDataContent(contentValues)) {
mInsertValuesList.add(contentValues);
}
}
else if(level == LEVEL_BASE) {
// insert but no start time key or start time is null, dismiss
mContentValueList.remove(frameID);
mInsertValuesList.remove(contentValues);
}
}
}catch(Throwable t) {
StackTraceElement[] elements = t.getStackTrace();
StringBuilder message = new StringBuilder();
for(StackTraceElement el : elements) {
message.append(el.getFileName()).append(" ").append(el.getLineNumber()).append(" ").append(el.getClassName()).append(" ").append(el.getMethodName()).append("\n");
}
doLog("Error read data file: '" +dataFile.getAbsolutePath() + "': " + t.getMessage() + " " + message.toString());
}
}
Log.d("info21", "VERSION " + dataFile.getName() + " " + dataInfo.getDataVersion());
mVersionMap.put(dataFile.getName(), dataInfo.getDataVersion());
if(level == LEVEL_BASE && missingFrameIDs != null && !missingFrameIDs.isEmpty()) {
StringBuilder where = new StringBuilder(" ( ( ");
where.append(TvBrowserContentProvider.DATA_KEY_DATE_PROG_ID);
where.append(" IN ( ");
where.append(TextUtils.join(", ", missingFrameIDs));
where.append(" ) ) OR ( ");
where.append(TvBrowserContentProvider.DATA_KEY_DATE_PROG_STRING_ID);
where.append(" IN ( '");
where.append(TextUtils.join("', '", missingFrameIDs));
where.append("' ) ) ) ");
where.append(" AND ");
where.append(" ( ");
where.append(TvBrowserContentProvider.DATA_KEY_UNIX_DATE);
where.append(" = ");
where.append(getDate());
where.append(" ) AND ( ");
where.append(TvBrowserContentProvider.CHANNEL_KEY_CHANNEL_ID);
where.append(" = ");
where.append(getChannelID());
where.append(" ) ");
doLog(" DELETE WHERE " + where);
Log.d("info66", " DELETE WHERE " + where);
int deletedRows = getContentResolver().delete(TvBrowserContentProvider.CONTENT_URI_DATA_UPDATE, where.toString(), null);
doLog(" DELETED ROWS: " + deletedRows);
Log.d("info66", " DELETED ROWS: " + deletedRows);
}
Log.d("info5", "INSERTED");
} catch (Exception e) {
StackTraceElement[] elements = e.getStackTrace();
StringBuilder message = new StringBuilder();
for(StackTraceElement el : elements) {
message.append(el.getFileName()).append(" ").append(el.getLineNumber()).append(" ").append(el.getClassName()).append(" ").append(el.getMethodName()).append("\n");
}
doLog("Error read data file: '" +dataFile.getAbsolutePath() + "': " + e.getMessage() + " " + message.toString());
Log.d("info5", "error data update", e);
} finally {
IOUtils.close(in);
}
deleteFile(dataFile);
doLog("Read data DONE from file: " +dataFile.getAbsolutePath());
}
else {
Log.d("info5", "file not available " + dataFile.getPath());
}
}
@Override
public String toString() {
return "ChannelID: " + mChannelID + " " + new Date(mDate) + " TimeZone: " + mTimeZone;
}
}
private boolean columnNameFromInfo(String columnName) {
for(String name : TvBrowserContentProvider.INFO_CATEGORIES_COLUMNS_ARRAY) {
if(name.equals(columnName)) {
return true;
}
}
return false;
}
private static boolean isValidDataContent(ContentValues values) {
boolean result = true;
if((!values.containsKey(TvBrowserContentProvider.DATA_KEY_STARTTIME) || values.getAsLong(TvBrowserContentProvider.DATA_KEY_STARTTIME) == null)
||
(!values.containsKey(TvBrowserContentProvider.DATA_KEY_ENDTIME) || values.getAsLong(TvBrowserContentProvider.DATA_KEY_ENDTIME) == null)
||
(!values.containsKey(TvBrowserContentProvider.DATA_KEY_TITLE) || values.getAsString(TvBrowserContentProvider.DATA_KEY_TITLE) == null)) {
result = false;
}
return result;
}
/**
* Class that stores informations about available data for a channel on an update server.
* <p>
* @author René Mach
*/
@SuppressLint("UseSparseArrays")
private static class ChannelFrame {
private String mCountry;
private String mChannelID;
private int mDayCount;
private HashMap<Integer,int[]> mLevelVersions;
public ChannelFrame(String country, String channelID, int dayCount) {
mCountry = country;
mChannelID = channelID;
mDayCount = dayCount;
mLevelVersions = new HashMap<Integer, int[]>();
}
public void add(int day, int[] levelVersions) {
mLevelVersions.put(day, levelVersions);
}
public int[] getVersionForDay(int day) {
return mLevelVersions.get(day);
}
public int getDayCount() {
return mDayCount;
}
public String getCountry() {
return mCountry;
}
public String getChannelID() {
return mChannelID;
}
}
private static interface Summary {}
/**
* Helper class that stores informations about the available data
* on an update server.
*
* @author René Mach
*/
private static class EPGfreeSummary implements Summary {
private long mStartDaySince1970;
private int mLevels;
/**
* List with available ChannelFrames for the server.
*/
private ArrayList<ChannelFrame> mFrameList;
public EPGfreeSummary() {
mFrameList = new ArrayList<ChannelFrame>();
}
public void setStartDaySince1970(long days) {
mStartDaySince1970 = days-1;
}
public void setLevels(int levels) {
mLevels = levels;
}
public void addChannelFrame(ChannelFrame frame) {
mFrameList.add(frame);
}
public int getLevels() {
return mLevels;
}
public Calendar getStartDate() {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
// calculate the number of miliseconds since 1970 to get to the UNIX time
cal.setTimeInMillis(mStartDaySince1970 * 24 * 60 * 60000);
return cal;
}
/**
* Get the ChannelFrame for the given channel ID
* <p>
* @param channelID The channel ID to get the ChannelFrame for.
* @return The requested ChannelFrame or <code>null</code> if there is no ChannelFrame for given ID.
*/
public ChannelFrame getChannelFrame(String channelID) {
for(ChannelFrame frame : mFrameList) {
if(frame.mChannelID.equals(channelID)) {
return frame;
}
}
return null;
}
}
private static final class EPGdonateSummary extends Properties implements Summary {}
private static final class EPGpaidDownloadFile {
private int mVersion;
private int mOldVersion;
private String mFileName;
private EPGpaidDownloadFile(int version, int oldVersion, String fileName) {
mVersion = version;
mOldVersion = oldVersion;
mFileName = fileName;
}
}
private static final class EPGpaidResult {
private byte mVersion;
private boolean mHadUnknownIds;
private EPGpaidResult(byte version) {
mVersion = version;
mHadUnknownIds = false;
}
private void setVersion(byte version) {
mVersion = version;
}
private void setHadUnknownIds() {
if(!mHadUnknownIds) {
mHadUnknownIds = true;
}
}
}
}