1 /* 2 * Copyright (C) 2015 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.tv.settings.system; 18 19 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected; 20 21 import android.app.AlertDialog; 22 import android.app.tvsettings.TvSettingsEnums; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.speech.tts.TextToSpeech; 26 import android.util.Log; 27 import android.widget.Checkable; 28 import android.widget.RadioButton; 29 30 import androidx.preference.Preference; 31 import androidx.preference.PreferenceViewHolder; 32 33 import com.android.tv.settings.R; 34 35 public class TtsEnginePreference extends Preference { 36 37 private static final String TAG = "TtsEnginePreference"; 38 39 /** 40 * The engine information for the engine this preference represents. 41 * Contains it's name, label etc. which are used for display. 42 */ 43 private final TextToSpeech.EngineInfo mEngineInfo; 44 45 /** 46 * The shared radio button state, which button is checked etc. 47 */ 48 private final RadioButtonGroupState mSharedState; 49 50 private RadioButton mRadioButton; 51 TtsEnginePreference(Context context, TextToSpeech.EngineInfo info, RadioButtonGroupState state)52 public TtsEnginePreference(Context context, TextToSpeech.EngineInfo info, 53 RadioButtonGroupState state) { 54 super(context); 55 setWidgetLayoutResource(R.layout.radio_preference_widget); 56 57 mSharedState = state; 58 mEngineInfo = info; 59 60 setKey(mEngineInfo.name); 61 setTitle(mEngineInfo.label); 62 } 63 64 @Override onBindViewHolder(PreferenceViewHolder viewHolder)65 public void onBindViewHolder(PreferenceViewHolder viewHolder) { 66 super.onBindViewHolder(viewHolder); 67 68 final RadioButton rb = (RadioButton) viewHolder.findViewById(android.R.id.checkbox); 69 70 boolean isChecked = getKey().equals(mSharedState.getCurrentKey()); 71 if (isChecked) { 72 mSharedState.setCurrentChecked(rb); 73 } 74 75 rb.setChecked(isChecked); 76 77 mRadioButton = rb; 78 } 79 80 @Override onClick()81 protected void onClick() { 82 super.onClick(); 83 onRadioButtonClicked(mRadioButton, !mRadioButton.isChecked()); 84 } 85 shouldDisplayDataAlert()86 private boolean shouldDisplayDataAlert() { 87 return !mEngineInfo.system; 88 } 89 displayDataAlert( DialogInterface.OnClickListener positiveOnClickListener, DialogInterface.OnClickListener negativeOnClickListener)90 private void displayDataAlert( 91 DialogInterface.OnClickListener positiveOnClickListener, 92 DialogInterface.OnClickListener negativeOnClickListener) { 93 // TODO: don't use phone UI 94 Log.i(TAG, "Displaying data alert for :" + mEngineInfo.name); 95 96 AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 97 builder.setTitle(android.R.string.dialog_alert_title) 98 .setMessage(getContext().getString( 99 R.string.tts_engine_security_warning, mEngineInfo.label)) 100 .setCancelable(true) 101 .setPositiveButton(android.R.string.ok, positiveOnClickListener) 102 .setNegativeButton(android.R.string.cancel, negativeOnClickListener); 103 104 AlertDialog dialog = builder.create(); 105 dialog.show(); 106 } 107 onRadioButtonClicked(final Checkable buttonView, boolean isChecked)108 private void onRadioButtonClicked(final Checkable buttonView, 109 boolean isChecked) { 110 logEntrySelected(TvSettingsEnums.SYSTEM_A11Y_TTS_ENGINE_SELECT); 111 if (mSharedState.getCurrentChecked() == buttonView) { 112 return; 113 } 114 115 if (isChecked) { 116 // Should we alert user? if that's true, delay making engine current one. 117 if (shouldDisplayDataAlert()) { 118 displayDataAlert( 119 new DialogInterface.OnClickListener() { 120 @Override 121 public void onClick(DialogInterface dialog, int which) { 122 makeCurrentEngine(buttonView); 123 } 124 }, 125 new DialogInterface.OnClickListener() { 126 @Override 127 public void onClick(DialogInterface dialog, int which) { 128 // Undo the click. 129 buttonView.setChecked(false); 130 } 131 }); 132 } else { 133 // Privileged engine, set it current 134 makeCurrentEngine(buttonView); 135 } 136 } 137 } 138 makeCurrentEngine(Checkable current)139 private void makeCurrentEngine(Checkable current) { 140 if (mSharedState.getCurrentChecked() != null) { 141 mSharedState.getCurrentChecked().setChecked(false); 142 } 143 mSharedState.setCurrentChecked(current); 144 mSharedState.setCurrentKey(getKey()); 145 callChangeListener(mSharedState.getCurrentKey()); 146 } 147 148 149 /** 150 * Holds all state that is common to this group of radio buttons, such 151 * as the currently selected key and the currently checked compound button. 152 * (which corresponds to this key). 153 */ 154 public interface RadioButtonGroupState { getCurrentKey()155 String getCurrentKey(); getCurrentChecked()156 Checkable getCurrentChecked(); 157 setCurrentKey(String key)158 void setCurrentKey(String key); setCurrentChecked(Checkable current)159 void setCurrentChecked(Checkable current); 160 } 161 162 } 163