• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.common;
18 
19 import android.media.tv.TvContentRating;
20 import android.support.annotation.Nullable;
21 import android.support.annotation.VisibleForTesting;
22 import android.text.TextUtils;
23 import android.util.ArrayMap;
24 import android.util.Log;
25 
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.SortedSet;
32 import java.util.TreeSet;
33 
34 /**
35  * TvContentRating cache.
36  */
37 public final class TvContentRatingCache implements MemoryManageable {
38     private final static String TAG = "TvContentRatings";
39 
40     private final static TvContentRatingCache INSTANCE = new TvContentRatingCache();
41 
getInstance()42     public static TvContentRatingCache getInstance() {
43         return INSTANCE;
44     }
45 
46     // @GuardedBy("TvContentRatingCache.this")
47     private final Map<String, TvContentRating[]> mRatingsMultiMap = new ArrayMap<>();
48 
49     /**
50      * Returns an array TvContentRatings from a string of comma separated set of rating strings
51      * creating each from {@link TvContentRating#unflattenFromString(String)} if needed.
52      * Returns {@code null} if the string is empty or contains no valid ratings.
53      */
54     @Nullable
getRatings(String commaSeparatedRatings)55     public synchronized TvContentRating[] getRatings(String commaSeparatedRatings) {
56         if (TextUtils.isEmpty(commaSeparatedRatings)) {
57             return null;
58         }
59         TvContentRating[] tvContentRatings;
60         if (mRatingsMultiMap.containsKey(commaSeparatedRatings)) {
61             tvContentRatings = mRatingsMultiMap.get(commaSeparatedRatings);
62         } else {
63             String normalizedRatings = TextUtils
64                     .join(",", getSortedSetFromCsv(commaSeparatedRatings));
65             if (mRatingsMultiMap.containsKey(normalizedRatings)) {
66                 tvContentRatings = mRatingsMultiMap.get(normalizedRatings);
67             } else {
68                 tvContentRatings = stringToContentRatings(commaSeparatedRatings);
69                 mRatingsMultiMap.put(normalizedRatings, tvContentRatings);
70             }
71             if (!normalizedRatings.equals(commaSeparatedRatings)) {
72                 // Add an entry so the non normalized entry points to the same result;
73                 mRatingsMultiMap.put(commaSeparatedRatings, tvContentRatings);
74             }
75         }
76         return tvContentRatings;
77     }
78 
79     /**
80      * Returns a sorted array of TvContentRatings from a comma separated string of ratings.
81      */
82     @VisibleForTesting
stringToContentRatings(String commaSeparatedRatings)83     static TvContentRating[] stringToContentRatings(String commaSeparatedRatings) {
84         if (TextUtils.isEmpty(commaSeparatedRatings)) {
85             return null;
86         }
87         Set<String> ratingStrings = getSortedSetFromCsv(commaSeparatedRatings);
88         List<TvContentRating> contentRatings = new ArrayList<>();
89         for (String rating : ratingStrings) {
90             try {
91                 contentRatings.add(TvContentRating.unflattenFromString(rating));
92             } catch (IllegalArgumentException e) {
93                 Log.e(TAG, "Can't parse the content rating: '" + rating + "'", e);
94             }
95         }
96         return contentRatings.size() == 0 ?
97                 null : contentRatings.toArray(new TvContentRating[contentRatings.size()]);
98     }
99 
getSortedSetFromCsv(String commaSeparatedRatings)100     private static Set<String> getSortedSetFromCsv(String commaSeparatedRatings) {
101         String[] ratingStrings = commaSeparatedRatings.split("\\s*,\\s*");
102         return toSortedSet(ratingStrings);
103     }
104 
toSortedSet(String[] ratingStrings)105     private static Set<String> toSortedSet(String[] ratingStrings) {
106         if (ratingStrings.length == 0) {
107             return Collections.EMPTY_SET;
108         } else if (ratingStrings.length == 1) {
109             return Collections.singleton(ratingStrings[0]);
110         } else {
111             // Using a TreeSet here is not very efficient, however it is good enough because:
112             //  - the results are cached
113             //  - in testing with multiple TISs, less than 50 entries are created
114             SortedSet<String> set = new TreeSet<>();
115             Collections.addAll(set, ratingStrings);
116             return set;
117         }
118     }
119 
120     /**
121      * Returns a string of each flattened content rating, sorted and concatenated together
122      * with a comma.
123      */
contentRatingsToString(TvContentRating[] contentRatings)124     public static String contentRatingsToString(TvContentRating[] contentRatings) {
125         if (contentRatings == null || contentRatings.length == 0) {
126             return null;
127         }
128         String[] ratingStrings = new String[contentRatings.length];
129         for (int i = 0; i < contentRatings.length; i++) {
130             ratingStrings[i] = contentRatings[i].flattenToString();
131         }
132         if (ratingStrings.length == 1) {
133             return ratingStrings[0];
134         } else {
135             return TextUtils.join(",", toSortedSet(ratingStrings));
136         }
137     }
138 
139     @Override
performTrimMemory(int level)140     public synchronized void performTrimMemory(int level) {
141         mRatingsMultiMap.clear();
142     }
143 
TvContentRatingCache()144     private TvContentRatingCache() {
145     }
146 }
147