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.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.UiThread;
22 import android.support.v4.media.MediaBrowserCompat;
23 
24 import androidx.lifecycle.LiveData;
25 import androidx.lifecycle.ViewModelProvider;
26 
27 import com.android.car.arch.common.FutureData;
28 import com.android.car.media.common.MediaItemMetadata;
29 import com.android.car.media.common.source.MediaSourceViewModel;
30 
31 import java.util.List;
32 
33 /**
34  * Contains observable data needed for displaying playback and browse UI. Instances can be obtained
35  * via {@link MediaBrowserViewModel.Factory}
36  */
37 public interface MediaBrowserViewModel {
38 
39     /**
40      * Possible states of the application UI
41      */
42     enum BrowseState {
43         /** There is no content to show */
44         EMPTY,
45         /** We are still in the process of obtaining data */
46         LOADING,
47         /** Data has been loaded */
48         LOADED,
49         /** The content can't be shown due an error */
50         ERROR
51     }
52 
53     /**
54      * Returns a LiveData that emits the current package name of the browser's service component.
55      */
getPackageName()56     LiveData<String> getPackageName();
57 
58     /**
59      * Returns a LiveData that emits the current {@link BrowseState}
60      */
getBrowseState()61     LiveData<BrowseState> getBrowseState();
62 
63 
64     /**
65      * Fetches the MediaItemMetadatas for the current browsed id, and the loading status of the
66      * fetch operation.
67      *
68      * This LiveData will never emit {@code null}. If the data is loading, the data component of the
69      * {@link FutureData} will be null
70      * A MediaSource must be selected and its MediaBrowser connected, otherwise the FutureData will
71      * always contain a {@code null} data value.
72      *
73      * @return a LiveData that emits a FutureData that contains the loading status and the
74      * MediaItemMetadatas for the current browsed id
75      */
getBrowsedMediaItems()76     LiveData<FutureData<List<MediaItemMetadata>>> getBrowsedMediaItems();
77 
78     /**
79      * Fetches the MediaItemMetadatas for the current search query, and the loading status of the
80      * fetch operation.
81      *
82      * See {@link #getBrowsedMediaItems()}
83      */
getSearchedMediaItems()84     LiveData<FutureData<List<MediaItemMetadata>>> getSearchedMediaItems();
85 
86 
87     /**
88      * Returns a LiveData that emits whether the media browser supports search. This wil never emit
89      * {@code null}
90      */
supportsSearch()91     LiveData<Boolean> supportsSearch();
92 
93     /**
94      * Gets the content style display type of browsable elements in this media browser, set at the
95      * browse root
96      */
rootBrowsableHint()97     LiveData<Integer> rootBrowsableHint();
98 
99     /**
100      * Gets the content style display type of playable elements in this media browser, set at the
101      * browse root
102      */
rootPlayableHint()103     LiveData<Integer> rootPlayableHint();
104 
105     /**
106      * A {@link MediaBrowserViewModel} whose selected browse ID may be changed.
107      */
108     interface WithMutableBrowseId extends MediaBrowserViewModel {
109 
110         /**
111          * Set the current item to be browsed. If available, the list of items will be emitted by
112          * {@link #getBrowsedMediaItems()}.
113          */
114         @UiThread
setCurrentBrowseId(@onNull String browseId)115         void setCurrentBrowseId(@NonNull String browseId);
116 
117         /**
118          * Set the current item to be searched for. If available, the list of items will be emitted
119          * by {@link #getBrowsedMediaItems()}.
120          */
121         @UiThread
search(@ullable String query)122         void search(@Nullable String query);
123     }
124 
125     /**
126      * Creates and/or fetches {@link MediaBrowserViewModel} instances.
127      */
128     class Factory {
129 
130         private static final String KEY_BROWSER_ROOT =
131                 "com.android.car.media.common.browse.MediaBrowserViewModel.Factory.browserRoot";
132 
133         /**
134          * Returns an initialized {@link MediaBrowserViewModel.WithMutableBrowseId} with the
135          * provided connected media browser. The provided {@code mediaBrowser} does not need to be
136          * from the same scope as {@code viewModelProvider}.
137          */
138         @NonNull
getInstanceWithMediaBrowser( @onNull String key, @NonNull ViewModelProvider viewModelProvider, @NonNull LiveData<MediaBrowserCompat> mediaBrowser)139         public static MediaBrowserViewModel.WithMutableBrowseId getInstanceWithMediaBrowser(
140                 @NonNull String key,
141                 @NonNull ViewModelProvider viewModelProvider,
142                 @NonNull LiveData<MediaBrowserCompat> mediaBrowser) {
143             MutableMediaBrowserViewModel viewModel =
144                     viewModelProvider.get(key, MutableMediaBrowserViewModel.class);
145             initMediaBrowser(mediaBrowser, viewModel);
146             return viewModel;
147         }
148 
149         /**
150          * Fetch an initialized {@link MediaBrowserViewModel}. It will get its media browser from
151          * the {@link MediaSourceViewModel} provided by {@code viewModelProvider}. It will already
152          * be configured to browse the root of the browser.
153          *
154          * @param mediaSourceVM     the {@link MediaSourceViewModel} singleton.
155          * @param viewModelProvider the ViewModelProvider to load ViewModels from.
156          * @return an initialized MediaBrowserViewModel configured to browse the specified browseId.
157          */
158         @NonNull
getInstanceForBrowseRoot( MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider)159         public static MediaBrowserViewModel getInstanceForBrowseRoot(
160                 MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider) {
161             RootMediaBrowserViewModel viewModel =
162                     viewModelProvider.get(KEY_BROWSER_ROOT, RootMediaBrowserViewModel.class);
163             initMediaBrowser(mediaSourceVM.getConnectedMediaBrowser(), viewModel);
164             return viewModel;
165         }
166 
initMediaBrowser( @onNull LiveData<MediaBrowserCompat> connectedMediaBrowser, MediaBrowserViewModelImpl viewModel)167         private static void initMediaBrowser(
168                 @NonNull LiveData<MediaBrowserCompat> connectedMediaBrowser,
169                 MediaBrowserViewModelImpl viewModel) {
170             if (viewModel.getMediaBrowserSource() != connectedMediaBrowser) {
171                 viewModel.setConnectedMediaBrowser(connectedMediaBrowser);
172             }
173         }
174     }
175 }
176