1 /* 2 * Copyright 2018 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.pump.db; 18 19 import android.net.Uri; 20 21 import androidx.annotation.AnyThread; 22 import androidx.annotation.NonNull; 23 import androidx.annotation.Nullable; 24 25 import java.util.ArrayList; 26 import java.util.Collections; 27 import java.util.List; 28 29 import static com.android.pump.util.Collections.binarySearch; 30 31 @AnyThread 32 public class Series { 33 private final String mTitle; 34 private final int mYear; 35 36 // TODO(b/123706949) Lock mutable fields to ensure consistent updates 37 private Uri mPosterUri; 38 private String mDescription; 39 private final List<List<Episode>> mSeasons = new ArrayList<>(); 40 private boolean mLoaded; 41 Series(@onNull String title)42 Series(@NonNull String title) { 43 mTitle = title; 44 mYear = Integer.MIN_VALUE; 45 } 46 Series(@onNull String title, int year)47 Series(@NonNull String title, int year) { 48 mTitle = title; 49 if (year <= 0) { 50 throw new IllegalArgumentException(); 51 } 52 mYear = year; 53 } 54 getTitle()55 public @NonNull String getTitle() { 56 return mTitle; 57 } 58 hasYear()59 public boolean hasYear() { 60 return mYear > 0; 61 } 62 getYear()63 public int getYear() { 64 if (!hasYear()) { 65 throw new IllegalStateException(); 66 } 67 return mYear; 68 } 69 getPosterUri()70 public @Nullable Uri getPosterUri() { 71 return mPosterUri; 72 } 73 setPosterUri(@onNull Uri posterUri)74 public boolean setPosterUri(@NonNull Uri posterUri) { 75 if (posterUri.equals(mPosterUri)) { 76 return false; 77 } 78 mPosterUri = posterUri; 79 return true; 80 } 81 getDescription()82 public @Nullable String getDescription() { 83 return mDescription; 84 } 85 setDescription(@onNull String description)86 public boolean setDescription(@NonNull String description) { 87 if (description.equals(mDescription)) { 88 return false; 89 } 90 mDescription = description; 91 return true; 92 } 93 getSeasons()94 public @NonNull List<List<Episode>> getSeasons() { 95 return Collections.unmodifiableList(mSeasons); 96 } 97 addEpisode(@onNull Episode episode)98 boolean addEpisode(@NonNull Episode episode) { 99 int seriesLocation = binarySearch(mSeasons, episode.getSeason(), 100 (season) -> season.get(0).getSeason()); 101 if (seriesLocation >= 0) { 102 List<Episode> series = mSeasons.get(seriesLocation); 103 int episodeLocation = binarySearch(series, episode.getEpisode(), Episode::getEpisode); 104 if (episodeLocation >= 0) { 105 if (episode.equals(series.get(episodeLocation))) { 106 return false; 107 } 108 // TODO(b/127524752) This should kind of be okay (i.e. handle gracefully) 109 throw new IllegalStateException("Two episodes with the same season & episode #"); 110 } else { 111 series.add(~episodeLocation, episode); 112 } 113 } else { 114 List<Episode> series = new ArrayList<>(); 115 series.add(episode); 116 mSeasons.add(~seriesLocation, series); 117 } 118 return true; 119 } 120 isLoaded()121 boolean isLoaded() { 122 return mLoaded; 123 } 124 setLoaded()125 void setLoaded() { 126 mLoaded = true; 127 } 128 129 @Override equals(@ullable Object obj)130 public final boolean equals(@Nullable Object obj) { 131 return obj instanceof Series && mTitle.equals(((Series) obj).mTitle) 132 && mYear == ((Series) obj).mYear; 133 } 134 135 @Override hashCode()136 public final int hashCode() { 137 return mTitle.hashCode() ^ mYear; 138 } 139 } 140