1 /* 2 * Copyright (C) 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.radio; 18 19 import android.car.Car; 20 import android.content.Intent; 21 import android.graphics.drawable.Drawable; 22 import android.os.Bundle; 23 import android.view.KeyEvent; 24 25 import androidx.annotation.NonNull; 26 import androidx.fragment.app.FragmentActivity; 27 import androidx.viewpager.widget.ViewPager; 28 29 import com.android.car.media.common.source.MediaSource; 30 import com.android.car.media.common.source.MediaSourceViewModel; 31 import com.android.car.radio.bands.ProgramType; 32 import com.android.car.radio.util.Log; 33 import com.android.car.ui.toolbar.MenuItem; 34 import com.android.car.ui.toolbar.TabLayout; 35 import com.android.car.ui.toolbar.Toolbar; 36 37 import java.util.Arrays; 38 import java.util.List; 39 40 /** 41 * The main activity for the radio app. 42 */ 43 public class RadioActivity extends FragmentActivity { 44 private static final String TAG = "BcRadioApp.activity"; 45 46 /** 47 * Intent action for notifying that the radio state has changed. 48 */ 49 private static final String ACTION_RADIO_APP_STATE_CHANGE = 50 "android.intent.action.RADIO_APP_STATE_CHANGE"; 51 52 /** 53 * Boolean Intent extra indicating if the radio is the currently in the foreground. 54 */ 55 private static final String EXTRA_RADIO_APP_FOREGROUND = 56 "android.intent.action.RADIO_APP_STATE"; 57 58 private RadioController mRadioController; 59 private BandController mBandController = new BandController(); 60 private Toolbar mToolbar; 61 private RadioPagerAdapter mRadioPagerAdapter; 62 63 @Override onCreate(Bundle savedInstanceState)64 protected void onCreate(Bundle savedInstanceState) { 65 super.onCreate(savedInstanceState); 66 67 Log.d(TAG, "Radio app main activity created"); 68 69 setContentView(R.layout.radio_activity); 70 71 mRadioController = new RadioController(this); 72 mRadioController.getCurrentProgram().observe(this, info -> { 73 ProgramType programType = ProgramType.fromSelector(info.getSelector()); 74 if (programType != null) { 75 mBandController.setType(programType); 76 updateMenuItems(); 77 } 78 }); 79 80 mRadioPagerAdapter = 81 new RadioPagerAdapter(this, getSupportFragmentManager(), mRadioController); 82 ViewPager viewPager = findViewById(R.id.viewpager); 83 viewPager.setAdapter(mRadioPagerAdapter); 84 85 mToolbar = requireViewById(R.id.toolbar); 86 mToolbar.registerOnTabSelectedListener(t -> 87 viewPager.setCurrentItem(mToolbar.getTabLayout().getTabPosition(t))); 88 89 updateMenuItems(); 90 setupTabsWithViewPager(viewPager); 91 92 MediaSourceViewModel model = MediaSourceViewModel.get(getApplication()); 93 model.getPrimaryMediaSource().observe(this, source -> { 94 if (source != null) { 95 // Always go through the trampoline activity to keep all the dispatching logic 96 // there. 97 startActivity(new Intent(Car.CAR_INTENT_ACTION_MEDIA_TEMPLATE)); 98 } 99 }); 100 } 101 102 @Override onStart()103 protected void onStart() { 104 super.onStart(); 105 106 mRadioController.start(); 107 108 Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE); 109 broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, true); 110 sendBroadcast(broadcast); 111 } 112 113 @Override onStop()114 protected void onStop() { 115 super.onStop(); 116 117 Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE); 118 broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, false); 119 sendBroadcast(broadcast); 120 } 121 122 @Override onDestroy()123 protected void onDestroy() { 124 super.onDestroy(); 125 126 mRadioController.shutdown(); 127 128 Log.d(TAG, "Radio app main activity destroyed"); 129 } 130 131 @Override onKeyDown(int keyCode, KeyEvent event)132 public boolean onKeyDown(int keyCode, KeyEvent event) { 133 switch (keyCode) { 134 case KeyEvent.KEYCODE_MEDIA_STEP_FORWARD: 135 mRadioController.step(true); 136 return true; 137 case KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD: 138 mRadioController.step(false); 139 return true; 140 default: 141 return super.onKeyDown(keyCode, event); 142 } 143 } 144 145 /** 146 * Set whether background scanning is supported, to know whether to show the browse tab or not. 147 */ setProgramListSupported(boolean supported)148 public void setProgramListSupported(boolean supported) { 149 if (supported && mRadioPagerAdapter.addBrowseTab()) { 150 updateTabs(); 151 } 152 } 153 154 /** 155 * Sets supported program types. 156 */ setSupportedProgramTypes(@onNull List<ProgramType> supported)157 public void setSupportedProgramTypes(@NonNull List<ProgramType> supported) { 158 mBandController.setSupportedProgramTypes(supported); 159 } 160 setupTabsWithViewPager(ViewPager viewPager)161 private void setupTabsWithViewPager(ViewPager viewPager) { 162 viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 163 @Override 164 public void onPageSelected(int position) { 165 mToolbar.selectTab(position); 166 } 167 }); 168 updateTabs(); 169 } 170 updateMenuItems()171 private void updateMenuItems() { 172 ProgramType currentBand = mBandController.getCurrentBand(); 173 MenuItem bandSelectorMenuItem = MenuItem.builder(this) 174 .setIcon(currentBand != null ? currentBand.getResourceId() : 0) 175 .setOnClickListener(i -> { 176 ProgramType programType = mBandController.switchToNext(); 177 mRadioController.switchBand(programType); 178 }) 179 .build(); 180 181 Intent appSelectorIntent = MediaSource.getSourceSelectorIntent(this, false); 182 MenuItem appSelectorMenuItem = MenuItem.builder(this) 183 .setIcon(R.drawable.ic_app_switch) 184 .setOnClickListener(m -> startActivity(appSelectorIntent)) 185 .build(); 186 187 mToolbar.setMenuItems(Arrays.asList(bandSelectorMenuItem, appSelectorMenuItem)); 188 } 189 updateTabs()190 private void updateTabs() { 191 mToolbar.clearAllTabs(); 192 for (int i = 0; i < mRadioPagerAdapter.getCount(); i++) { 193 Drawable icon = mRadioPagerAdapter.getPageIcon(i); 194 CharSequence title = mRadioPagerAdapter.getPageTitle(i); 195 mToolbar.addTab(new TabLayout.Tab(icon, title)); 196 } 197 } 198 } 199