1 package com.android.car.media.widgets; 2 3 import android.car.drivingstate.CarUxRestrictions; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.util.AttributeSet; 7 8 import androidx.annotation.NonNull; 9 import androidx.annotation.Nullable; 10 11 import com.android.car.media.R; 12 import com.android.car.media.common.MediaItemMetadata; 13 import com.android.car.media.common.source.MediaSource; 14 import com.android.car.ui.toolbar.MenuItem; 15 import com.android.car.ui.toolbar.Toolbar; 16 17 import java.util.Arrays; 18 import java.util.List; 19 import java.util.Objects; 20 21 /** 22 * Media template application bar. The callers should set properties via the public methods (e.g., 23 * {@link #setItems}, {@link #setTitle}, {@link #setHasSettings}), and set the visibility of the 24 * views via {@link #setState}. A detailed explanation of all possible states of this application 25 * bar can be seen at {@link Toolbar.State}. 26 */ 27 public class AppBarView extends Toolbar { 28 29 private static final int MEDIA_UX_RESTRICTION_DEFAULT = 30 CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP; 31 private static final int MEDIA_UX_RESTRICTION_NONE = CarUxRestrictions.UX_RESTRICTIONS_BASELINE; 32 33 private int mMaxTabs; 34 35 @NonNull 36 private AppBarListener mListener = new AppBarListener(); 37 private MenuItem mSearch; 38 private MenuItem mSettings; 39 private MenuItem mEqualizer; 40 private MenuItem mAppSelector; 41 42 private boolean mSearchSupported; 43 private boolean mShowSearchIfSupported; 44 45 private Intent mAppSelectorIntent; 46 47 /** 48 * Application bar listener 49 */ 50 public static class AppBarListener { 51 /** 52 * Invoked when the user selects an item from the tabs 53 */ onTabSelected(MediaItemMetadata item)54 protected void onTabSelected(MediaItemMetadata item) {} 55 56 /** 57 * Invoked when the user clicks on the back button 58 */ onBack()59 protected void onBack() {} 60 61 /** 62 * Invoked when the user clicks on the settings button. 63 */ onSettingsSelection()64 protected void onSettingsSelection() {} 65 66 /** 67 * Invoked when the user clicks on the equalizer button. 68 */ onEqualizerSelection()69 protected void onEqualizerSelection() {} 70 71 /** 72 * Invoked when the user submits a search query. 73 */ onSearch(String query)74 protected void onSearch(String query) {} 75 76 /** 77 * Invoked when the user clicks on the search button 78 */ onSearchSelection()79 protected void onSearchSelection() {} 80 81 /** 82 * Invoked when the height of the toolbar changes 83 */ onHeightChanged(int height)84 protected void onHeightChanged(int height) {} 85 } 86 AppBarView(Context context)87 public AppBarView(Context context) { 88 this(context, null); 89 } 90 AppBarView(Context context, AttributeSet attrs)91 public AppBarView(Context context, AttributeSet attrs) { 92 this(context, attrs, 0); 93 } 94 AppBarView(Context context, AttributeSet attrs, int defStyleAttr)95 public AppBarView(Context context, AttributeSet attrs, int defStyleAttr) { 96 super(context, attrs, defStyleAttr); 97 init(context); 98 } 99 init(Context context)100 private void init(Context context) { 101 mMaxTabs = context.getResources().getInteger(R.integer.max_tabs); 102 103 mAppSelectorIntent = MediaSource.getSourceSelectorIntent(context, false); 104 105 registerOnTabSelectedListener(tab -> 106 mListener.onTabSelected(((MediaItemTab) tab).getItem())); 107 registerOnBackListener(() -> { 108 mListener.onBack(); 109 return true; 110 }); 111 registerOnSearchListener(query -> mListener.onSearch(query)); 112 registerToolbarHeightChangeListener(height -> mListener.onHeightChanged(height)); 113 mSearch = MenuItem.Builder.createSearch(context, v -> mListener.onSearchSelection()); 114 mSettings = new MenuItem.Builder(context) 115 .setToSettings() 116 .setUxRestrictions(MEDIA_UX_RESTRICTION_DEFAULT) 117 .setOnClickListener(v -> mListener.onSettingsSelection()) 118 .build(); 119 mEqualizer = new MenuItem.Builder(context) 120 .setTitle(R.string.menu_item_sound_settings_title) 121 .setIcon(R.drawable.ic_equalizer) 122 .setOnClickListener(v -> mListener.onEqualizerSelection()) 123 .build(); 124 mAppSelector = new MenuItem.Builder(context) 125 .setTitle(R.string.menu_item_app_selector_title) 126 .setIcon(R.drawable.ic_app_switch) 127 .setOnClickListener(m -> getContext().startActivity(mAppSelectorIntent)) 128 .build(); 129 setMenuItems(Arrays.asList(mSearch, mEqualizer, mSettings, mAppSelector)); 130 131 setAppLauncherSupported(mAppSelectorIntent != null); 132 } 133 134 /** 135 * Sets a listener of this application bar events. In order to avoid memory leaks, consumers 136 * must reset this reference by setting the listener to null. 137 */ setListener(AppBarListener listener)138 public void setListener(AppBarListener listener) { 139 mListener = listener; 140 } 141 142 /** 143 * Updates the list of items to show in the application bar tabs. 144 * 145 * @param items list of tabs to show, or null if no tabs should be shown. 146 */ setItems(@ullable List<MediaItemMetadata> items)147 public void setItems(@Nullable List<MediaItemMetadata> items) { 148 clearAllTabs(); 149 150 if (items != null && !items.isEmpty()) { 151 int count = 0; 152 for (MediaItemMetadata item : items) { 153 addTab(new MediaItemTab(item)); 154 155 count++; 156 if (count >= mMaxTabs) { 157 break; 158 } 159 } 160 } 161 } 162 163 /** Sets whether the source has settings (not all screens show it). */ setHasSettings(boolean hasSettings)164 public void setHasSettings(boolean hasSettings) { 165 mSettings.setVisible(hasSettings); 166 } 167 168 /** Sets whether the source's settings is distraction optimized. */ setSettingsDistractionOptimized(boolean isDistractionOptimized)169 public void setSettingsDistractionOptimized(boolean isDistractionOptimized) { 170 mSettings.setUxRestrictions(isDistractionOptimized 171 ? MEDIA_UX_RESTRICTION_NONE 172 : MEDIA_UX_RESTRICTION_DEFAULT); 173 } 174 175 /** Sets whether the source has equalizer support. */ setHasEqualizer(boolean hasEqualizer)176 public void setHasEqualizer(boolean hasEqualizer) { 177 mEqualizer.setVisible(hasEqualizer); 178 } 179 180 /** 181 * Sets whether search is supported 182 */ setSearchSupported(boolean supported)183 public void setSearchSupported(boolean supported) { 184 mSearchSupported = supported; 185 updateSearchVisibility(); 186 } 187 188 /** Sets whether to show the search MenuItem if supported */ showSearchIfSupported(boolean show)189 public void showSearchIfSupported(boolean show) { 190 mShowSearchIfSupported = show; 191 updateSearchVisibility(); 192 } 193 updateSearchVisibility()194 private void updateSearchVisibility() { 195 mSearch.setVisible(mShowSearchIfSupported && mSearchSupported); 196 } 197 198 /** 199 * Sets whether launching app selector is supported 200 */ setAppLauncherSupported(boolean supported)201 private void setAppLauncherSupported(boolean supported) { 202 mAppSelector.setVisible(supported); 203 } 204 205 /** 206 * Updates the currently active item 207 */ setActiveItem(MediaItemMetadata item)208 public void setActiveItem(MediaItemMetadata item) { 209 for (int i = 0; i < getTabLayout().getTabCount(); i++) { 210 MediaItemTab mediaItemTab = (MediaItemTab) getTabLayout().get(i); 211 boolean match = item != null && Objects.equals( 212 item.getId(), 213 mediaItemTab.getItem().getId()); 214 if (match) { 215 getTabLayout().selectTab(i); 216 return; 217 } 218 } 219 } 220 } 221