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 }