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