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.car.media.common.browse;
18 
19 import android.os.Bundle;
20 import android.support.v4.media.MediaBrowserCompat;
21 
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 
25 import com.android.car.media.common.MediaConstants;
26 import com.android.car.media.common.MediaItemMetadata;
27 
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.function.Predicate;
34 import java.util.stream.Collectors;
35 
36 /**
37  * TODO: rename to MediaBrowserUtils.
38  * Provides utility methods for {@link MediaBrowserCompat}.
39  */
40 public class MediaBrowserViewModelImpl {
41 
MediaBrowserViewModelImpl()42     private MediaBrowserViewModelImpl() {
43     }
44 
45     /**
46      * Filters the items that are valid for the root (tabs) or the current node. Returns null when
47      * the given list is null to preserve its error signal.
48      */
49     @Nullable
filterItems(boolean forRoot, @Nullable List<MediaItemMetadata> items)50     public static List<MediaItemMetadata> filterItems(boolean forRoot,
51             @Nullable List<MediaItemMetadata> items) {
52         if (items == null) return null;
53         Predicate<MediaItemMetadata> predicate = forRoot ? MediaItemMetadata::isBrowsable
54                 : item -> (item.isPlayable() || item.isBrowsable());
55         return items.stream().filter(predicate).collect(Collectors.toList());
56     }
57 
58     /** Returns only the browse-able items from the given list. */
59     @Nullable
selectBrowseableItems( @ullable List<MediaItemMetadata> items)60     public static List<MediaItemMetadata> selectBrowseableItems(
61             @Nullable List<MediaItemMetadata> items) {
62         if (items == null) return null;
63         Predicate<MediaItemMetadata> predicate = MediaItemMetadata::isBrowsable;
64         return items.stream().filter(predicate).collect(Collectors.toList());
65     }
66 
67 
68     @SuppressWarnings("deprecation")
getSupportsSearch(@ullable MediaBrowserCompat mediaBrowserCompat)69     public static boolean getSupportsSearch(@Nullable MediaBrowserCompat mediaBrowserCompat) {
70         if (mediaBrowserCompat == null) {
71             return false;
72         }
73         Bundle extras = mediaBrowserCompat.getExtras();
74         if (extras == null) {
75             return false;
76         }
77         if (extras.containsKey(MediaConstants.MEDIA_SEARCH_SUPPORTED)) {
78             return extras.getBoolean(MediaConstants.MEDIA_SEARCH_SUPPORTED);
79         }
80         if (extras.containsKey(MediaConstants.MEDIA_SEARCH_SUPPORTED_PRERELEASE)) {
81             return extras.getBoolean(MediaConstants.MEDIA_SEARCH_SUPPORTED_PRERELEASE);
82         }
83         return false;
84     }
85 
86     @SuppressWarnings("deprecation")
getRootBrowsableHint(@ullable MediaBrowserCompat mediaBrowserCompat)87     public static int getRootBrowsableHint(@Nullable MediaBrowserCompat mediaBrowserCompat) {
88         if (mediaBrowserCompat == null) {
89             return 0;
90         }
91         Bundle extras = mediaBrowserCompat.getExtras();
92         if (extras == null) {
93             return 0;
94         }
95         if (extras.containsKey(MediaConstants.CONTENT_STYLE_BROWSABLE_HINT)) {
96             return extras.getInt(MediaConstants.CONTENT_STYLE_BROWSABLE_HINT, 0);
97         }
98         if (extras.containsKey(MediaConstants.CONTENT_STYLE_BROWSABLE_HINT_PRERELEASE)) {
99             return extras.getInt(MediaConstants.CONTENT_STYLE_BROWSABLE_HINT_PRERELEASE, 0);
100         }
101         return 0;
102     }
103 
104     @SuppressWarnings("deprecation")
getRootPlayableHint(@ullable MediaBrowserCompat mediaBrowserCompat)105     public static int getRootPlayableHint(@Nullable MediaBrowserCompat mediaBrowserCompat) {
106         if (mediaBrowserCompat == null) {
107             return 0;
108         }
109         Bundle extras = mediaBrowserCompat.getExtras();
110         if (extras == null) {
111             return 0;
112         }
113         if (extras.containsKey(MediaConstants.CONTENT_STYLE_PLAYABLE_HINT)) {
114             return extras.getInt(MediaConstants.CONTENT_STYLE_PLAYABLE_HINT, 0);
115         }
116         if (extras.containsKey(MediaConstants.CONTENT_STYLE_PLAYABLE_HINT_PRERELEASE)) {
117             return extras.getInt(MediaConstants.CONTENT_STYLE_PLAYABLE_HINT_PRERELEASE, 0);
118         }
119         return 0;
120     }
121 
122     /** Returns the elements of oldList that do NOT appear in newList. */
computeRemovedItems( @ullable List<MediaItemMetadata> oldList, @Nullable List<MediaItemMetadata> newList)123     public static @NonNull Collection<MediaItemMetadata> computeRemovedItems(
124             @Nullable List<MediaItemMetadata> oldList, @Nullable List<MediaItemMetadata> newList) {
125         if (oldList == null || oldList.isEmpty()) {
126             // Nothing was removed
127             return Collections.emptyList();
128         }
129 
130         if (newList == null || newList.isEmpty()) {
131             // Everything was removed
132             return new ArrayList<>(oldList);
133         }
134 
135         HashSet<MediaItemMetadata> itemsById = new HashSet<>(oldList);
136         itemsById.removeAll(newList);
137         return itemsById;
138     }
139 }
140