Java tutorial
/* * Copyright (C) 2011 John Trnblom * * This file is part of TVHGuide. * * TVHGuide is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * TVHGuide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with TVHGuide. If not, see <http://www.gnu.org/licenses/>. */ package org.tvheadend.tvhclient.htsp; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.MalformedURLException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.tvheadend.tvhclient.Constants; import org.tvheadend.tvhclient.R; import org.tvheadend.tvhclient.TVHClientApplication; import org.tvheadend.tvhclient.interfaces.HTSConnectionListener; import org.tvheadend.tvhclient.model.Channel; import org.tvheadend.tvhclient.model.ChannelTag; import org.tvheadend.tvhclient.model.DvrCutpoint; import org.tvheadend.tvhclient.model.HttpTicket; import org.tvheadend.tvhclient.model.Packet; import org.tvheadend.tvhclient.model.Profiles; import org.tvheadend.tvhclient.model.Program; import org.tvheadend.tvhclient.model.Recording; import org.tvheadend.tvhclient.model.SeriesInfo; import org.tvheadend.tvhclient.model.SeriesRecording; import org.tvheadend.tvhclient.model.SourceInfo; import org.tvheadend.tvhclient.model.Stream; import org.tvheadend.tvhclient.model.Subscription; import org.tvheadend.tvhclient.model.TimerRecording; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Binder; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.Log; /** * * @author john-tornblom * @author Robert Siebert */ public class HTSService extends Service implements HTSConnectionListener { private static final String TAG = HTSService.class.getSimpleName(); private ScheduledExecutorService execService; private HTSConnection connection; PackageInfo packInfo; private NotificationManager notificationManager = null; private SharedPreferences prefs; public class LocalBinder extends Binder { HTSService getService() { return HTSService.this; } } @Override public void onCreate() { execService = Executors.newScheduledThreadPool(5); prefs = PreferenceManager.getDefaultSharedPreferences(this); notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); try { packInfo = getPackageManager().getPackageInfo(getPackageName(), 0); } catch (NameNotFoundException ex) { Log.e(TAG, "Can't get package info", ex); } } @Override public int onStartCommand(Intent intent, int flags, int startId) { final String action = intent.getAction(); if (action.equals(Constants.ACTION_CONNECT)) { boolean force = intent.getBooleanExtra("force", false); boolean async = intent.getBooleanExtra("async", true); final String hostname = intent.getStringExtra("hostname"); final int port = intent.getIntExtra("port", 9982); final String username = intent.getStringExtra("username"); final String password = intent.getStringExtra("password"); if (connection != null && force) { connection.close(); } if (connection == null || !connection.isConnected()) { final TVHClientApplication app = (TVHClientApplication) getApplication(); app.clearAll(); app.setLoading(true); connection = new HTSConnection(this, packInfo.packageName, packInfo.versionName, async); // Since this is blocking, spawn to a new thread execService.execute(new Runnable() { public void run() { connection.open(hostname, port); connection.authenticate(username, password); } }); } } else if (connection == null || !connection.isConnected()) { Log.e(TAG, "No connection to perform " + action); } else if (action.equals(Constants.ACTION_DISCONNECT)) { connection.close(); } else if (action.equals(Constants.ACTION_GET_EVENT)) { getEvent(intent.getLongExtra("eventId", 0)); } else if (action.equals(Constants.ACTION_GET_EVENTS)) { TVHClientApplication app = (TVHClientApplication) getApplication(); final Channel ch = app.getChannel(intent.getLongExtra("channelId", 0)); getEvents(ch, intent.getLongExtra("eventId", 0), intent.getIntExtra("count", 10)); } else if (action.equals(Constants.ACTION_ADD_DVR_ENTRY)) { TVHClientApplication app = (TVHClientApplication) getApplication(); Channel ch = app.getChannel(intent.getLongExtra("channelId", 0)); addDvrEntry(ch, intent.getLongExtra("eventId", 0)); } else if (action.equals(Constants.ACTION_DELETE_DVR_ENTRY)) { deleteDvrEntry(Integer.valueOf(intent.getStringExtra("id"))); } else if (action.equals(Constants.ACTION_CANCEL_DVR_ENTRY)) { cancelDvrEntry(intent.getLongExtra("id", 0)); } else if (action.equals(Constants.ACTION_ADD_TIMER_REC_ENTRY)) { addTimerRecEntry(intent.getStringExtra("title"), intent.getLongExtra("start", 0), intent.getLongExtra("stop", 0), intent.getLongExtra("channelId", 0), intent.getStringExtra("configName"), intent.getLongExtra("retention", 0), intent.getLongExtra("daysOfWeek", 0), intent.getLongExtra("priority", 0), intent.getLongExtra("enabled", 0), intent.getStringExtra("name"), intent.getStringExtra("directory")); } else if (action.equals(Constants.ACTION_DELETE_TIMER_REC_ENTRY)) { deleteTimerRecEntry(intent.getStringExtra("id")); } else if (action.equals(Constants.ACTION_EPG_QUERY)) { TVHClientApplication app = (TVHClientApplication) getApplication(); Channel ch = app.getChannel(intent.getLongExtra("channelId", 0)); epgQuery(ch, intent.getStringExtra("query"), intent.getLongExtra("tagId", 0)); } else if (action.equals(Constants.ACTION_SUBSCRIBE)) { subscribe(intent.getLongExtra("channelId", 0), intent.getLongExtra("subscriptionId", 0), intent.getIntExtra("maxWidth", 0), intent.getIntExtra("maxHeight", 0), intent.getStringExtra("audioCodec"), intent.getStringExtra("videoCodec")); } else if (action.equals(Constants.ACTION_UNSUBSCRIBE)) { unsubscribe(intent.getLongExtra("subscriptionId", 0)); } else if (action.equals(Constants.ACTION_FEEDBACK)) { feedback(intent.getLongExtra("subscriptionId", 0), intent.getIntExtra("speed", 0)); } else if (action.equals(Constants.ACTION_GET_TICKET)) { TVHClientApplication app = (TVHClientApplication) getApplication(); Channel ch = app.getChannel(intent.getLongExtra("channelId", 0)); Recording rec = app.getRecording(intent.getLongExtra("dvrId", 0)); if (ch != null) { getTicket(ch); } else if (rec != null) { getTicket(rec); } } else if (action.equals(Constants.ACTION_GET_DISC_SPACE)) { getDiscSpace(); } else if (action.equals(Constants.ACTION_GET_DVR_CONFIG)) { getDvrConfigs(); } else if (action.equals(Constants.ACTION_GET_PROFILES)) { getProfiles(); } else if (action.equals(Constants.ACTION_GET_CHANNEL)) { TVHClientApplication app = (TVHClientApplication) getApplication(); Channel ch = app.getChannel(intent.getLongExtra("channelId", 0)); if (ch != null) { getChannel(ch); } } else if (action.equals(Constants.ACTION_SUBSCRIBE_FILTER_STREAM)) { subscriptionFilterStream(); } else if (action.equals(Constants.ACTION_GET_DVR_CUTPOINTS)) { TVHClientApplication app = (TVHClientApplication) getApplication(); Recording rec = app.getRecording(intent.getLongExtra("dvrId", 0)); if (rec != null) { getDvrCutpoints(rec); } } else if (action.equals(Constants.ACTION_ADD_SERIES_DVR_ENTRY)) { addAutorecEntry(intent.getStringExtra("title"), intent.getLongExtra("channelId", 0), intent.getStringExtra("configName"), intent.getLongExtra("maxDuration", 0), intent.getLongExtra("minDuration", 0), intent.getLongExtra("retention", 0), intent.getLongExtra("daysOfWeek", 127), intent.getLongExtra("priority", 0), intent.getLongExtra("enabled", 1), intent.getLongExtra("startExtra", 0), intent.getLongExtra("stopExtra", 0), intent.getStringExtra("name"), intent.getStringExtra("directory")); } else if (action.equals(Constants.ACTION_DELETE_SERIES_DVR_ENTRY)) { String id = intent.getStringExtra("id"); deleteAutorecEntry(id); } else if (action.equals(Constants.ACTION_GET_SYSTEM_TIME)) { getSystemTime(); } return START_NOT_STICKY; } @Override public void onDestroy() { execService.shutdown(); if (connection != null) { connection.close(); } } public void onError(final String error) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.setLoading(false); app.setConnectionState(error); } @Override public IBinder onBind(Intent intent) { return mBinder; } private final IBinder mBinder = new LocalBinder(); private void onTagAdd(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); ChannelTag tag = new ChannelTag(); tag.id = msg.getLong("tagId"); tag.name = msg.getString("tagName", ""); tag.icon = msg.getString("tagIcon", ""); app.addChannelTag(tag); if (tag.icon != null) { getChannelTagIcon(tag); } } private void onTagUpdate(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); ChannelTag tag = app.getChannelTag(msg.getLong("tagId")); if (tag == null) { return; } tag.name = msg.getString("tagName", tag.name); String icon = msg.getString("tagIcon", tag.icon); if (icon == null) { tag.icon = null; tag.iconBitmap = null; } else if (!icon.equals(tag.icon)) { tag.icon = icon; getChannelTagIcon(tag); } } private void onTagDelete(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.removeChannelTag(msg.getLong("tagId")); } private void onChannelAdd(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); final Channel ch = new Channel(); ch.id = msg.getLong("channelId"); ch.name = msg.getString("channelName", ""); ch.number = msg.getInt("channelNumber", 0); // The default values will be set in case a server with a htsp API // version 12 or lower is used ch.numberMinor = msg.getInt("channelNumberMinor", 0); ch.icon = msg.getString("channelIcon", ""); ch.tags = msg.getIntList("tags", ch.tags); if (ch.number == 0) { ch.number = (int) (ch.id + 25000); } app.addChannel(ch); if (ch.icon != null) { getChannelIcon(ch); } long currEventId = msg.getLong("eventId", 0); long nextEventId = msg.getLong("nextEventId", 0); ch.isTransmitting = (currEventId != 0); if (currEventId > 0) { getEvents(ch, currEventId, 5); } else if (nextEventId > 0) { getEvents(ch, nextEventId, 5); } } private void onChannelUpdate(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); final Channel ch = app.getChannel(msg.getLong("channelId")); if (ch == null) { return; } ch.name = msg.getString("channelName", ch.name); ch.number = msg.getInt("channelNumber", ch.number); // The default values will be set in case a server with a htsp API // version 12 or lower is used ch.numberMinor = msg.getInt("channelNumberMinor", 0); String icon = msg.getString("channelIcon", ch.icon); ch.tags = msg.getIntList("tags", ch.tags); if (icon == null) { ch.icon = null; ch.iconBitmap = null; } else if (!icon.equals(ch.icon)) { ch.icon = icon; getChannelIcon(ch); } // Remove programs that have ended long currEventId = msg.getLong("eventId", 0); long nextEventId = msg.getLong("nextEventId", 0); ch.isTransmitting = currEventId != 0; Iterator<Program> it = ch.epg.iterator(); ArrayList<Program> tmp = new ArrayList<Program>(); while (it.hasNext() && currEventId > 0) { Program p = it.next(); if (p.id != currEventId) { tmp.add(p); } else { break; } } ch.epg.removeAll(tmp); for (Program p : tmp) { app.removeProgram(p); } final long eventId = currEventId != 0 ? currEventId : nextEventId; if (eventId > 0 && ch.epg.size() < 2) { execService.schedule(new Runnable() { public void run() { getEvents(ch, eventId, 5); } }, 30, TimeUnit.SECONDS); } else { app.updateChannel(ch); } } private void onChannelDelete(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.removeChannel(msg.getLong("channelId")); } private void onDvrEntryAdd(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Recording rec = new Recording(); rec.id = msg.getLong("id"); rec.eventId = msg.getLong("eventId", 0); rec.autorecId = msg.getString("autorecId", ""); rec.timerecId = msg.getString("timerecId", ""); rec.start = msg.getDate("start"); rec.stop = msg.getDate("stop"); rec.startExtra = msg.getLong("startExtra"); rec.stopExtra = msg.getLong("stopExtra"); rec.retention = msg.getLong("retention"); rec.priority = msg.getLong("priority"); rec.contentType = msg.getLong("contentType"); rec.title = msg.getString("title", ""); rec.description = msg.getString("description", ""); rec.owner = msg.getString("owner", ""); rec.creator = msg.getString("creator", ""); rec.path = msg.getString("path", ""); rec.state = msg.getString("state", ""); rec.error = msg.getString("error", null); rec.channel = app.getChannel(msg.getLong("channel", 0)); if (rec.channel != null) { rec.channel.recordings.add(rec); } app.addRecording(rec); } private void onDvrEntryUpdate(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Recording rec = app.getRecording(msg.getLong("id")); if (rec == null) { return; } // Get the current recording state to check if a notification shall be shown String currentRecState = rec.state; rec.eventId = msg.getLong("eventId", rec.eventId); rec.autorecId = msg.getString("autorecId", rec.autorecId); rec.timerecId = msg.getString("timerecId", rec.timerecId); rec.start = msg.getDate("start"); rec.stop = msg.getDate("stop"); rec.startExtra = msg.getLong("startExtra"); rec.stopExtra = msg.getLong("stopExtra"); rec.retention = msg.getLong("retention"); rec.priority = msg.getLong("priority"); rec.contentType = msg.getLong("contentType"); rec.title = msg.getString("title", rec.title); rec.description = msg.getString("description", rec.description); rec.owner = msg.getString("owner", rec.owner); rec.creator = msg.getString("creator", rec.creator); rec.path = msg.getString("path", rec.path); rec.state = msg.getString("state", rec.state); rec.error = msg.getString("error", rec.error); app.updateRecording(rec); // Check that the notification shall be shown boolean showNotification = app.isUnlocked() && prefs.getBoolean("showNotificationsPref", false); // Show a notification if enabled that the recording has either started or completed if (showNotification && notificationManager != null && currentRecState != rec.state) { NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setSmallIcon(R.drawable.notification_icon); if (rec.state.equals("recording")) { builder.setContentTitle(getString(R.string.recording_started)); builder.setContentText(getString(R.string.recording_started_text, rec.title)); notificationManager.notify(1, builder.build()); } else if (rec.state.equals("completed")) { builder.setContentTitle(getString(R.string.recording_completed)); builder.setContentText(getString(R.string.recording_completed_text, rec.title)); notificationManager.notify(1, builder.build()); } } } private void onDvrEntryDelete(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Recording rec = app.getRecording(msg.getLong("id")); if (rec == null || rec.channel == null) { return; } rec.channel.recordings.remove(rec); for (Program p : rec.channel.epg) { if (p.recording == rec) { p.recording = null; app.updateProgram(p); break; } } app.removeRecording(rec); } private void onTimerRecEntryAdd(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); TimerRecording rec = new TimerRecording(); rec.id = msg.getString("id", ""); rec.enabled = (msg.getLong("enabled", 0) == 0) ? false : true; rec.daysOfWeek = msg.getLong("daysOfWeek", 0); rec.retention = msg.getLong("retention", 0); rec.priority = msg.getLong("priority", 0); rec.start = msg.getLong("start"); rec.stop = msg.getLong("stop"); rec.title = msg.getString("title", ""); rec.name = msg.getString("name", ""); rec.directory = msg.getString("directory", ""); rec.owner = msg.getString("owner", ""); rec.creator = msg.getString("creator", ""); rec.channel = app.getChannel(msg.getLong("channel", 0)); app.addTimerRecording(rec); } private void onTimerRecEntryUpdate(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); TimerRecording rec = app.getTimerRecording(msg.getString("id")); if (rec == null) { return; } rec.enabled = (msg.getLong("enabled", 0) == 0) ? false : true; rec.daysOfWeek = msg.getLong("daysOfWeek", rec.daysOfWeek); rec.retention = msg.getLong("retention", rec.retention); rec.priority = msg.getLong("priority", rec.priority); rec.start = msg.getLong("start", rec.start); rec.stop = msg.getLong("stop", rec.stop); rec.title = msg.getString("title", rec.title); rec.name = msg.getString("name", rec.name); rec.directory = msg.getString("directory", rec.directory); rec.owner = msg.getString("owner", rec.owner); rec.creator = msg.getString("creator", rec.creator); rec.channel = app.getChannel(msg.getLong("channel", 0)); app.updateTimerRecording(rec); } private void onTimerRecEntryDelete(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); TimerRecording rec = app.getTimerRecording(msg.getString("id")); if (rec == null || rec.channel == null) { return; } rec.channel = null; app.removeTimerRecording(rec); } private void onInitialSyncCompleted(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.setLoading(false); app.setConnectionState(Constants.ACTION_CONNECTION_STATE_OK); app.setProtocolVersion(connection.getProtocolVersion()); } private void onSubscriptionStart(HTSMessage msg) { Log.d(TAG, "onSubscriptionStart"); TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription subscription = app.getSubscription(msg.getLong("subscriptionId")); if (subscription == null) { return; } for (Object obj : msg.getList("streams")) { Stream s = new Stream(); HTSMessage sub = (HTSMessage) obj; s.index = sub.getInt("index"); s.type = sub.getString("type"); s.language = sub.getString("language", ""); s.width = sub.getInt("width", 0); s.height = sub.getInt("height", 0); s.duration = sub.getInt("duration", 0); s.aspectNum = sub.getInt("aspect_num", 0); s.aspectDen = sub.getInt("aspect_den", 0); s.autioType = sub.getInt("autio_type", 0); s.channels = sub.getInt("channels", 0); s.rate = sub.getInt("rate", 0); subscription.streams.add(s); Log.d(TAG, "onSubscriptionStart, added stream " + s.index); } if (msg.containsField("sourceinfo")) { Object obj = msg.get("sourceinfo"); HTSMessage sub = (HTSMessage) obj; SourceInfo si = new SourceInfo(); si.adapter = sub.getString("adapter", ""); si.mux = sub.getString("mux", ""); si.network = sub.getString("network", ""); si.provider = sub.getString("provider", ""); si.service = sub.getString("service", ""); subscription.sourceInfo = si; Log.d(TAG, "onSubscriptionStart, added sourceinfo " + si.adapter); } } private void onSubscriptionStatus(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription s = app.getSubscription(msg.getLong("subscriptionId")); if (s == null) { return; } String status = msg.getString("status", ""); if (s.status == null ? status != null : !s.status.equals(status)) { s.status = status; app.updateSubscription(s); } } private void onSubscriptionStop(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription s = app.getSubscription(msg.getLong("subscriptionId")); if (s == null) { return; } String status = msg.getString("status", ""); if (s.status == null ? status != null : !s.status.equals(status)) { s.status = status; app.updateSubscription(s); } app.removeSubscription(s); } private void onSubscriptionGrace(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription s = app.getSubscription(msg.getLong("subscriptionId")); if (s == null) { return; } long gt = msg.getLong("graceTimeout", 0); if (s.graceTimeout != gt) { s.graceTimeout = gt; app.updateSubscription(s); } } private void onSubscriptionSignalStatus(HTSMessage msg) { Log.d(TAG, "onSubscriptionSignalStatus"); TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription s = app.getSubscription(msg.getLong("subscriptionId")); if (s == null) { return; } s.feStatus = msg.getString("feStatus"); s.feSNR = msg.getInt("feSNR", 0); s.feSignal = msg.getInt("feSignal", 0); s.feBER = msg.getInt("feBER", 0); s.feUNC = msg.getInt("feUNC", 0); } private void onMuxPacket(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription sub = app.getSubscription(msg.getLong("subscriptionId")); if (sub == null) { return; } Packet packet = new Packet(); packet.dts = msg.getLong("dts", 0); packet.pts = msg.getLong("pts", 0); packet.duration = msg.getLong("duration"); packet.frametype = msg.getInt("frametype"); packet.payload = msg.getByteArray("payload"); for (Stream st : sub.streams) { if (st.index == msg.getInt("stream")) { packet.stream = st; } } packet.subscription = sub; app.broadcastPacket(packet); } private void onQueueStatus(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); Subscription sub = app.getSubscription(msg.getLong("subscriptionId")); if (sub == null) { return; } if (msg.containsField("delay")) { BigInteger delay = msg.getBigInteger("delay"); delay = delay.divide(BigInteger.valueOf((1000))); sub.delay = delay.longValue(); } sub.droppedBFrames = msg.getLong("Bdrops", sub.droppedBFrames); sub.droppedIFrames = msg.getLong("Idrops", sub.droppedIFrames); sub.droppedPFrames = msg.getLong("Pdrops", sub.droppedPFrames); sub.packetCount = msg.getLong("packets", sub.packetCount); sub.queSize = msg.getLong("bytes", sub.queSize); app.updateSubscription(sub); } private void onAutorecEntryDelete(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); String id = msg.getString("id"); if (id == null) { return; } // Remove the series recording from the list and also update all // recordings by removing the series id app.removeSeriesRecording(id); for (Recording rec : app.getRecordings()) { if (rec.autorecId != null && rec.autorecId.equals(id)) { rec.autorecId = null; } } } private void onAutorecEntryUpdate(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); SeriesRecording rec = app.getSeriesRecording(msg.getString("id")); if (rec == null) { return; } rec.enabled = (msg.getLong("enabled", 0) == 0) ? false : true; rec.maxDuration = msg.getLong("maxDuration"); rec.minDuration = msg.getLong("minDuration"); rec.retention = msg.getLong("retention"); rec.daysOfWeek = msg.getLong("daysOfWeek"); rec.approxTime = msg.getLong("approxTime"); rec.start = msg.getLong("start"); rec.startWindow = msg.getLong("startWindow"); rec.priority = msg.getLong("priority"); rec.startExtra = msg.getLong("startExtra"); rec.stopExtra = msg.getLong("stopExtra"); rec.title = msg.getString("title", rec.title); rec.name = msg.getString("name", rec.name); rec.directory = msg.getString("directory", rec.directory); rec.owner = msg.getString("owner", rec.owner); rec.creator = msg.getString("creator", rec.creator); app.updateSeriesRecording(rec); } private void onAutorecEntryAdd(HTSMessage msg) { TVHClientApplication app = (TVHClientApplication) getApplication(); SeriesRecording rec = new SeriesRecording(); rec.id = msg.getString("id"); rec.enabled = (msg.getLong("enabled", 0) == 0) ? false : true; rec.maxDuration = msg.getLong("maxDuration"); rec.minDuration = msg.getLong("minDuration"); rec.retention = msg.getLong("retention"); rec.daysOfWeek = msg.getLong("daysOfWeek"); rec.approxTime = msg.getLong("approxTime"); rec.start = msg.getLong("start"); rec.startWindow = msg.getLong("startWindow"); rec.priority = msg.getLong("priority"); rec.startExtra = msg.getLong("startExtra"); rec.stopExtra = msg.getLong("stopExtra"); rec.title = msg.getString("title", ""); rec.name = msg.getString("name", ""); rec.directory = msg.getString("directory", ""); rec.owner = msg.getString("owner", ""); rec.creator = msg.getString("creator", ""); rec.channel = app.getChannel(msg.getLong("channel", 0)); app.addSeriesRecording(rec); } public void onMessage(HTSMessage msg) { String method = msg.getMethod(); if (method.equals("tagAdd")) { onTagAdd(msg); } else if (method.equals("tagUpdate")) { onTagUpdate(msg); } else if (method.equals("tagDelete")) { onTagDelete(msg); } else if (method.equals("channelAdd")) { onChannelAdd(msg); } else if (method.equals("channelUpdate")) { onChannelUpdate(msg); } else if (method.equals("channelDelete")) { onChannelDelete(msg); } else if (method.equals("initialSyncCompleted")) { onInitialSyncCompleted(msg); } else if (method.equals("dvrEntryAdd")) { onDvrEntryAdd(msg); } else if (method.equals("dvrEntryUpdate")) { onDvrEntryUpdate(msg); } else if (method.equals("dvrEntryDelete")) { onDvrEntryDelete(msg); } else if (method.equals("timerecEntryAdd")) { onTimerRecEntryAdd(msg); } else if (method.equals("timerecEntryUpdate")) { onTimerRecEntryUpdate(msg); } else if (method.equals("timerecEntryDelete")) { onTimerRecEntryDelete(msg); } else if (method.equals("subscriptionStart")) { onSubscriptionStart(msg); } else if (method.equals("subscriptionStatus")) { onSubscriptionStatus(msg); } else if (method.equals("subscriptionStop")) { onSubscriptionStop(msg); } else if (method.equals("subscriptionGrace")) { onSubscriptionGrace(msg); } else if (method.equals("muxpkt")) { onMuxPacket(msg); } else if (method.equals("queueStatus")) { onQueueStatus(msg); } else if (method.equals("autorecEntryAdd")) { onAutorecEntryAdd(msg); } else if (method.equals("autorecEntryUpdate")) { onAutorecEntryUpdate(msg); } else if (method.equals("autorecEntryDelete")) { onAutorecEntryDelete(msg); } else if (method.equals("signalStatus")) { onSubscriptionSignalStatus(msg); } else { Log.d(TAG, method.toString()); } } public String hashString(String s) { try { MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); digest.update(s.getBytes()); byte messageDigest[] = digest.digest(); StringBuilder hexString = new StringBuilder(); for (int i = 0; i < messageDigest.length; i++) { hexString.append(Integer.toHexString(0xFF & messageDigest[i])); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { Log.e(TAG, "Can't create hash string", e); } return ""; } public void cacheImage(String url, File f) throws MalformedURLException, IOException { InputStream is; if (url.startsWith("http")) { is = new BufferedInputStream(new URL(url).openStream()); } else if (connection.getProtocolVersion() > 9) { is = new HTSFileInputStream(connection, url); } else { Log.d(TAG, "Unhandled url: " + url); return; } OutputStream os = new FileOutputStream(f); float scale = getResources().getDisplayMetrics().density; int width = (int) (64 * scale); int height = (int) (64 * scale); // Set the options for a bitmap and decode an input stream into a bitmap BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(is, null, o); is.close(); if (url.startsWith("http")) { is = new BufferedInputStream(new URL(url).openStream()); } else if (connection.getProtocolVersion() > 9) { is = new HTSFileInputStream(connection, url); } // Set the sample size of the image. This is the number of pixels in // either dimension that correspond to a single pixel in the decoded // bitmap. For example, inSampleSize == 4 returns an image that is 1/4 // the width/height of the original, and 1/16 the number of pixels. int ratio = Math.max(o.outWidth / width, o.outHeight / height); int sampleSize = Integer.highestOneBit((int) Math.floor(ratio)); o = new BitmapFactory.Options(); o.inSampleSize = sampleSize; // Now decode an input stream into a bitmap and compress it. Bitmap bitmap = BitmapFactory.decodeStream(is, null, o); if (bitmap != null) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); } os.close(); is.close(); } private Bitmap getIcon(final String url) throws MalformedURLException, IOException { // When no channel icon shall be shown return null instead of the icon. // The icon will not be shown anyway, so returning null will drastically // reduce memory consumption. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); Boolean showIcons = prefs.getBoolean("showIconPref", true); if (!showIcons) { return null; } if (url == null || url.length() == 0) { return null; } File dir = getCacheDir(); File f = new File(dir, hashString(url) + ".png"); if (!f.exists()) { cacheImage(url, f); } return BitmapFactory.decodeFile(f.toString()); } private void getChannelIcon(final Channel ch) { execService.execute(new Runnable() { @Override public void run() { try { ch.iconBitmap = getIcon(ch.icon); TVHClientApplication app = (TVHClientApplication) getApplication(); app.updateChannel(ch); } catch (Throwable ex) { // Log.e(TAG, "Can't load channel icon", ex); } } }); } private void getChannelTagIcon(final ChannelTag tag) { execService.execute(new Runnable() { public void run() { try { tag.iconBitmap = getIcon(tag.icon); TVHClientApplication app = (TVHClientApplication) getApplication(); app.updateChannelTag(tag); } catch (Throwable ex) { // Log.e(TAG, "Can't load tag icon", ex); } } }); } private void getEvents(final Channel ch, final long eventId, int cnt) { if (ch == null) { return; } HTSMessage request = new HTSMessage(); request.setMethod("getEvents"); request.putField("eventId", eventId); request.putField("numFollowing", cnt); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (!response.containsKey("events")) { return; } TVHClientApplication app = (TVHClientApplication) getApplication(); for (Object obj : response.getList("events")) { Program p = new Program(); HTSMessage sub = (HTSMessage) obj; p.id = sub.getLong("eventId", 0); p.nextId = sub.getLong("nextEventId", 0); p.description = sub.getString("description", ""); p.summary = sub.getString("summary", ""); p.recording = app.getRecording(sub.getLong("dvrId", 0)); p.contentType = sub.getInt("contentType", 0); p.title = sub.getString("title"); p.start = sub.getDate("start"); p.stop = sub.getDate("stop"); p.seriesInfo = buildSeriesInfo(sub); p.starRating = sub.getInt("starRating", -1); p.channel = ch; if (ch.epg.add(p)) { app.addProgram(p); } } app.updateChannel(ch); } }); } private void getEvent(long eventId) { HTSMessage request = new HTSMessage(); request.setMethod("getEvent"); request.putField("eventId", eventId); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { TVHClientApplication app = (TVHClientApplication) getApplication(); Channel ch = app.getChannel(response.getLong("channelId")); Program p = new Program(); p.id = response.getLong("eventId"); p.nextId = response.getLong("nextEventId", 0); p.description = response.getString("description", ""); p.summary = response.getString("summary", ""); p.recording = app.getRecording(response.getLong("dvrId", 0)); p.contentType = response.getInt("contentType", 0); p.title = response.getString("title"); p.start = response.getDate("start"); p.stop = response.getDate("stop"); p.seriesInfo = buildSeriesInfo(response); p.starRating = response.getInt("starRating", -1); p.channel = ch; if (ch.epg.add(p)) { app.addProgram(p); app.updateChannel(ch); } } }); } private SeriesInfo buildSeriesInfo(HTSMessage msg) { SeriesInfo info = new SeriesInfo(); info.episodeCount = msg.getInt("episodeCount", 0); info.episodeNumber = msg.getInt("episodeNumber", 0); info.onScreen = msg.getString("episodeOnscreen", ""); info.partCount = msg.getInt("partCount", 0); info.partNumber = msg.getInt("partNumber", 0); info.seasonCount = msg.getInt("seasonCount", 0); info.seasonNumber = msg.getInt("seasonNumber", 0); return info; } private void epgQuery(final Channel ch, String query, long tagId) { HTSMessage request = new HTSMessage(); request.setMethod("epgQuery"); request.putField("query", query); // The default values will be set in case a server with a htsp API // version 12 or lower is used request.putField("minduration", 0); request.putField("maxduration", Integer.MAX_VALUE); if (ch != null) { request.putField("channelId", ch.id); } if (tagId > 0) { request.putField("tagId", tagId); } connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (!response.containsKey("eventIds")) { return; } for (Long id : response.getLongList("eventIds")) { getEvent(id); } } }); } private void cancelDvrEntry(long id) { HTSMessage request = new HTSMessage(); request.setMethod("cancelDvrEntry"); request.putField("id", id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; } }); } private void deleteDvrEntry(long id) { HTSMessage request = new HTSMessage(); request.setMethod("deleteDvrEntry"); request.putField("id", id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; } }); } private void addDvrEntry(final Channel ch, final long eventId) { HTSMessage request = new HTSMessage(); request.setMethod("addDvrEntry"); request.putField("eventId", eventId); request.putField("retention", 0); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (response.getInt("success", 0) == 1) { for (Program p : ch.epg) { if (p.id == eventId) { TVHClientApplication app = (TVHClientApplication) getApplication(); p.recording = app.getRecording(response.getLong("id", 0)); app.updateProgram(p); break; } } } @SuppressWarnings("unused") String error = response.getString("error", ""); } }); } private void deleteTimerRecEntry(String id) { HTSMessage request = new HTSMessage(); request.setMethod("deleteTimerecEntry"); request.putField("id", id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; } }); } /** * * @param title * @param start * @param stop * @param channelId * @param configName * @param retention * @param daysOfWeek * @param priority * @param enabled * @param name * @param directory */ private void addTimerRecEntry(String title, long start, long stop, long channelId, String configName, long retention, long daysOfWeek, long priority, long enabled, String name, String directory) { HTSMessage request = new HTSMessage(); request.setMethod("addTimerecEntry"); request.putField("title", title); request.putField("start", start); request.putField("stop", stop); request.putField("channelId", channelId); request.putField("configName", configName); request.putField("retention", retention); request.putField("daysOfWeek", daysOfWeek); request.putField("priority", priority); request.putField("enabled", enabled); request.putField("name", name); request.putField("directory", directory); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; @SuppressWarnings("unused") String error = response.getString("error", ""); } }); } private void subscribe(long channelId, long subscriptionId, int maxWidth, int maxHeight, String aCodec, String vCodec) { Subscription subscription = new Subscription(); subscription.id = subscriptionId; subscription.status = "Subscribing"; TVHClientApplication app = (TVHClientApplication) getApplication(); app.addSubscription(subscription); HTSMessage request = new HTSMessage(); request.setMethod("subscribe"); request.putField("channelId", channelId); request.putField("maxWidth", maxWidth); request.putField("maxHeight", maxHeight); request.putField("audioCodec", aCodec); request.putField("videoCodec", vCodec); request.putField("subscriptionId", subscriptionId); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { //NOP } }); } private void unsubscribe(long subscriptionId) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.removeSubscription(subscriptionId); HTSMessage request = new HTSMessage(); request.setMethod("unsubscribe"); request.putField("subscriptionId", subscriptionId); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { //NOP } }); } private void feedback(long subscriptionId, int speed) { HTSMessage request = new HTSMessage(); request.setMethod("feedback"); request.putField("subscriptionId", subscriptionId); request.putField("speed", speed); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { //NOP } }); } private void getTicket(Channel ch) { HTSMessage request = new HTSMessage(); request.setMethod("getTicket"); request.putField("channelId", ch.id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { String path = response.getString("path", ""); String ticket = response.getString("ticket", ""); String webroot = connection.getWebRoot(); if (path != null && ticket != null) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.addTicket(new HttpTicket(webroot + path, ticket)); } } }); } private void getTicket(Recording rec) { HTSMessage request = new HTSMessage(); request.setMethod("getTicket"); request.putField("dvrId", rec.id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { String path = response.getString("path", ""); String ticket = response.getString("ticket", ""); if (path != null && ticket != null) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.addTicket(new HttpTicket(path, ticket)); } } }); } private void getDiscSpace() { HTSMessage request = new HTSMessage(); request.setMethod("getDiskSpace"); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.updateStatus("freediskspace", response.getString("freediskspace", "")); app.updateStatus("totaldiskspace", response.getString("totaldiskspace", "")); } }); } private void getSystemTime() { HTSMessage request = new HTSMessage(); request.setMethod("getSysTime"); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { TVHClientApplication app = (TVHClientApplication) getApplication(); app.updateStatus("time", response.getString("time", "")); app.updateStatus("timezone", response.getString("timezone", "")); } }); } private void getDvrConfigs() { HTSMessage request = new HTSMessage(); request.setMethod("getDvrConfigs"); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (!response.containsKey("dvrconfigs")) { return; } List<Profiles> pList = new ArrayList<Profiles>(); TVHClientApplication app = (TVHClientApplication) getApplication(); for (Object obj : response.getList("dvrconfigs")) { HTSMessage sub = (HTSMessage) obj; Profiles p = new Profiles(); p.uuid = sub.getString("uuid"); p.name = sub.getString("name"); if (p.name.length() == 0) { p.name = Constants.REC_PROFILE_DEFAULT; } p.comment = sub.getString("comment"); pList.add(p); } app.addDvrConfigs(pList); } }); } private void deleteAutorecEntry(final String id) { HTSMessage request = new HTSMessage(); request.setMethod("deleteAutorecEntry"); request.putField("id", id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; } }); } /** * * @param title * @param channelId * @param configName * @param maxDuration * @param minDuration * @param retention * @param daysOfWeek * @param priority * @param enabled * @param startExtra * @param stopExtra * @param name * @param directory */ private void addAutorecEntry(String title, long channelId, String configName, long maxDuration, long minDuration, long retention, long daysOfWeek, long priority, long enabled, long startExtra, long stopExtra, String name, String directory) { HTSMessage request = new HTSMessage(); request.setMethod("addAutorecEntry"); request.putField("title", title); request.putField("configName", configName); request.putField("channelId", channelId); request.putField("minDuration", minDuration); request.putField("maxDuration", maxDuration); request.putField("retention", retention); request.putField("daysOfWeek", daysOfWeek); request.putField("priority", priority); request.putField("enabled", enabled); request.putField("startExtra", startExtra); request.putField("stopExtra", stopExtra); request.putField("name", name); request.putField("directory", directory); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { @SuppressWarnings("unused") boolean success = response.getInt("success", 0) == 1; } }); } private void getDvrCutpoints(final Recording rec) { Log.d(TAG, "getDvrCutpoints, rec " + rec.title); HTSMessage request = new HTSMessage(); request.setMethod("getDvrCutpoints"); request.putField("id", rec.id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (!response.containsKey("cutpoints")) { return; } // Clear all saved cut points before adding new ones. rec.dvrCutPoints.clear(); for (Object obj : response.getList("cutpoints")) { DvrCutpoint dc = new DvrCutpoint(); HTSMessage sub = (HTSMessage) obj; dc.start = sub.getInt("start"); dc.end = sub.getInt("end"); dc.type = sub.getInt("type"); rec.dvrCutPoints.add(dc); Log.d(TAG, "getDvrCutpoints, added cut point for rec " + rec.title); } } }); } private void subscriptionFilterStream() { // TODO Auto-generated method stub } private void getChannel(final Channel ch) { HTSMessage request = new HTSMessage(); request.setMethod("getChannel"); request.putField("channelId", ch.id); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { // TODO } }); } private void getProfiles() { HTSMessage request = new HTSMessage(); request.setMethod("getProfiles"); connection.sendMessage(request, new HTSResponseHandler() { public void handleResponse(HTSMessage response) { if (!response.containsKey("profiles")) { return; } List<Profiles> pList = new ArrayList<Profiles>(); TVHClientApplication app = (TVHClientApplication) getApplication(); for (Object obj : response.getList("profiles")) { HTSMessage sub = (HTSMessage) obj; Profiles p = new Profiles(); p.uuid = sub.getString("uuid"); p.name = sub.getString("name"); p.comment = sub.getString("comment"); pList.add(p); } app.addProfiles(pList); } }); } }