• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Intent;
20 import android.hardware.radio.RadioManager;
21 import android.os.Bundle;
22 import android.support.annotation.Nullable;
23 import android.support.v4.app.Fragment;
24 import android.support.v4.app.FragmentManager;
25 import android.util.Log;
26 
27 import com.android.car.app.CarDrawerActivity;
28 import com.android.car.app.CarDrawerAdapter;
29 import com.android.car.app.DrawerItemViewHolder;
30 import com.android.car.radio.service.RadioStation;
31 
32 import java.util.ArrayList;
33 import java.util.List;
34 
35 /**
36  * The main activity for the radio. This activity initializes the radio controls and listener for
37  * radio changes.
38  */
39 public class CarRadioActivity extends CarDrawerActivity implements
40         RadioPresetsFragment.PresetListExitListener,
41         MainRadioFragment.RadioPresetListClickListener,
42         ManualTunerFragment.ManualTunerCompletionListener {
43     private static final String TAG = "Em.RadioActivity";
44     private static final String MANUAL_TUNER_BACKSTACK = "MANUAL_TUNER_BACKSTACK";
45     private static final String CONTENT_FRAGMENT_TAG = "CONTENT_FRAGMENT_TAG";
46 
47     private static final int[] SUPPORTED_RADIO_BANDS = new int[] {
48         RadioManager.BAND_AM, RadioManager.BAND_FM };
49 
50     /**
51      * Intent action for notifying that the radio state has changed.
52      */
53     private static final String ACTION_RADIO_APP_STATE_CHANGE
54             = "android.intent.action.RADIO_APP_STATE_CHANGE";
55 
56     /**
57      * Boolean Intent extra indicating if the radio is the currently in the foreground.
58      */
59     private static final String EXTRA_RADIO_APP_FOREGROUND
60             = "android.intent.action.RADIO_APP_STATE";
61 
62     /**
63      * Whether or not it is safe to make transactions on the
64      * {@link android.support.v4.app.FragmentManager}. This variable prevents a possible exception
65      * when calling commit() on the FragmentManager.
66      *
67      * <p>The default value is {@code true} because it is only after
68      * {@link #onSaveInstanceState(Bundle)} has been called that fragment commits are not allowed.
69      */
70     private boolean mAllowFragmentCommits = true;
71 
72     private RadioController mRadioController;
73 
74     @Override
onCreate(Bundle savedInstanceState)75     protected void onCreate(Bundle savedInstanceState) {
76         super.onCreate(savedInstanceState);
77 
78         mRadioController = new RadioController(this);
79         setContentFragment(
80                 MainRadioFragment.newInstance(mRadioController, this /* clickListener */));
81 
82     }
83 
84     @Override
getRootAdapter()85     protected CarDrawerAdapter getRootAdapter() {
86         return new RadioDrawerAdapter();
87     }
88 
89     @Override
onPresetListClicked()90     public void onPresetListClicked() {
91         setContentFragment(
92                 RadioPresetsFragment.newInstance(mRadioController, this /* existListener */));
93     }
94 
95     @Override
OnPresetListExit()96     public void OnPresetListExit() {
97         setContentFragment(
98                 MainRadioFragment.newInstance(mRadioController, this /* clickListener */));
99     }
100 
startManualTuner()101     private void startManualTuner() {
102         if (!mAllowFragmentCommits || getSupportFragmentManager().getBackStackEntryCount() > 0) {
103             return;
104         }
105 
106         Fragment currentFragment = getCurrentFragment();
107         if (currentFragment instanceof FragmentWithFade) {
108             ((FragmentWithFade) currentFragment).fadeOutContent();
109         }
110 
111         ManualTunerFragment tunerFragment =
112                 ManualTunerFragment.newInstance(mRadioController.getCurrentRadioBand());
113         tunerFragment.setManualTunerCompletionListener(this);
114 
115         getSupportFragmentManager().beginTransaction()
116                 .setCustomAnimations(R.anim.slide_up, R.anim.slide_down,
117                         R.anim.slide_up, R.anim.slide_down)
118                 .add(getContentContainerId(), tunerFragment)
119                 .addToBackStack(MANUAL_TUNER_BACKSTACK)
120                 .commit();
121     }
122 
123     @Override
onStationSelected(RadioStation station)124     public void onStationSelected(RadioStation station) {
125         maybeDismissManualTuner();
126 
127         Fragment fragment = getCurrentFragment();
128         if (fragment instanceof FragmentWithFade) {
129             ((FragmentWithFade) fragment).fadeInContent();
130         }
131 
132         if (station != null) {
133             mRadioController.tuneToRadioChannel(station);
134         }
135     }
136 
137     @Override
onStart()138     protected void onStart() {
139         super.onStart();
140 
141         if (Log.isLoggable(TAG, Log.DEBUG)) {
142             Log.d(TAG, "onStart");
143         }
144 
145         // Fragment commits are not allowed once the Activity's state has been saved. Once
146         // onStart() has been called, the FragmentManager should now allow commits.
147         mAllowFragmentCommits = true;
148 
149         mRadioController.start();
150 
151         Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE);
152         broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, true);
153         sendBroadcast(broadcast);
154     }
155 
156     @Override
onStop()157     protected void onStop() {
158         super.onStop();
159 
160         if (Log.isLoggable(TAG, Log.DEBUG)) {
161             Log.d(TAG, "onStop");
162         }
163 
164         Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE);
165         broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, false);
166         sendBroadcast(broadcast);
167     }
168 
169     @Override
onDestroy()170     protected void onDestroy() {
171         super.onDestroy();
172 
173         if (Log.isLoggable(TAG, Log.DEBUG)) {
174             Log.d(TAG, "onDestroy");
175         }
176 
177         mRadioController.shutdown();
178     }
179 
180     @Override
onSaveInstanceState(Bundle outState)181     public void onSaveInstanceState(Bundle outState) {
182         // A transaction can only be committed with this method prior to its containing activity
183         // saving its state.
184         mAllowFragmentCommits = false;
185         super.onSaveInstanceState(outState);
186     }
187 
188     /**
189      * Checks if the manual tuner is currently being displayed. If it is, then dismiss it.
190      */
maybeDismissManualTuner()191     private void maybeDismissManualTuner() {
192         FragmentManager fragmentManager = getSupportFragmentManager();
193         if (fragmentManager.getBackStackEntryCount() > 0) {
194             // A station can only be selected if the manual tuner fragment has been shown; so, remove
195             // that here.
196             getSupportFragmentManager().popBackStack();
197         }
198     }
199 
setContentFragment(Fragment fragment)200     private void setContentFragment(Fragment fragment) {
201         if (!mAllowFragmentCommits) {
202             return;
203         }
204 
205         getSupportFragmentManager().beginTransaction()
206                 .replace(getContentContainerId(), fragment, CONTENT_FRAGMENT_TAG)
207                 .commitNow();
208     }
209 
210     /**
211      * Returns the fragment that is currently being displayed as the content view. Note that this
212      * is not necessarily the fragment that is visible. The manual tuner fragment can be displayed
213      * on top of this content fragment.
214      */
215     @Nullable
getCurrentFragment()216     private Fragment getCurrentFragment() {
217         return getSupportFragmentManager().findFragmentByTag(CONTENT_FRAGMENT_TAG);
218     }
219 
220     /**
221      * An adapter that is responsible for populating the Radio drawer with the available bands to
222      * select, as well as the option for opening the manual tuner.
223      */
224     private class RadioDrawerAdapter extends CarDrawerAdapter {
225         private final List<String> mDrawerOptions =
226                 new ArrayList<>(SUPPORTED_RADIO_BANDS.length + 1);
227 
RadioDrawerAdapter()228         RadioDrawerAdapter() {
229             super(CarRadioActivity.this, false /* showDisabledListOnEmpty */);
230             setTitle(getString(R.string.app_name));
231             // The ordering of options is hardcoded. The click handler below depends on it.
232             for (int band : SUPPORTED_RADIO_BANDS) {
233                 String bandText =
234                         RadioChannelFormatter.formatRadioBand(CarRadioActivity.this, band);
235                 mDrawerOptions.add(bandText);
236             }
237             mDrawerOptions.add(getString(R.string.manual_tuner_drawer_entry));
238         }
239 
240         @Override
getActualItemCount()241         protected int getActualItemCount() {
242             return mDrawerOptions.size();
243         }
244 
245         @Override
populateViewHolder(DrawerItemViewHolder holder, int position)246         public void populateViewHolder(DrawerItemViewHolder holder, int position) {
247             holder.getTitle().setText(mDrawerOptions.get(position));
248         }
249 
250         @Override
onItemClick(int position)251         public void onItemClick(int position) {
252             closeDrawer();
253             if (position < SUPPORTED_RADIO_BANDS.length) {
254                 mRadioController.openRadioBand(SUPPORTED_RADIO_BANDS[position]);
255             } else if (position == SUPPORTED_RADIO_BANDS.length) {
256                 startManualTuner();
257             } else {
258                 Log.w(TAG, "Unexpected position: " + position);
259             }
260         }
261     }
262 }
263