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.os.Bundle; 22 import android.view.KeyEvent; 23 24 import androidx.annotation.NonNull; 25 import androidx.fragment.app.FragmentActivity; 26 import androidx.viewpager.widget.ViewPager; 27 28 import com.android.car.apps.common.widget.CarTabLayout; 29 import com.android.car.media.common.MediaAppSelectorWidget; 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.radio.widget.BandSelector; 34 35 import java.util.List; 36 37 /** 38 * The main activity for the radio app. 39 */ 40 public class RadioActivity extends FragmentActivity { 41 private static final String TAG = "BcRadioApp.activity"; 42 43 /** 44 * Intent action for notifying that the radio state has changed. 45 */ 46 private static final String ACTION_RADIO_APP_STATE_CHANGE = 47 "android.intent.action.RADIO_APP_STATE_CHANGE"; 48 49 /** 50 * Boolean Intent extra indicating if the radio is the currently in the foreground. 51 */ 52 private static final String EXTRA_RADIO_APP_FOREGROUND = 53 "android.intent.action.RADIO_APP_STATE"; 54 55 private RadioController mRadioController; 56 private BandSelector mBandSelector; 57 58 private CarTabLayout mCarTabLayout; 59 private RadioPagerAdapter mRadioPagerAdapter; 60 61 @Override onCreate(Bundle savedInstanceState)62 protected void onCreate(Bundle savedInstanceState) { 63 super.onCreate(savedInstanceState); 64 65 Log.d(TAG, "Radio app main activity created"); 66 67 setContentView(R.layout.radio_activity); 68 mBandSelector = findViewById(R.id.band_toggle_button); 69 70 MediaAppSelectorWidget appSelector = findViewById(R.id.app_switch_container); 71 appSelector.setFragmentActivity(this); 72 73 mRadioController = new RadioController(this); 74 mBandSelector.setCallback(mRadioController::switchBand); 75 mRadioController.getCurrentProgram().observe(this, info -> 76 mBandSelector.setType(ProgramType.fromSelector(info.getSelector()))); 77 78 mRadioPagerAdapter = 79 new RadioPagerAdapter(this, getSupportFragmentManager(), mRadioController); 80 ViewPager viewPager = findViewById(R.id.viewpager); 81 viewPager.setAdapter(mRadioPagerAdapter); 82 mCarTabLayout = findViewById(R.id.tabs); 83 setupTabsWithViewPager(mCarTabLayout, viewPager); 84 85 MediaSourceViewModel model = MediaSourceViewModel.get(getApplication()); 86 model.getPrimaryMediaSource().observe(this, source -> { 87 if (source != null) { 88 // Always go through the trampoline activity to keep all the dispatching logic 89 // there. 90 startActivity(new Intent(Car.CAR_INTENT_ACTION_MEDIA_TEMPLATE)); 91 } 92 }); 93 } 94 95 @Override onStart()96 protected void onStart() { 97 super.onStart(); 98 99 mRadioController.start(); 100 101 Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE); 102 broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, true); 103 sendBroadcast(broadcast); 104 } 105 106 @Override onStop()107 protected void onStop() { 108 super.onStop(); 109 110 Intent broadcast = new Intent(ACTION_RADIO_APP_STATE_CHANGE); 111 broadcast.putExtra(EXTRA_RADIO_APP_FOREGROUND, false); 112 sendBroadcast(broadcast); 113 } 114 115 @Override onDestroy()116 protected void onDestroy() { 117 super.onDestroy(); 118 119 mRadioController.shutdown(); 120 121 Log.d(TAG, "Radio app main activity destroyed"); 122 } 123 124 @Override onKeyDown(int keyCode, KeyEvent event)125 public boolean onKeyDown(int keyCode, KeyEvent event) { 126 switch (keyCode) { 127 case KeyEvent.KEYCODE_MEDIA_STEP_FORWARD: 128 mRadioController.step(true); 129 return true; 130 case KeyEvent.KEYCODE_MEDIA_STEP_BACKWARD: 131 mRadioController.step(false); 132 return true; 133 default: 134 return super.onKeyDown(keyCode, event); 135 } 136 } 137 138 /** 139 * Set whether background scanning is supported, to know whether to show the browse tab or not 140 */ setProgramListSupported(boolean supported)141 public void setProgramListSupported(boolean supported) { 142 if (supported && mRadioPagerAdapter.addBrowseTab()) { 143 buildTabs(); 144 } 145 } 146 147 /** 148 * Sets supported program types. 149 */ setSupportedProgramTypes(@onNull List<ProgramType> supported)150 public void setSupportedProgramTypes(@NonNull List<ProgramType> supported) { 151 mBandSelector.setSupportedProgramTypes(supported); 152 } 153 setupTabsWithViewPager(CarTabLayout carTabLayout, ViewPager viewPager)154 private void setupTabsWithViewPager(CarTabLayout carTabLayout, ViewPager viewPager) { 155 carTabLayout.addOnCarTabSelectedListener(new CarTabLayout.SimpleOnCarTabSelectedListener() { 156 @Override 157 public void onCarTabSelected(CarTabLayout.CarTab carTab) { 158 viewPager.setCurrentItem(carTabLayout.getCarTabPosition(carTab)); 159 } 160 }); 161 viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 162 @Override 163 public void onPageSelected(int position) { 164 carTabLayout.selectCarTab(position); 165 } 166 }); 167 buildTabs(); 168 } 169 buildTabs()170 private void buildTabs() { 171 mCarTabLayout.clearAllCarTabs(); 172 for (int i = 0; i < mRadioPagerAdapter.getCount(); i++) { 173 CarTabLayout.CarTab carTab = new CarTabLayout.CarTab(mRadioPagerAdapter.getPageIcon(i), 174 mRadioPagerAdapter.getPageTitle(i)); 175 mCarTabLayout.addCarTab(carTab); 176 } 177 } 178 179 } 180