1

I am working with Xamarin.Forms app. I am trying to add Speech to Text functionality to Xamarin.Forms through a toolbar item click. When I click the button on tool I want the builtin phone speech service to open and convert my speech to text and add to page's label.

Problem: In order to trigger the speech service which is android specific. I need a custom renderer for the toolbar item. So, I can add the code for speech to text in that custom renderer's OnClick method. but I can't seem to find the renderer class for toolbar item.

Here is code of my current attempt at Toolbar Item renderer

VoiceToolbarItemRenderer.cs

[assembly: ExportRenderer(typeof(VoiceToolbarItem), typeof(VoiceToolbarItemRenderer))]

namespace Xamarin_App.Droid
{
    public class VoiceToolbarItemRenderer : PageRenderer, Android.Views.View.IOnClickListene
{

    private bool isRecording;
    private readonly int VOICE = 10;
    private MainActivity activity;

    private VoiceToolbarItem sharedToolbarItem;
    private Toolbar nativeButton;

    private SpeechRecognizer mSpeechRecognizer;
    private Intent mSpeechRecognizerIntent;


    public VoiceToolbarItemRenderer(Context context) : base(context)
    {
        isRecording = false;
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
    {
        base.OnElementChanged(e);
        activity = this.Context as MainActivity;
        nativeButton = new global::Android.Widget.Toolbar(Context);

        if (e.OldElement == null)
        {
            // perform initial setup
            //SetNativeControl();
            nativeButton.Clickable = true;
            nativeButton.Focusable = true;

            nativeButton.SetOnClickListener(this);

        }

        if (e.OldElement != null)
        {
            activity.ActivityResult -= HandleActivityResult;
        }

        if (e.NewElement != null)
        {
            activity.ActivityResult += HandleActivityResult;
            sharedToolbarItem = e.NewElement.ToolbarItems as VoiceToolbarItem;
        }
    }

    public void OnClick(Android.Views.View view)
    {

        try
        {
            string rec = Android.Content.PM.PackageManager.FeatureMicrophone;
            if (rec != "android.hardware.microphone")
            {
                // no microphone, no recording. Disable the button and output an alert
                var alert = new AlertDialog.Builder(Context);
                alert.SetTitle("You don't seem to have a microphone to record with");
                alert.SetPositiveButton("OK", (sender, e) => {

                    return;
                });

                alert.Show();
            }
            else
            {

                // create the intent and start the activity

                var voiceIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
                voiceIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);


               // if there is more then 1.5s of silence, consider the speech over
                voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1500);
                voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1500);
                voiceIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 15000);
                voiceIntent.PutExtra(RecognizerIntent.ExtraMaxResults, 1);

                // you can specify other languages recognised here, for example
                // voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.German);
                // if you wish it to recognise the default Locale language and German
                // if you do use another locale, regional dialects may not be recognised very well

                voiceIntent.PutExtra(RecognizerIntent.ExtraLanguage, Java.Util.Locale.Default);
                activity.StartActivityForResult(voiceIntent, VOICE);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private void HandleActivityResult(object sender, ActivityResultEventArgs e)
    {
        if (e.RequestCode == VOICE)
        {
            if (e.ResultCode == Result.Ok)
            {
                var matches = e.Data.GetStringArrayListExtra(RecognizerIntent.ExtraResults);
                if (matches.Count != 0)
                {
                    string textInput = matches[0];

                    // limit the output to 500 characters
                    if (textInput.Length > 500)
                        textInput = textInput.Substring(0, 500);
                    sharedToolbarItem.OnTextChanged?.Invoke(textInput);
                    //textBox.Text = textInput;
                }
                else
                    sharedToolbarItem.OnTextChanged?.Invoke("No speech was recognised");
            }
        }

    }

}

}

If someone has an Idea of making toolbarItem's custom renderer or any other suggestions please let me know.

ocgprogramers
  • 35
  • 1
  • 8
  • you can follow this of implementing badge icon [here is the link](https://stackoverflow.com/questions/6011786/add-new-item-count-to-icon-on-button-android/50854335#50854335) – Ronak Shetiya Jun 27 '18 at 06:25

1 Answers1

3

By toolbar I suppose you mean the navigation bar (or the bar where you get the Page Title , right? )

If that is the case , then you have two options:

  1. Wait for the next release of Xamarin.Forms they are working on being able to add stuff to the toolbar. (for example you can have your own back button)

  2. You can make your own toolbar , just make sure to not show the Navigation bar on the NavigationPage, and make your own toolbar (e.g. a horizontal stacklayout (or flexlayout) where you place the title and the buttons you need . and has a background color .

I have tried to do custom renderer for the toolbar and it seems that it is not an easy job.

Ahmad ElMadi
  • 2,507
  • 21
  • 36