Skip to content

Commit a46fe37

Browse files
committed
Half fix channel sorting on Sony TVs
It's impossible for us to fully fix this, as soon as a new channel is added or updated, it will be added at the end no matter what channel number it is. This only proper fix for this can come from Sony. In the meantime, Sony users must uninstall, reinstall, and resetup the app in order to resort the channels Fixes #92
1 parent 0dcc0e0 commit a46fe37

File tree

1 file changed

+75
-23
lines changed

1 file changed

+75
-23
lines changed

app/src/main/java/ie/macinnes/tvheadend/sync/EpgSyncTask.java

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import java.io.OutputStream;
4040
import java.util.ArrayList;
4141
import java.util.Arrays;
42+
import java.util.Collections;
43+
import java.util.Comparator;
4244
import java.util.HashSet;
4345
import java.util.List;
4446
import java.util.Queue;
@@ -62,6 +64,8 @@ public class EpgSyncTask implements HtspMessage.Listener, Authenticator.Listener
6264
"eventAdd", "eventUpdate", "eventDelete",
6365
"initialSyncCompleted",
6466
}));
67+
private static final boolean IS_BRAVIA = Build.MODEL.contains("BRAVIA");
68+
6569
private static final String CHANNEL_ID_KEY = "channelId";
6670
private static final String CHANNEL_NUMBER_KEY = "channelNumber";
6771
private static final String CHANNEL_NUMBER_MINOR_KEY = "channelNumberMinor";
@@ -118,15 +122,27 @@ public interface Listener {
118122
private final SparseArray<Uri> mChannelUriMap;
119123
private final SparseArray<Uri> mProgramUriMap;
120124

121-
private final SparseArray<ContentProviderOperation> mPendingChannelOps = new SparseArray<>();
122-
private final SparseArray<ContentProviderOperation> mPendingProgramOps = new SparseArray<>();
125+
private final ArrayList<PendingChannelAddUpdate> mPendingChannelOps = new ArrayList<>();
126+
private final ArrayList<PendingEventAddUpdate> mPendingProgramOps = new ArrayList<>();
123127

124128
private final Queue<PendingChannelLogoFetch> mPendingChannelLogoFetches = new ConcurrentLinkedQueue<>();
125129
private final byte[] mImageBytes = new byte[102400];
126130

127131
private Set<Integer> mSeenChannels = new HashSet<>();
128132
private Set<Integer> mSeenPrograms = new HashSet<>();
129133

134+
private final class PendingChannelAddUpdate {
135+
public int channelId;
136+
public int channelNumber;
137+
public ContentProviderOperation operation;
138+
139+
public PendingChannelAddUpdate(int channelId, int channelNumber, ContentProviderOperation operation) {
140+
this.channelId = channelId;
141+
this.channelNumber = channelNumber;
142+
this.operation = operation;
143+
}
144+
}
145+
130146
private final class PendingChannelLogoFetch {
131147
public int channelId;
132148
public Uri logoUri;
@@ -137,6 +153,16 @@ public PendingChannelLogoFetch(int channelId, Uri logoUri) {
137153
}
138154
}
139155

156+
private final class PendingEventAddUpdate {
157+
public int eventId;
158+
public ContentProviderOperation operation;
159+
160+
public PendingEventAddUpdate(int eventId, ContentProviderOperation operation) {
161+
this.eventId = eventId;
162+
this.operation = operation;
163+
}
164+
}
165+
140166
public EpgSyncTask(Context context, @NonNull HtspMessage.Dispatcher dispatcher, boolean quickSync) {
141167
this(context, dispatcher);
142168

@@ -295,27 +321,32 @@ private void handleChannelAddUpdate(@NonNull HtspMessage message) {
295321
// Insert the channel
296322
if (Constants.DEBUG)
297323
Log.v(TAG, "Insert channel " + channelId);
298-
mPendingChannelOps.put(
299-
channelId,
324+
final int channelNumber = message.getInteger(CHANNEL_NUMBER_KEY);
325+
mPendingChannelOps.add(new PendingChannelAddUpdate(
326+
channelId, channelNumber,
300327
ContentProviderOperation.newInsert(TvContract.Channels.CONTENT_URI)
301-
.withValues(values)
302-
.build()
303-
);
328+
.withValues(values)
329+
.build()
330+
));
304331
} else {
305332
// Update the channel
306333
if (Constants.DEBUG)
307334
Log.v(TAG, "Update channel " + channelId);
308-
mPendingChannelOps.put(
309-
channelId,
335+
mPendingChannelOps.add(new PendingChannelAddUpdate(
336+
channelId, -1,
310337
ContentProviderOperation.newUpdate(channelUri)
311338
.withValues(values)
312339
.build()
313-
);
340+
));
314341
}
315342

316-
// Throttle the batch operation not to cause TransactionTooLargeException. If the initial
317-
// sync has already completed, flush for every message.
318-
if (mInitialSyncCompleted || mPendingChannelOps.size() >= 500) {
343+
if (mInitialSyncCompleted) {
344+
flushPendingChannelOps();
345+
} else if (!IS_BRAVIA && mPendingChannelOps.size() >= 100) {
346+
// Throttle the batch operation not to cause TransactionTooLargeException. If the initial
347+
// sync has already completed, flush for every message. Additionally, we have no choice
348+
// on a Sony set but to not flush until we have all the channels, as sony's EPG view
349+
// is buggy.
319350
flushPendingChannelOps();
320351
}
321352

@@ -333,10 +364,31 @@ private void flushPendingChannelOps() {
333364

334365
Log.d(TAG, "Flushing " + mPendingChannelOps.size() + " channel operations");
335366

367+
if (IS_BRAVIA) {
368+
// Sort the Pending Add/Updates by their channel numbers as Sony fails to do this in
369+
// their EPG view.
370+
Collections.sort(mPendingChannelOps, new Comparator<PendingChannelAddUpdate>() {
371+
@Override
372+
public int compare(PendingChannelAddUpdate o1, PendingChannelAddUpdate o2) {
373+
if (o1.channelNumber == -1 || o2.channelNumber == -1) {
374+
// One of the events is a channelUpdate, no need (or ability) to sort it
375+
return 0;
376+
}
377+
if (o1.channelNumber > o2.channelNumber) {
378+
return 1;
379+
} else if (o1.channelNumber == o2.channelNumber) {
380+
return 0;
381+
}
382+
383+
return -1;
384+
}
385+
});
386+
}
387+
336388
// Build out an ArrayList of Operations needed for applyBatch()
337389
ArrayList<ContentProviderOperation> operations = new ArrayList<>(mPendingChannelOps.size());
338-
for (int i = 0; i < mPendingChannelOps.size(); i++) {
339-
operations.add(mPendingChannelOps.valueAt(i));
390+
for (PendingChannelAddUpdate pcau : mPendingChannelOps) {
391+
operations.add(pcau.operation);
340392
}
341393

342394
// Apply the batch of Operations
@@ -360,7 +412,7 @@ private void flushPendingChannelOps() {
360412

361413
// Update the Channel Uri Map based on the results
362414
for (int i = 0; i < mPendingChannelOps.size(); i++) {
363-
final int channelId = mPendingChannelOps.keyAt(i);
415+
final int channelId = mPendingChannelOps.get(i).channelId;
364416
final ContentProviderResult result = results[i];
365417

366418
mChannelUriMap.put(channelId, result.uri);
@@ -546,22 +598,22 @@ private void handleEventAddUpdate(@NonNull HtspMessage message) {
546598
// Insert the event
547599
if (Constants.DEBUG)
548600
Log.v(TAG, "Insert event " + eventId + " on channel " + channelId);
549-
mPendingProgramOps.put(
601+
mPendingProgramOps.add(new PendingEventAddUpdate(
550602
eventId,
551603
ContentProviderOperation.newInsert(TvContract.Programs.CONTENT_URI)
552604
.withValues(values)
553605
.build()
554-
);
606+
));
555607
} else {
556608
// Update the event
557609
if (Constants.DEBUG)
558610
Log.v(TAG, "Update event " + eventId + " on channel " + channelId);
559-
mPendingProgramOps.put(
611+
mPendingProgramOps.add(new PendingEventAddUpdate(
560612
eventId,
561613
ContentProviderOperation.newUpdate(eventUri)
562614
.withValues(values)
563615
.build()
564-
);
616+
));
565617
}
566618

567619
// Throttle the batch operation not to cause TransactionTooLargeException. If the initial
@@ -582,8 +634,8 @@ private void flushPendingEventOps() {
582634

583635
// Build out an ArrayList of Operations needed for applyBatch()
584636
ArrayList<ContentProviderOperation> operations = new ArrayList<>(mPendingProgramOps.size());
585-
for (int i = 0; i < mPendingProgramOps.size(); i++) {
586-
operations.add(mPendingProgramOps.valueAt(i));
637+
for (PendingEventAddUpdate peau : mPendingProgramOps) {
638+
operations.add(peau.operation);
587639
}
588640

589641
// Apply the batch of Operations
@@ -608,7 +660,7 @@ private void flushPendingEventOps() {
608660

609661
// Update the Event Uri Map based on the results
610662
for (int i = 0; i < mPendingProgramOps.size(); i++) {
611-
final int eventId = mPendingProgramOps.keyAt(i);
663+
final int eventId = mPendingProgramOps.get(i).eventId;
612664
final ContentProviderResult result = results[i];
613665

614666
mProgramUriMap.put(eventId, result.uri);

0 commit comments

Comments
 (0)