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(@ullable String browseId)115 void setCurrentBrowseId(@Nullable 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 ViewModelProvider viewModelProvider, @NonNull LiveData<MediaBrowserCompat> mediaBrowser)139 public static MediaBrowserViewModel.WithMutableBrowseId getInstanceWithMediaBrowser( 140 @NonNull ViewModelProvider viewModelProvider, 141 @NonNull LiveData<MediaBrowserCompat> mediaBrowser) { 142 MediaBrowserViewModelImpl viewModel = viewModelProvider.get( 143 MediaBrowserViewModelImpl.class); 144 initMediaBrowser(mediaBrowser, viewModel); 145 return viewModel; 146 } 147 148 /** 149 * Fetch an initialized {@link MediaBrowserViewModel.WithMutableBrowseId}. It will get its 150 * media browser from the {@link MediaSourceViewModel} provided by {@code 151 * viewModelProvider}. 152 * 153 * 154 * @param mediaSourceVM the {@link MediaSourceViewModel} singleton. 155 * @param viewModelProvider the ViewModelProvider to load ViewModels from. 156 * @param key a key to decide which instance of the ViewModel to fetch. 157 * Subsequent calls with the same key will return the same 158 * instance. 159 * @return an initialized MediaBrowserViewModel.WithMutableBrowseId for the given key. 160 * @see ViewModelProvider#get(String, Class) 161 */ 162 @NonNull getInstanceForKey( MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider, @NonNull String key)163 public static MediaBrowserViewModel.WithMutableBrowseId getInstanceForKey( 164 MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider, 165 @NonNull String key) { 166 MediaBrowserViewModelImpl viewModel = viewModelProvider.get(key, 167 MediaBrowserViewModelImpl.class); 168 initMediaBrowser(mediaSourceVM.getConnectedMediaBrowser(), viewModel); 169 return viewModel; 170 } 171 172 /** 173 * Fetch an initialized {@link MediaBrowserViewModel}. It will get its media browser from 174 * the {@link MediaSourceViewModel} provided by {@code viewModelProvider}. It will already 175 * be configured to browse {@code browseId}. 176 * 177 * 178 * @param mediaSourceVM the {@link MediaSourceViewModel} singleton. 179 * @param viewModelProvider the ViewModelProvider to load ViewModels from. 180 * @param browseId the browseId to browse. This will also serve as the key for 181 * fetching the ViewModel. 182 * @return an initialized MediaBrowserViewModel configured to browse the specified browseId. 183 */ 184 @NonNull getInstanceForBrowseId( MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider, @NonNull String browseId)185 public static MediaBrowserViewModel getInstanceForBrowseId( 186 MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider, 187 @NonNull String browseId) { 188 MediaBrowserViewModel.WithMutableBrowseId viewModel = 189 getInstanceForKey(mediaSourceVM, viewModelProvider, browseId); 190 viewModel.setCurrentBrowseId(browseId); 191 return viewModel; 192 } 193 194 /** 195 * Fetch an initialized {@link MediaBrowserViewModel}. It will get its media browser from 196 * the {@link MediaSourceViewModel} provided by {@code viewModelProvider}. It will already 197 * be configured to browse the root of the browser. 198 * 199 * @param mediaSourceVM the {@link MediaSourceViewModel} singleton. 200 * @param viewModelProvider the ViewModelProvider to load ViewModels from. 201 * @return an initialized MediaBrowserViewModel configured to browse the specified browseId. 202 */ 203 @NonNull getInstanceForBrowseRoot( MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider)204 public static MediaBrowserViewModel getInstanceForBrowseRoot( 205 MediaSourceViewModel mediaSourceVM, @NonNull ViewModelProvider viewModelProvider) { 206 MediaBrowserViewModel.WithMutableBrowseId viewModel = 207 getInstanceForKey(mediaSourceVM, viewModelProvider, KEY_BROWSER_ROOT); 208 viewModel.setCurrentBrowseId(null); 209 return viewModel; 210 } 211 initMediaBrowser( @onNull LiveData<MediaBrowserCompat> connectedMediaBrowser, MediaBrowserViewModelImpl viewModel)212 private static void initMediaBrowser( 213 @NonNull LiveData<MediaBrowserCompat> connectedMediaBrowser, 214 MediaBrowserViewModelImpl viewModel) { 215 if (viewModel.getMediaBrowserSource() != connectedMediaBrowser) { 216 viewModel.setConnectedMediaBrowser(connectedMediaBrowser); 217 } 218 } 219 } 220 } 221