1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.tv.testing; 18 19 import android.support.annotation.NonNull; 20 import android.support.annotation.Nullable; 21 import android.util.Range; 22 23 import com.android.tv.data.ChannelImpl; 24 import com.android.tv.data.ChannelNumber; 25 import com.android.tv.data.Lineup; 26 import com.android.tv.data.ProgramImpl; 27 import com.android.tv.data.api.Channel; 28 import com.android.tv.data.api.Program; 29 import com.android.tv.data.epg.EpgReader; 30 import com.android.tv.dvr.data.SeriesInfo; 31 import com.android.tv.testing.fakes.FakeClock; 32 33 import com.google.common.base.Function; 34 import com.google.common.base.Predicate; 35 import com.google.common.collect.ImmutableList; 36 import com.google.common.collect.ImmutableMap; 37 import com.google.common.collect.Iterables; 38 import com.google.common.collect.LinkedListMultimap; 39 import com.google.common.collect.ListMultimap; 40 41 import java.util.Collection; 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Map; 45 import java.util.Objects; 46 import java.util.Set; 47 48 /** Fake {@link EpgReader} for testing. */ 49 public final class FakeEpgReader implements EpgReader { 50 public final ListMultimap<String, Lineup> zip2lineups = LinkedListMultimap.create(2); 51 public final ListMultimap<String, Channel> lineup2Channels = LinkedListMultimap.create(2); 52 public final ListMultimap<String, Program> epgChannelId2Programs = LinkedListMultimap.create(2); 53 public final FakeClock fakeClock; 54 FakeEpgReader(FakeClock fakeClock)55 public FakeEpgReader(FakeClock fakeClock) { 56 this.fakeClock = fakeClock; 57 } 58 59 @Override isAvailable()60 public boolean isAvailable() { 61 return true; 62 } 63 64 @Override getEpgTimestamp()65 public long getEpgTimestamp() { 66 return fakeClock.currentTimeMillis(); 67 } 68 69 @Override setRegionCode(String regionCode)70 public void setRegionCode(String regionCode) {} 71 72 @Override getLineups(@onNull String postalCode)73 public List<Lineup> getLineups(@NonNull String postalCode) { 74 return zip2lineups.get(postalCode); 75 } 76 77 @Override getChannelNumbers(@onNull String lineupId)78 public List<String> getChannelNumbers(@NonNull String lineupId) { 79 return null; 80 } 81 82 @Override getChannels(Set<Channel> inputChannels, @NonNull String lineupId)83 public Set<EpgChannel> getChannels(Set<Channel> inputChannels, @NonNull String lineupId) { 84 Set<EpgChannel> result = new HashSet<>(); 85 List<Channel> lineupChannels = lineup2Channels.get(lineupId); 86 for (Channel channel : lineupChannels) { 87 Channel match = 88 Iterables.find( 89 inputChannels, 90 new Predicate<Channel>() { 91 @Override 92 public boolean apply(@Nullable Channel inputChannel) { 93 return ChannelNumber.equivalent( 94 inputChannel.getDisplayNumber(), 95 channel.getDisplayNumber()); 96 } 97 }, 98 null); 99 if (match != null) { 100 ChannelImpl updatedChannel = new ChannelImpl.Builder(match).build(); 101 updatedChannel.setLogoUri(channel.getLogoUri()); 102 boolean dbUpdateNeeded = false; 103 if (!Objects.equals( 104 channel.getNetworkAffiliation(), updatedChannel.getNetworkAffiliation())) { 105 dbUpdateNeeded = true; 106 updatedChannel.setNetworkAffiliation(channel.getNetworkAffiliation()); 107 } 108 result.add( 109 EpgChannel.createEpgChannel( 110 updatedChannel, channel.getDisplayNumber(), dbUpdateNeeded)); 111 } 112 } 113 return result; 114 } 115 116 @Override preloadChannels(@onNull String lineupId)117 public void preloadChannels(@NonNull String lineupId) {} 118 119 @Override clearCachedChannels(@onNull String lineupId)120 public void clearCachedChannels(@NonNull String lineupId) {} 121 122 @Override getPrograms(EpgChannel epgChannel)123 public List<Program> getPrograms(EpgChannel epgChannel) { 124 return ImmutableList.copyOf( 125 Iterables.transform( 126 epgChannelId2Programs.get(epgChannel.getEpgChannelId()), 127 updateWith(epgChannel))); 128 } 129 130 @Override getPrograms( @onNull Set<EpgChannel> epgChannels, long duration)131 public Map<EpgChannel, Collection<Program>> getPrograms( 132 @NonNull Set<EpgChannel> epgChannels, long duration) { 133 Range<Long> validRange = 134 Range.create( 135 fakeClock.currentTimeMillis(), fakeClock.currentTimeMillis() + duration); 136 ImmutableMap.Builder<EpgChannel, Collection<Program>> mapBuilder = ImmutableMap.builder(); 137 for (EpgChannel epgChannel : epgChannels) { 138 Iterable<Program> programs = getPrograms(epgChannel); 139 140 mapBuilder.put( 141 epgChannel, 142 ImmutableList.copyOf(Iterables.filter(programs, isProgramDuring(validRange)))); 143 } 144 return mapBuilder.build(); 145 } 146 updateWith(final EpgChannel channel)147 protected Function<Program, Program> updateWith(final EpgChannel channel) { 148 return new Function<Program, Program>() { 149 @Nullable 150 @Override 151 public Program apply(@Nullable Program program) { 152 return new ProgramImpl.Builder(program) 153 .setChannelId(channel.getChannel().getId()) 154 .setPackageName(channel.getChannel().getPackageName()) 155 .build(); 156 } 157 }; 158 } 159 160 /** 161 * True if the start time or the end time is {@link Range#contains contained (inclusive)} in the 162 * range 163 */ 164 protected Predicate<Program> isProgramDuring(final Range<Long> validRange) { 165 return new Predicate<Program>() { 166 @Override 167 public boolean apply(@Nullable Program program) { 168 return validRange.contains(program.getStartTimeUtcMillis()) 169 || validRange.contains(program.getEndTimeUtcMillis()); 170 } 171 }; 172 } 173 174 @Override 175 public SeriesInfo getSeriesInfo(@NonNull String seriesId) { 176 return null; 177 } 178 } 179