1 /*
2 * Copyright (C) 2020 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 package com.android.cts.mockspellchecker
17
18 import android.content.ComponentName
19 import android.service.textservice.SpellCheckerService
20 import android.util.Log
21 import android.view.textservice.SentenceSuggestionsInfo
22 import android.view.textservice.SuggestionsInfo
23 import android.view.textservice.TextInfo
24 import com.android.cts.mockspellchecker.MockSpellCheckerProto.MockSpellCheckerConfiguration
25 import com.android.cts.mockspellchecker.MockSpellCheckerProto.SuggestionRule
26 import java.io.FileDescriptor
27 import java.io.PrintWriter
28
withLognull29 internal inline fun <T> withLog(msg: String, block: () -> T): T {
30 Log.i(TAG, msg)
31 return block()
32 }
33
34 const val EXTRAS_KEY_PREFIX = "prefix"
35
36 /** Mock Spell checker for end-to-end tests. */
37 class MockSpellChecker : SpellCheckerService() {
38
<lambda>null39 override fun onCreate() = withLog("MockSpellChecker.onCreate") {
40 super.onCreate()
41 }
42
<lambda>null43 override fun onDestroy() = withLog("MockSpellChecker.onDestroy") {
44 super.onDestroy()
45 }
46
dumpnull47 override fun dump(fd: FileDescriptor?, writer: PrintWriter?, args: Array<out String>?) {
48 writer?.println("MockSpellChecker")
49 }
50
<lambda>null51 override fun createSession(): Session = withLog("MockSpellChecker.createSession") {
52 return MockSpellCheckerSession()
53 }
54
55 private inner class MockSpellCheckerSession : SpellCheckerService.Session() {
56
<lambda>null57 override fun onCreate() = withLog("MockSpellCheckerSession.onCreate") {
58 }
59
onGetSentenceSuggestionsMultiplenull60 override fun onGetSentenceSuggestionsMultiple(
61 textInfos: Array<out TextInfo>?,
62 suggestionsLimit: Int
63 ): Array<SentenceSuggestionsInfo> = withLog(
64 "MockSpellCheckerSession.onGetSuggestionsMultiple " +
65 "${textInfos?.map { it.text }?.joinToString(":")}") {
66 if (textInfos == null) return emptyArray()
67 val configuration = MockSpellCheckerConfiguration.parseFrom(
68 SharedPrefsProvider.get(contentResolver, KEY_CONFIGURATION))
69 if (configuration.matchSentence)
70 return textInfos.map { matchSentenceSuggestion(configuration, it) }.toTypedArray()
71 return super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit)
72 }
73
matchSentenceSuggestionnull74 private fun matchSentenceSuggestion(
75 configuration: MockSpellCheckerConfiguration,
76 textInfo: TextInfo
77 ): SentenceSuggestionsInfo {
78 return configuration.suggestionRulesList.find { it.match == textInfo.text }
79 ?.let {
80 SentenceSuggestionsInfo(
81 arrayOf(suggestionsInfo(it, textInfo.cookie, textInfo.sequence)),
82 intArrayOf(if (it.hasStartOffset()) it.startOffset else 0),
83 intArrayOf(if (it.hasLength()) it.length else textInfo.text.length))
84 }
85 ?: SentenceSuggestionsInfo(emptyArray(), intArrayOf(), intArrayOf())
86 }
87
onGetSuggestionsnull88 override fun onGetSuggestions(
89 textInfo: TextInfo?,
90 suggestionsLimit: Int
91 ): SuggestionsInfo = withLog(
92 "MockSpellCheckerSession.onGetSuggestions: ${textInfo?.text}") {
93 if (textInfo == null) return emptySuggestionsInfo()
94 val configuration = MockSpellCheckerConfiguration.parseFrom(
95 SharedPrefsProvider.get(contentResolver, KEY_CONFIGURATION))
96 return configuration.suggestionRulesList
97 .find { it.match == textInfo.text }
98 ?.let { suggestionsInfo(it) }
99 ?: emptySuggestionsInfo()
100 }
101
suggestionsInfonull102 private fun suggestionsInfo(rule: SuggestionRule): SuggestionsInfo {
103 return suggestionsInfo(rule, 0, 0)
104 }
105
suggestionsInfonull106 private fun suggestionsInfo(
107 rule: SuggestionRule,
108 cookie: Int,
109 sequence: Int
110 ): SuggestionsInfo {
111 // Only use attrs in supportedAttributes
112 val attrs = rule.attributes and supportedAttributes
113 // Add prefix if it is passed in getBundle()
114 val prefix = bundle.getString(EXTRAS_KEY_PREFIX)
115 val suggestions = if (prefix != null) {
116 rule.suggestionsList.map { prefix + it }.toTypedArray()
117 } else {
118 rule.suggestionsList.toTypedArray()
119 }
120 return SuggestionsInfo(attrs, suggestions, cookie, sequence)
121 }
122
emptySuggestionsInfonull123 private fun emptySuggestionsInfo() = SuggestionsInfo(0, arrayOf())
124 }
125
126 companion object {
127 @JvmStatic
128 fun getId(): String =
129 ComponentName(PACKAGE, MockSpellChecker::class.java.name).flattenToShortString()
130 }
131 }