File indexing completed on 2024-12-22 05:25:49

0001 /*
0002  * Copyright 2018 Kai Uwe Broulik <kde@broulik.de>
0003  *
0004  * Licensed under the Apache License, Version 2.0 (the "License");
0005  * you may not use this file except in compliance with the License.
0006  * You may obtain a copy of the License at
0007  *
0008  *    http://www.apache.org/licenses/LICENSE-2.0
0009  *
0010  * Unless required by applicable law or agreed to in writing, software
0011  * distributed under the License is distributed on an "AS IS" BASIS,
0012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013  * See the License for the specific language governing permissions and
0014  * limitations under the License.
0015  *
0016  */
0017 
0018 #include "speechintent.h"
0019 
0020 #ifdef Q_OS_ANDROID
0021 #include <QtAndroid>
0022 #include <QAndroidActivityResultReceiver>
0023 #endif
0024 
0025 
0026 #ifdef Q_OS_ANDROID
0027 
0028 static int s_receiverRequestCode = 42;
0029 
0030 class SpeechIntentResultReceiver : public QAndroidActivityResultReceiver
0031 {
0032 public:
0033     SpeechIntentResultReceiver(SpeechIntent *q);
0034     void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
0035 
0036 private:
0037     SpeechIntent *q;
0038 
0039 };
0040 
0041 SpeechIntentResultReceiver::SpeechIntentResultReceiver(SpeechIntent *q)
0042     : q(q)
0043 {
0044 
0045 }
0046 
0047 void SpeechIntentResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
0048 {
0049     if (!q) {
0050         return;
0051     }
0052 
0053     if (receiverRequestCode != s_receiverRequestCode) {
0054         return;
0055     }
0056 
0057     static int resultOk = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK");
0058     static int resultCanceled = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_CANCELED");
0059 
0060     if (resultCode == resultCanceled) {
0061         emit q->recognitionCanceled();
0062         return;
0063     }
0064 
0065     if (resultCode != resultOk) {
0066         emit q->recognitionFailed();
0067         return;
0068     }
0069 
0070     if (!data.isValid()) { // can this happen?
0071         emit q->recognitionFailed();
0072         return;
0073     }
0074 
0075     QAndroidJniObject extraResultsKey = QAndroidJniObject::getStaticObjectField<jstring>("android/speech/RecognizerIntent", "EXTRA_RESULTS");
0076     Q_ASSERT(extraResultsKey.isValid());
0077 
0078     QAndroidJniObject results = data.callObjectMethod("getStringArrayListExtra",
0079                                                       "(Ljava/lang/String;)Ljava/util/ArrayList;",
0080                                                       extraResultsKey.object());
0081 
0082     if (data.callMethod<jboolean>("isEmpty")) {
0083         emit q->nothingRecognized();
0084         return;
0085     }
0086 
0087     QAndroidJniObject firstResult = results.callObjectMethod("get", "(I)Ljava/lang/Object;", static_cast<jint>(0));
0088 
0089     const QString text = firstResult.toString();
0090     if (text.isEmpty()) {
0091         emit q->nothingRecognized();
0092         return;
0093     }
0094 
0095     emit q->speechRecognized(text);
0096 }
0097 #endif // Q_OS_ANDROID
0098 
0099 SpeechIntent::SpeechIntent(QObject *parent) : QObject(parent)
0100 {
0101 
0102 }
0103 
0104 SpeechIntent::~SpeechIntent() = default;
0105 
0106 QString SpeechIntent::title() const
0107 {
0108     return m_title;
0109 }
0110 
0111 void SpeechIntent::setTitle(const QString &title)
0112 {
0113     if (m_title != title) {
0114         m_title = title;
0115         emit titleChanged(title);
0116     }
0117 }
0118 
0119 bool SpeechIntent::isSupported() const
0120 {
0121 #ifdef Q_OS_ANDROID
0122     // TODO check for whether the intent class exists or permission or whatever?
0123     return true;
0124 #else
0125     return false;
0126 #endif
0127 }
0128 
0129 void SpeechIntent::start()
0130 {
0131 #ifdef Q_OS_ANDROID
0132     if (!m_receiver) {
0133         m_receiver.reset(new SpeechIntentResultReceiver(this));
0134     }
0135 
0136     QAndroidJniObject actionRecognizeSpeech = QAndroidJniObject::getStaticObjectField<jstring>("android/speech/RecognizerIntent", "ACTION_RECOGNIZE_SPEECH");
0137 
0138     QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", actionRecognizeSpeech.object());
0139 
0140     QAndroidJniObject extraLanguageModel = QAndroidJniObject::getStaticObjectField<jstring>("android/speech/RecognizerIntent", "EXTRA_LANGUAGE_MODEL");
0141     QAndroidJniObject langaugeModelFreeForm = QAndroidJniObject::getStaticObjectField<jstring>("android/speech/RecognizerIntent", "LANGUAGE_MODEL_FREE_FORM");
0142 
0143     intent.callObjectMethod("putExtra",
0144                             "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
0145                             extraLanguageModel.object(),
0146                             langaugeModelFreeForm.object());
0147 
0148     if (!m_title.isEmpty()) {
0149         QAndroidJniObject extraPrompt = QAndroidJniObject::getStaticObjectField<jstring>("android/speech/RecognizerIntent", "EXTRA_PROMPT");
0150 
0151         intent.callObjectMethod("putExtra",
0152                                 "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
0153                                 extraPrompt.object(),
0154                                 QAndroidJniObject::fromString(m_title).object());
0155     }
0156 
0157     QtAndroid::startActivity(intent, s_receiverRequestCode, m_receiver.data());
0158 #endif // Q_OS_ANDROID
0159 }