1 /*
2  * Copyright (C) 2016 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.radio;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.media.session.PlaybackState;
22 import android.text.TextUtils;
23 import android.view.View;
24 import android.view.ViewStub;
25 import android.widget.ImageView;
26 import android.widget.TextView;
27 
28 /**
29  * Controller that controls the appearance state of various UI elements in the radio.
30  */
31 public class RadioDisplayController {
32     private final Context mContext;
33 
34     private TextView mChannelBand;
35     private TextView mChannelNumber;
36 
37     private CarouselView mChannelList;
38 
39     private TextView mCurrentSongTitle;
40     private TextView mCurrentSongArtistOrStation;
41 
42     private ImageView mBackwardSeekButton;
43     private ImageView mForwardSeekButton;
44 
45     private PlayPauseButton mPlayButton;
46     private PlayPauseButton mPresetPlayButton;
47 
48     private ImageView mPresetsListButton;
49     private ImageView mAddPresetsButton;
50 
RadioDisplayController(Context context)51     public RadioDisplayController(Context context) {
52         mContext = context;
53     }
54 
initialize(View container)55     public void initialize(View container) {
56         // Note that the band and channel number can exist without the stub
57         // single_channel_view_stub. Refer to setSingleChannelDisplay() for more information.
58         mChannelBand = (TextView) container.findViewById(R.id.radio_station_band);
59         mChannelNumber = (TextView) container.findViewById(R.id.radio_station_channel);
60 
61         mCurrentSongTitle = (TextView) container.findViewById(R.id.radio_station_song);
62         mCurrentSongArtistOrStation =
63                 (TextView) container.findViewById(R.id.radio_station_artist_or_station);
64 
65         mBackwardSeekButton = (ImageView) container.findViewById(R.id.radio_back_button);
66         mForwardSeekButton = (ImageView) container.findViewById(R.id.radio_forward_button);
67 
68         mPlayButton = (PlayPauseButton) container.findViewById(R.id.radio_play_button);
69         mPresetPlayButton = (PlayPauseButton) container.findViewById(R.id.preset_radio_play_button);
70 
71         mPresetsListButton = (ImageView) container.findViewById(R.id.radio_presets_list);
72         mAddPresetsButton = (ImageView) container.findViewById(R.id.radio_add_presets_button);
73     }
74 
75     /**
76      * Sets this radio controller to display with a single box representing the current radio
77      * station.
78      */
setSingleChannelDisplay(View container)79     public void setSingleChannelDisplay(View container) {
80         ViewStub stub = (ViewStub) container.findViewById(R.id.single_channel_view_stub);
81 
82         if (stub != null) {
83             container = stub.inflate();
84         }
85 
86         // Update references to the band and channel number.
87         mChannelBand = (TextView) container.findViewById(R.id.radio_station_band);
88         mChannelNumber = (TextView) container.findViewById(R.id.radio_station_channel);
89     }
90 
91     /**
92      * Sets this controller to display a list of channels that include the current radio station as
93      * well as pre-scanned stations for the current band.
94      */
setChannelListDisplay(View container, PrescannedRadioStationAdapter adapter)95     public void setChannelListDisplay(View container, PrescannedRadioStationAdapter adapter) {
96         ViewStub stub = (ViewStub) container.findViewById(R.id.channel_list_view_stub);
97 
98         if (stub == null) {
99             return;
100         }
101 
102         mChannelList = (CarouselView) stub.inflate();
103         mChannelList.setAdapter(adapter);
104 
105         Resources res = mContext.getResources();
106         int topOffset = res.getDimensionPixelSize(R.dimen.lens_header_height)
107                 + res.getDimensionPixelSize(R.dimen.car_radio_container_top_padding)
108                 + res.getDimensionPixelSize(R.dimen.car_radio_station_top_margin);
109 
110         mChannelList.setTopOffset(topOffset);
111     }
112 
113     /**
114      * Set the given position as the radio station that should be be displayed first in the channel
115      * list controlled by this class.
116      */
setCurrentStationInList(int position)117     public void setCurrentStationInList(int position) {
118         if (mChannelList != null) {
119             mChannelList.shiftToPosition(position);
120         }
121     }
122 
123     /**
124      * Returns the View that is responsible for rendering the play/pause state.
125      */
getPlayButton()126     public View getPlayButton() {
127         return mPlayButton;
128     }
129 
130     /**
131      * Set whether or not the buttons controlled by this controller are enabled. If {@code false}
132      * is passed to this method, then no {@link View.OnClickListener}s will be
133      * triggered when the buttons are pressed. In addition, the look of the button wil be updated
134      * to reflect their disabled state.
135      */
setEnabled(boolean enabled)136     public void setEnabled(boolean enabled) {
137         // Color the buttons so that they are grey in appearance if they are disabled.
138         int tint = enabled
139                 ? mContext.getColor(R.color.car_radio_control_button)
140                 : mContext.getColor(R.color.car_radio_control_button_disabled);
141 
142         if (mPlayButton != null) {
143             // No need to tint the play button because its drawable already contains a disabled
144             // state.
145             mPlayButton.setEnabled(enabled);
146         }
147 
148         if (mPresetPlayButton != null) {
149             // No need to tint the play button because its drawable already contains a disabled
150             // state.
151             mPresetPlayButton.setEnabled(enabled);
152         }
153 
154         if (mForwardSeekButton != null) {
155             mForwardSeekButton.setEnabled(enabled);
156             mForwardSeekButton.setColorFilter(tint);
157         }
158 
159         if (mBackwardSeekButton != null) {
160             mBackwardSeekButton.setEnabled(enabled);
161             mBackwardSeekButton.setColorFilter(tint);
162         }
163 
164         if (mPresetsListButton != null) {
165             mPresetsListButton.setEnabled(enabled);
166             mPresetsListButton.setColorFilter(tint);
167         }
168 
169         if (mAddPresetsButton != null) {
170             mAddPresetsButton.setEnabled(enabled);
171             mAddPresetsButton.setColorFilter(tint);
172         }
173     }
174 
175     /**
176      * Sets the {@link android.view.View.OnClickListener} for the backwards seek button.
177      */
setBackwardSeekButtonListener(View.OnClickListener listener)178     public void setBackwardSeekButtonListener(View.OnClickListener listener) {
179         if (mBackwardSeekButton != null) {
180             mBackwardSeekButton.setOnClickListener(listener);
181         }
182     }
183 
184     /**
185      * Sets the {@link android.view.View.OnClickListener} for the forward seek button.
186      */
setForwardSeekButtonListener(View.OnClickListener listener)187     public void setForwardSeekButtonListener(View.OnClickListener listener) {
188         if (mForwardSeekButton != null) {
189             mForwardSeekButton.setOnClickListener(listener);
190         }
191     }
192 
193     /**
194      * Sets the {@link android.view.View.OnClickListener} for the play button. Clicking on this
195      * button should toggle the radio from muted to un-muted.
196      */
setPlayButtonListener(View.OnClickListener listener)197     public void setPlayButtonListener(View.OnClickListener listener) {
198         if (mPlayButton != null) {
199             mPlayButton.setOnClickListener(listener);
200         }
201 
202         if (mPresetPlayButton != null) {
203             mPresetPlayButton.setOnClickListener(listener);
204         }
205     }
206 
207     /**
208      * Sets the {@link android.view.View.OnClickListener} for the button that will add the current
209      * radio station to a list of stored presets.
210      */
setAddPresetButtonListener(View.OnClickListener listener)211     public void setAddPresetButtonListener(View.OnClickListener listener) {
212         if (mAddPresetsButton != null) {
213             mAddPresetsButton.setOnClickListener(listener);
214         }
215     }
216 
217     /**
218      * Sets the current radio channel (e.g. 88.5).
219      */
setChannelNumber(String channel)220     public void setChannelNumber(String channel) {
221         if (mChannelNumber != null) {
222             mChannelNumber.setText(channel);
223         }
224     }
225 
226     /**
227      * Sets the radio channel band (e.g. FM).
228      */
setChannelBand(String channelBand)229     public void setChannelBand(String channelBand) {
230         if (mChannelBand != null) {
231             mChannelBand.setText(channelBand);
232             mChannelBand.setVisibility(
233                     !TextUtils.isEmpty(channelBand) ? View.VISIBLE : View.GONE);
234         }
235     }
236 
237     /**
238      * Sets the title of the currently playing song.
239      */
setCurrentSongTitle(String songTitle)240     public void setCurrentSongTitle(String songTitle) {
241         if (mCurrentSongTitle != null) {
242             boolean isEmpty = TextUtils.isEmpty(songTitle);
243             mCurrentSongTitle.setText(isEmpty ? null : songTitle.trim());
244             mCurrentSongTitle.setVisibility(isEmpty ? View.GONE : View.VISIBLE);
245         }
246     }
247 
248     /**
249      * Sets the artist(s) of the currently playing song or current radio station information
250      * (e.g. KOIT).
251      */
setCurrentSongArtistOrStation(String songArtist)252     public void setCurrentSongArtistOrStation(String songArtist) {
253         if (mCurrentSongArtistOrStation != null) {
254             boolean isEmpty = TextUtils.isEmpty(songArtist);
255             mCurrentSongArtistOrStation.setText(isEmpty ? null : songArtist.trim());
256             mCurrentSongArtistOrStation.setVisibility(isEmpty ? View.GONE : View.VISIBLE);
257         }
258     }
259 
260     /**
261      * Sets the current state of the play button. If the given {@code muted} value is {@code true},
262      * then the button display a play icon. If {@code false}, then the button will display a
263      * pause icon.
264      */
setPlayPauseButtonState(boolean muted)265     public void setPlayPauseButtonState(boolean muted) {
266         if (mPlayButton != null) {
267             mPlayButton.setPlayState(muted
268                     ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING);
269             mPlayButton.refreshDrawableState();
270         }
271 
272         if (mPresetPlayButton != null) {
273             mPresetPlayButton.setPlayState(muted
274                     ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING);
275             mPresetPlayButton.refreshDrawableState();
276         }
277     }
278 
279     /**
280      * Sets whether or not the current channel that is playing is a preset. If it is, then the
281      * icon in {@link #mPresetsListButton} will be updatd to reflect this state.
282      */
setChannelIsPreset(boolean isPreset)283     public void setChannelIsPreset(boolean isPreset) {
284         if (mAddPresetsButton != null) {
285             mAddPresetsButton.setImageResource(isPreset
286                     ? R.drawable.ic_star_filled
287                     : R.drawable.ic_star_empty);
288         }
289     }
290 }
291