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 package com.android.car.radio; 17 18 import android.content.Context; 19 import android.hardware.radio.ProgramSelector; 20 import android.view.View; 21 import android.widget.TextView; 22 23 import androidx.annotation.NonNull; 24 25 import com.android.car.radio.bands.ProgramType; 26 import com.android.car.radio.bands.RegionConfig; 27 import com.android.car.radio.widget.BandSelectorFlat; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.Objects; 32 33 public class ManualTunerController { 34 private final Object mLock = new Object(); 35 36 private final List<View> mDigitButtons = new ArrayList<>(); 37 private final View mEnterButton; 38 private final TextView mChannelDisplay; 39 private BandSelectorFlat mBandSelector; 40 41 private ProgramType mProgramType; 42 private final RegionConfig mRegionConfig; 43 private final TuningDoneListener mDoneListener; 44 private int mEnteredDigits; 45 46 /** 47 * Listener for manual tuning done event. 48 */ 49 public interface TuningDoneListener { 50 /** 51 * Called when the user accepted channel selection. 52 */ onDone(@onNull ProgramSelector sel)53 void onDone(@NonNull ProgramSelector sel); 54 } 55 ManualTunerController(Context context, View container, @NonNull RegionConfig regionConfig, @NonNull TuningDoneListener doneListener)56 public ManualTunerController(Context context, View container, 57 @NonNull RegionConfig regionConfig, @NonNull TuningDoneListener doneListener) { 58 mRegionConfig = Objects.requireNonNull(regionConfig); 59 mDoneListener = Objects.requireNonNull(doneListener); 60 61 mChannelDisplay = Objects.requireNonNull(container.findViewById(R.id.manual_tuner_channel)); 62 mEnterButton = container.findViewById(R.id.manual_tuner_done_button); 63 mBandSelector = container.findViewById(R.id.manual_tuner_band_selector); 64 65 mEnterButton.setOnClickListener(this::onDoneClick); 66 mBandSelector.setCallback(this::switchProgramType); 67 mBandSelector.setSupportedProgramTypes(regionConfig.getSupportedProgramTypes()); 68 69 View dialpad = container.findViewById(R.id.dialpad_layout); 70 View.OnClickListener digitClickListener = this::onDigitClick; 71 for (int i = 0; i <= 9; i++) { 72 View btn = dialpad.findViewWithTag(Integer.toString(i)); 73 btn.setOnClickListener(digitClickListener); 74 mDigitButtons.add(i, btn); 75 } 76 View backspace = dialpad.findViewById(R.id.manual_tuner_backspace); 77 backspace.setOnClickListener(this::onBackspaceClick); 78 79 switchProgramType(ProgramType.FM); 80 } 81 updateDisplay()82 private void updateDisplay() { 83 synchronized (mLock) { 84 mChannelDisplay.setText(mProgramType.format(mEnteredDigits)); 85 mEnterButton.setEnabled(mProgramType.isComplete(mRegionConfig, mEnteredDigits)); 86 boolean[] valid = mProgramType.getValidAppendices(mRegionConfig, mEnteredDigits); 87 for (int i = 0; i < 10; i++) { 88 mDigitButtons.get(i).setEnabled(valid[i]); 89 } 90 } 91 } 92 onDigitClick(View btn)93 private void onDigitClick(View btn) { 94 int digit = Integer.parseInt((String) btn.getTag()); 95 synchronized (mLock) { 96 mEnteredDigits *= 10; 97 mEnteredDigits += digit; 98 } 99 updateDisplay(); 100 } 101 onBackspaceClick(View btn)102 private void onBackspaceClick(View btn) { 103 synchronized (mLock) { 104 mEnteredDigits /= 10; 105 } 106 updateDisplay(); 107 } 108 onDoneClick(View btn)109 private void onDoneClick(View btn) { 110 synchronized (mLock) { 111 mDoneListener.onDone(mProgramType.parseDigits(mEnteredDigits)); 112 mEnteredDigits = 0; 113 } 114 updateDisplay(); 115 } 116 117 /** 118 * Switches program type (band). 119 */ switchProgramType(@onNull ProgramType pt)120 public void switchProgramType(@NonNull ProgramType pt) { 121 Objects.requireNonNull(pt); 122 synchronized (mLock) { 123 if (mProgramType == pt) return; 124 mProgramType = pt; 125 mEnteredDigits = 0; 126 mBandSelector.setType(pt); 127 } 128 updateDisplay(); 129 } 130 } 131