1 /* 2 * Copyright (C) 2011 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.settings.tts; 18 19 import com.android.settings.R; 20 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.Bundle; 24 import android.preference.Preference; 25 import android.preference.PreferenceActivity; 26 import android.speech.tts.TextToSpeech.EngineInfo; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.widget.Checkable; 30 import android.widget.CompoundButton; 31 import android.widget.RadioButton; 32 33 34 public class TtsEnginePreference extends Preference { 35 36 /** 37 * Key for the name of the TTS engine passed in to the engine 38 * settings fragment {@link TtsEngineSettingsFragment}. 39 */ 40 static final String FRAGMENT_ARGS_NAME = "name"; 41 42 /** 43 * Key for the label of the TTS engine passed in to the engine 44 * settings fragment. This is used as the title of the fragment 45 * {@link TtsEngineSettingsFragment}. 46 */ 47 static final String FRAGMENT_ARGS_LABEL = "label"; 48 49 /** 50 * Key for the voice data data passed in to the engine settings 51 * fragmetn {@link TtsEngineSettingsFragment}. 52 */ 53 static final String FRAGMENT_ARGS_VOICES = "voices"; 54 55 /** 56 * The preference activity that owns this preference. Required 57 * for instantiating the engine specific settings screen. 58 */ 59 private final PreferenceActivity mPreferenceActivity; 60 61 /** 62 * The engine information for the engine this preference represents. 63 * Contains it's name, label etc. which are used for display. 64 */ 65 private final EngineInfo mEngineInfo; 66 67 /** 68 * The shared radio button state, which button is checked etc. 69 */ 70 private final RadioButtonGroupState mSharedState; 71 72 /** 73 * When true, the change callbacks on the radio button will not 74 * fire. 75 */ 76 private volatile boolean mPreventRadioButtonCallbacks; 77 78 private View mSettingsIcon; 79 private RadioButton mRadioButton; 80 private Intent mVoiceCheckData; 81 82 private final CompoundButton.OnCheckedChangeListener mRadioChangeListener = 83 new CompoundButton.OnCheckedChangeListener() { 84 @Override 85 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 86 onRadioButtonClicked(buttonView, isChecked); 87 } 88 }; 89 90 public TtsEnginePreference(Context context, EngineInfo info, RadioButtonGroupState state, 91 PreferenceActivity prefActivity) { 92 super(context); 93 setLayoutResource(R.layout.preference_tts_engine); 94 95 mSharedState = state; 96 mPreferenceActivity = prefActivity; 97 mEngineInfo = info; 98 mPreventRadioButtonCallbacks = false; 99 100 setKey(mEngineInfo.name); 101 setTitle(mEngineInfo.label); 102 } 103 104 @Override 105 public View getView(View convertView, ViewGroup parent) { 106 if (mSharedState == null) { 107 throw new IllegalStateException("Call to getView() before a call to" + 108 "setSharedState()"); 109 } 110 111 View view = super.getView(convertView, parent); 112 final RadioButton rb = (RadioButton) view.findViewById(R.id.tts_engine_radiobutton); 113 rb.setOnCheckedChangeListener(mRadioChangeListener); 114 115 boolean isChecked = getKey().equals(mSharedState.getCurrentKey()); 116 if (isChecked) { 117 mSharedState.setCurrentChecked(rb); 118 } 119 120 mPreventRadioButtonCallbacks = true; 121 rb.setChecked(isChecked); 122 mPreventRadioButtonCallbacks = false; 123 124 mRadioButton = rb; 125 126 View textLayout = view.findViewById(R.id.tts_engine_pref_text); 127 textLayout.setOnClickListener(new View.OnClickListener() { 128 @Override 129 public void onClick(View v) { 130 onRadioButtonClicked(rb, !rb.isChecked()); 131 } 132 }); 133 134 mSettingsIcon = view.findViewById(R.id.tts_engine_settings); 135 // Will be enabled only the engine has passed the voice check, and 136 // is currently enabled. 137 mSettingsIcon.setEnabled(isChecked && mVoiceCheckData != null); 138 mSettingsIcon.setOnClickListener(new View.OnClickListener() { 139 @Override 140 public void onClick(View v) { 141 Bundle args = new Bundle(); 142 args.putString(FRAGMENT_ARGS_NAME, mEngineInfo.name); 143 args.putString(FRAGMENT_ARGS_LABEL, mEngineInfo.label); 144 if (mVoiceCheckData != null) { 145 args.putParcelable(FRAGMENT_ARGS_VOICES, mVoiceCheckData); 146 } 147 148 // Note that we use this instead of the (easier to use) 149 // PreferenceActivity.startPreferenceFragment because the 150 // title will not be updated correctly in the fragment 151 // breadcrumb since it isn't inflated from the XML layout. 152 mPreferenceActivity.startPreferencePanel( 153 TtsEngineSettingsFragment.class.getName(), 154 args, 0, mEngineInfo.label, null, 0); 155 } 156 }); 157 158 return view; 159 } 160 161 public void setVoiceDataDetails(Intent data) { 162 mVoiceCheckData = data; 163 mSettingsIcon.setEnabled(mRadioButton.isChecked()); 164 } 165 166 private void onRadioButtonClicked(CompoundButton buttonView, boolean isChecked) { 167 if (mPreventRadioButtonCallbacks) { 168 return; 169 } 170 171 if (isChecked) { 172 if (mSharedState.getCurrentChecked() != null) { 173 mSharedState.getCurrentChecked().setChecked(false); 174 } 175 mSharedState.setCurrentChecked(buttonView); 176 mSharedState.setCurrentKey(getKey()); 177 callChangeListener(mSharedState.getCurrentKey()); 178 } 179 180 mSettingsIcon.setEnabled(isChecked); 181 } 182 183 184 /** 185 * Holds all state that is common to this group of radio buttons, such 186 * as the currently selected key and the currently checked compound button. 187 * (which corresponds to this key). 188 */ 189 public interface RadioButtonGroupState { 190 String getCurrentKey(); 191 Checkable getCurrentChecked(); 192 193 void setCurrentKey(String key); 194 void setCurrentChecked(Checkable current); 195 } 196 197 } 198