Home | History | Annotate | Download | only in voice
      1 /*
      2  * Copyright (C) 2014 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.voice;
     18 
     19 import android.app.AlertDialog;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.content.Intent;
     24 import android.preference.Preference;
     25 import android.util.Log;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.Checkable;
     29 import android.widget.CompoundButton;
     30 import android.widget.RadioButton;
     31 
     32 
     33 import com.android.settings.R;
     34 import com.android.settings.Utils;
     35 
     36 public final class VoiceInputPreference extends Preference {
     37 
     38     private static final String TAG = "VoiceInputPreference";
     39 
     40     private final CharSequence mLabel;
     41 
     42     private final CharSequence mAppLabel;
     43 
     44     private final CharSequence mAlertText;
     45 
     46     private final ComponentName mSettingsComponent;
     47 
     48     /**
     49      * The shared radio button state, which button is checked etc.
     50      */
     51     private final RadioButtonGroupState mSharedState;
     52 
     53     /**
     54      * When true, the change callbacks on the radio button will not
     55      * fire.
     56      */
     57     private volatile boolean mPreventRadioButtonCallbacks;
     58 
     59     private View mSettingsIcon;
     60     private RadioButton mRadioButton;
     61 
     62     private final CompoundButton.OnCheckedChangeListener mRadioChangeListener =
     63         new CompoundButton.OnCheckedChangeListener() {
     64             @Override
     65             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
     66                 onRadioButtonClicked(buttonView, isChecked);
     67             }
     68         };
     69 
     70     public VoiceInputPreference(Context context, VoiceInputHelper.BaseInfo info,
     71             CharSequence summary, CharSequence alertText, RadioButtonGroupState state) {
     72         super(context);
     73         setLayoutResource(R.layout.preference_tts_engine);
     74 
     75         mSharedState = state;
     76         mLabel = info.label;
     77         mAppLabel = info.appLabel;
     78         mAlertText = alertText;
     79         mSettingsComponent = info.settings;
     80         mPreventRadioButtonCallbacks = false;
     81 
     82         setKey(info.key);
     83         setTitle(info.label);
     84         setSummary(summary);
     85     }
     86 
     87     @Override
     88     public View getView(View convertView, ViewGroup parent) {
     89         if (mSharedState == null) {
     90             throw new IllegalStateException("Call to getView() before a call to" +
     91                     "setSharedState()");
     92         }
     93 
     94         View view = super.getView(convertView, parent);
     95         final RadioButton rb = (RadioButton) view.findViewById(R.id.tts_engine_radiobutton);
     96         rb.setOnCheckedChangeListener(mRadioChangeListener);
     97 
     98         boolean isChecked = getKey().equals(mSharedState.getCurrentKey());
     99         if (isChecked) {
    100             mSharedState.setCurrentChecked(rb);
    101         }
    102 
    103         mPreventRadioButtonCallbacks = true;
    104         rb.setChecked(isChecked);
    105         mPreventRadioButtonCallbacks = false;
    106 
    107         mRadioButton = rb;
    108 
    109         View textLayout = view.findViewById(R.id.tts_engine_pref_text);
    110         textLayout.setOnClickListener(new View.OnClickListener() {
    111             @Override
    112             public void onClick(View v) {
    113                 if (!rb.isChecked()) {
    114                     onRadioButtonClicked(rb, true);
    115                 }
    116             }
    117         });
    118 
    119         mSettingsIcon = view.findViewById(R.id.tts_engine_settings);
    120         mSettingsIcon.setOnClickListener(new View.OnClickListener() {
    121             @Override
    122             public void onClick(View v) {
    123                 Intent intent = new Intent(Intent.ACTION_MAIN);
    124                 intent.setComponent(mSettingsComponent);
    125                 getContext().startActivity(new Intent(intent));
    126             }
    127         });
    128         updateCheckedState(isChecked);
    129 
    130         return view;
    131     }
    132 
    133     private boolean shouldDisplayAlert() {
    134         return mAlertText != null;
    135     }
    136 
    137     private void displayAlert(
    138             final DialogInterface.OnClickListener positiveOnClickListener,
    139             final DialogInterface.OnClickListener negativeOnClickListener) {
    140         Log.i(TAG, "Displaying data alert for :" + getKey());
    141 
    142         AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    143         String msg = String.format(getContext().getResources().getConfiguration().locale,
    144                 mAlertText.toString(), mAppLabel);
    145         builder.setTitle(android.R.string.dialog_alert_title)
    146                 .setMessage(msg)
    147                 .setCancelable(true)
    148                 .setPositiveButton(android.R.string.ok, positiveOnClickListener)
    149                 .setNegativeButton(android.R.string.cancel, negativeOnClickListener)
    150                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
    151                     @Override public void onCancel(DialogInterface dialog) {
    152                         negativeOnClickListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
    153                     }
    154                 });
    155 
    156         AlertDialog dialog = builder.create();
    157         dialog.show();
    158     }
    159 
    160     public void doClick() {
    161         mRadioButton.performClick();
    162     }
    163 
    164     void updateCheckedState(boolean isChecked) {
    165         if (mSettingsComponent != null) {
    166             mSettingsIcon.setVisibility(View.VISIBLE);
    167             if (isChecked) {
    168                 mSettingsIcon.setEnabled(true);
    169                 mSettingsIcon.setAlpha(1);
    170             } else {
    171                 mSettingsIcon.setEnabled(false);
    172                 mSettingsIcon.setAlpha(Utils.DISABLED_ALPHA);
    173             }
    174         } else {
    175             mSettingsIcon.setVisibility(View.GONE);
    176         }
    177     }
    178 
    179     void onRadioButtonClicked(final CompoundButton buttonView, boolean isChecked) {
    180         if (mPreventRadioButtonCallbacks) {
    181             return;
    182         }
    183         if (mSharedState.getCurrentChecked() == buttonView) {
    184             updateCheckedState(isChecked);
    185             return;
    186         }
    187 
    188         if (isChecked) {
    189             // Should we alert user? if that's true, delay making engine current one.
    190             if (shouldDisplayAlert()) {
    191                 displayAlert(new DialogInterface.OnClickListener() {
    192                                  @Override
    193                                  public void onClick(DialogInterface dialog, int which) {
    194                                      makeCurrentChecked(buttonView);
    195                                  }
    196                              }, new DialogInterface.OnClickListener() {
    197                                  @Override
    198                                  public void onClick(DialogInterface dialog, int which) {
    199                                      // Undo the click.
    200                                      buttonView.setChecked(false);
    201                                  }
    202                              }
    203                 );
    204             } else {
    205                 // Privileged engine, set it current
    206                 makeCurrentChecked(buttonView);
    207             }
    208         } else {
    209             updateCheckedState(isChecked);
    210         }
    211     }
    212 
    213     void makeCurrentChecked(Checkable current) {
    214         if (mSharedState.getCurrentChecked() != null) {
    215             mSharedState.getCurrentChecked().setChecked(false);
    216         }
    217         mSharedState.setCurrentChecked(current);
    218         mSharedState.setCurrentKey(getKey());
    219         updateCheckedState(true);
    220         callChangeListener(mSharedState.getCurrentKey());
    221         current.setChecked(true);
    222     }
    223 
    224     /**
    225      * Holds all state that is common to this group of radio buttons, such
    226      * as the currently selected key and the currently checked compound button.
    227      * (which corresponds to this key).
    228      */
    229     public interface RadioButtonGroupState {
    230         String getCurrentKey();
    231         Checkable getCurrentChecked();
    232 
    233         void setCurrentKey(String key);
    234         void setCurrentChecked(Checkable current);
    235     }
    236 }
    237