Add prototypes of Subjects for Ime Traces
Create new subjects with basic functions for ImeClient,
InputMethodService and InputMethodManagerService traces and entries.
In the future, add more functions to make assertions on these
subjects.
Test: verify that Winscope still builds successfully, and atest
FlickerLibTest
Bug: 239021832
Change-Id: I7016280c35149dda0ec04c7c277e74ba673e8a0c
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IImeClientSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IImeClientSubject.kt
new file mode 100644
index 0000000..07b6acf
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IImeClientSubject.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+/** Base interface for ImeClient trace and state assertions */
+interface IImeClientSubject<ImeClientSubjectType> {
+ /** Asserts that the current ImeClient state doesn't contain anything */
+ fun isEmpty(): ImeClientSubjectType
+
+ /** Asserts that the current ImeClient state contains something */
+ fun isNotEmpty(): ImeClientSubjectType
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodManagerServiceSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodManagerServiceSubject.kt
new file mode 100644
index 0000000..e24d221
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodManagerServiceSubject.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+/** Base interface for InputMethodManagerService trace and state assertions */
+interface IInputMethodManagerServiceSubject<InputMethodManagerServiceSubjectType> {
+ /** Asserts that the current InputMethodManagerService state doesn't contain anything */
+ fun isEmpty(): InputMethodManagerServiceSubjectType
+
+ /** Asserts that the current InputMethodManagerService state contains something */
+ fun isNotEmpty(): InputMethodManagerServiceSubjectType
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodServiceSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodServiceSubject.kt
new file mode 100644
index 0000000..2e35403
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/IInputMethodServiceSubject.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+/** Base interface for InputMethodService trace and state assertions */
+interface IInputMethodServiceSubject<InputMethodServiceSubjectType> {
+ /** Asserts that the current InputMethodService state doesn't contain anything */
+ fun isEmpty(): InputMethodServiceSubjectType
+
+ /** Asserts that the current InputMethodService state contains something */
+ fun isNotEmpty(): InputMethodServiceSubjectType
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientEntrySubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientEntrySubject.kt
new file mode 100644
index 0000000..3c08bb3
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientEntrySubject.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.ImeClientEntry
+import com.android.server.common.inputmethod.ImeClientTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.assertions.FlickerSubject
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [ImeClientEntry] objects, used to make assertions over behaviors that occur on
+ * a single ImeClientEntry state.
+ *
+ * To make assertions over a specific state from a trace it is recommended to create a subject using
+ * [ImeClientTraceSubject.assertThat](myTrace) and select the specific state using:
+ * [ImeClientTraceSubject.first] [ImeClientTraceSubject.last] [ImeClientTraceSubject.entry]
+ *
+ * Alternatively, it is also possible to use [ImeClientEntrySubject.assertThat](myState) or
+ * Truth.assertAbout([ImeClientEntrySubject.getFactory]), however they will provide less debug
+ * information because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = ImeClientTraceParser.parseFromTrace(myTraceFile) val subject =
+ * ImeClientTraceSubject.assertThat(trace).first() ... .invoke { myCustomAssertion(this) }
+ */
+class ImeClientEntrySubject
+private constructor(
+ fm: FailureMetadata,
+ val entry: ImeClientEntry,
+ val trace: ImeClientTrace?,
+ override val parent: FlickerSubject?
+) : FlickerSubject(fm, entry), IImeClientSubject<ImeClientEntrySubject> {
+ override val timestamp: Long
+ get() = entry.timestamp
+ override val selfFacts = listOf(Fact.fact("ImeClientEntry", entry))
+
+ /** Executes a custom [assertion] on the current subject */
+ operator fun invoke(assertion: Assertion<ImeClientEntry>): ImeClientEntrySubject = apply {
+ assertion(this.entry)
+ }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): ImeClientEntrySubject = apply {
+ check("ImeClientEntry").that(entry).isNull()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): ImeClientEntrySubject = apply {
+ check("ImeClientEntry").that(entry).isNotNull()
+ }
+
+ override fun toString(): String {
+ return "ImeClientEntrySubject($entry)"
+ }
+
+ companion object {
+ /** Boilerplate Subject.Factory for ImeClientTraceSubject */
+ private fun getFactory(
+ trace: ImeClientTrace?,
+ parent: FlickerSubject?
+ ): Factory<Subject, ImeClientEntry> = Factory { fm, subject ->
+ ImeClientEntrySubject(fm, subject, trace, parent)
+ }
+
+ /**
+ * Creates a [ImeClientEntrySubject] to represent a ImeClient state[entry], which can be
+ * used to make assertions.
+ *
+ * @param entry ImeClient trace entry
+ * @param parent Trace that contains this entry (optional)
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ entry: ImeClientEntry,
+ trace: ImeClientTrace? = null,
+ parent: FlickerSubject? = null
+ ): ImeClientEntrySubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(trace, parent))
+ .that(entry) as ImeClientEntrySubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ @JvmOverloads
+ fun entries(
+ trace: ImeClientTrace? = null,
+ parent: FlickerSubject? = null
+ ): Factory<Subject, ImeClientEntry> = getFactory(trace, parent)
+ }
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientTraceSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientTraceSubject.kt
new file mode 100644
index 0000000..c282c1f
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/ImeClientTraceSubject.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.ImeClientEntry
+import com.android.server.common.inputmethod.ImeClientTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.android.server.wm.flicker.traces.FlickerTraceSubject
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [ImeClientTrace] objects, used to make assertions over behaviors that occur
+ * throughout a whole trace
+ *
+ * To make assertions over a trace it is recommended to create a subject using
+ * [ImeClientTraceSubject.assertThat](myTrace). Alternatively, it is also possible to use
+ * Truth.assertAbout(ImeClientTraceSubject.FACTORY), however it will provide less debug information
+ * because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = ImeClientTraceParser.parseFromTrace(myTraceFile) val subject =
+ * ImeClientTraceSubject.assertThat(trace) Example2: val trace =
+ * ImeClientTraceParser.parseFromTrace(myTraceFile) val subject =
+ * ImeClientTraceSubject.assertThat(trace) { check("Custom check") { myCustomAssertion(this) } }
+ */
+class ImeClientTraceSubject
+private constructor(
+ fm: FailureMetadata,
+ val trace: ImeClientTrace,
+ override val parent: ImeClientTraceSubject?,
+ val facts: Collection<Fact>
+) :
+ FlickerTraceSubject<ImeClientEntrySubject>(fm, trace),
+ IImeClientSubject<ImeClientTraceSubject> {
+
+ override val selfFacts by lazy {
+ val allFacts = super.selfFacts.toMutableList()
+ allFacts.addAll(facts)
+ allFacts
+ }
+
+ override val subjects by lazy {
+ trace.entries.map { ImeClientEntrySubject.assertThat(it, trace, this) }
+ }
+
+ /** {@inheritDoc} */
+ override fun then(): ImeClientTraceSubject = apply { super.then() }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): ImeClientTraceSubject = apply {
+ check("ImeClientTrace").that(trace).isEmpty()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): ImeClientTraceSubject = apply {
+ check("ImeClientTrace").that(trace).isNotEmpty()
+ }
+
+ /** Executes a custom [assertion] on the current subject */
+ @JvmOverloads
+ operator fun invoke(
+ name: String,
+ isOptional: Boolean = false,
+ assertion: Assertion<ImeClientEntrySubject>
+ ): ImeClientTraceSubject = apply { addAssertion(name, isOptional, assertion) }
+
+ /** Run the assertions for all trace entries within the specified time range */
+ fun forRange(startTime: Long, endTime: Long) {
+ val subjectsInRange = subjects.filter { it.entry.timestamp in startTime..endTime }
+ assertionsChecker.test(subjectsInRange)
+ }
+
+ /**
+ * User-defined entry point for the trace entry with [timestamp]
+ *
+ * @param timestamp of the entry
+ */
+ fun entry(timestamp: Long): ImeClientEntrySubject =
+ subjects.first { it.entry.timestamp == timestamp }
+
+ /**
+ * @return List of [ImeClientEntrySubject]s matching [predicate] in the order they appear in the
+ * trace
+ */
+ fun imeClientEntriesThat(predicate: (ImeClientEntry) -> Boolean): List<ImeClientEntrySubject> =
+ subjects.filter { predicate(it.entry) }
+
+ companion object {
+ /** Boilerplate Subject.Factory for ImeClientTraceSubject */
+ private fun getFactory(
+ parent: ImeClientTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, ImeClientTrace> = Factory { fm, subject ->
+ ImeClientTraceSubject(fm, subject, parent, facts)
+ }
+
+ /**
+ * Creates a [ImeClientTraceSubject] to represent a ImeClient trace, which can be used to
+ * make assertions.
+ *
+ * @param trace ImeClient trace
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ trace: ImeClientTrace,
+ parent: ImeClientTraceSubject? = null,
+ facts: Collection<Fact> = emptyList()
+ ): ImeClientTraceSubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(parent, facts))
+ .that(trace) as ImeClientTraceSubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ fun entries(
+ parent: ImeClientTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, ImeClientTrace> {
+ return getFactory(parent, facts)
+ }
+ }
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceEntrySubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceEntrySubject.kt
new file mode 100644
index 0000000..ce100db
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceEntrySubject.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.InputMethodManagerServiceEntry
+import com.android.server.common.inputmethod.InputMethodManagerServiceTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.assertions.FlickerSubject
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [InputMethodManagerServiceEntry] objects, used to make assertions over
+ * behaviors that occur on a single InputMethodManagerServiceEntry state.
+ *
+ * To make assertions over a specific state from a trace it is recommended to create a subject using
+ * [InputMethodManagerServiceTraceSubject.assertThat](myTrace) and select the specific state using:
+ * [InputMethodManagerServiceTraceSubject.first] [InputMethodManagerServiceTraceSubject.last]
+ * [InputMethodManagerServiceTraceSubject.entry]
+ *
+ * Alternatively, it is also possible to use
+ * [InputMethodManagerServiceEntrySubject.assertThat](myState) or
+ * Truth.assertAbout([InputMethodManagerServiceEntrySubject.getFactory]), however they will provide
+ * less debug information because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = InputMethodManagerServiceTraceParser.parseFromTrace(myTraceFile) val subject
+ * = InputMethodManagerServiceTraceSubject.assertThat(trace).first() ... .invoke {
+ * myCustomAssertion(this) }
+ */
+class InputMethodManagerServiceEntrySubject
+private constructor(
+ fm: FailureMetadata,
+ val entry: InputMethodManagerServiceEntry,
+ val trace: InputMethodManagerServiceTrace?,
+ override val parent: FlickerSubject?
+) :
+ FlickerSubject(fm, entry),
+ IInputMethodManagerServiceSubject<InputMethodManagerServiceEntrySubject> {
+ override val timestamp: Long
+ get() = entry.timestamp
+ override val selfFacts = listOf(Fact.fact("InputMethodManagerServiceEntry", entry))
+
+ /** Executes a custom [assertion] on the current subject */
+ operator fun invoke(
+ assertion: Assertion<InputMethodManagerServiceEntry>
+ ): InputMethodManagerServiceEntrySubject = apply { assertion(this.entry) }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): InputMethodManagerServiceEntrySubject = apply {
+ check("InputMethodManagerServiceEntry").that(entry).isNull()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): InputMethodManagerServiceEntrySubject = apply {
+ check("InputMethodManagerServiceEntry").that(entry).isNotNull()
+ }
+
+ override fun toString(): String {
+ return "InputMethodManagerServiceEntrySubject($entry)"
+ }
+
+ companion object {
+ /** Boilerplate Subject.Factory for InputMethodManagerServiceTraceSubject */
+ private fun getFactory(
+ trace: InputMethodManagerServiceTrace?,
+ parent: FlickerSubject?
+ ): Factory<Subject, InputMethodManagerServiceEntry> = Factory { fm, subject ->
+ InputMethodManagerServiceEntrySubject(fm, subject, trace, parent)
+ }
+
+ /**
+ * Creates a [InputMethodManagerServiceEntrySubject] to represent a
+ * InputMethodManagerService state[entry], which can be used to make assertions.
+ *
+ * @param entry InputMethodManagerService trace entry
+ * @param parent Trace that contains this entry (optional)
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ entry: InputMethodManagerServiceEntry,
+ trace: InputMethodManagerServiceTrace? = null,
+ parent: FlickerSubject? = null
+ ): InputMethodManagerServiceEntrySubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(trace, parent))
+ .that(entry) as InputMethodManagerServiceEntrySubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ @JvmOverloads
+ fun entries(
+ trace: InputMethodManagerServiceTrace? = null,
+ parent: FlickerSubject? = null
+ ): Factory<Subject, InputMethodManagerServiceEntry> = getFactory(trace, parent)
+ }
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceTraceSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceTraceSubject.kt
new file mode 100644
index 0000000..cea2172
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodManagerServiceTraceSubject.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.InputMethodManagerServiceEntry
+import com.android.server.common.inputmethod.InputMethodManagerServiceTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.android.server.wm.flicker.traces.FlickerTraceSubject
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [InputMethodManagerServiceTrace] objects, used to make assertions over
+ * behaviors that occur throughout a whole trace
+ *
+ * To make assertions over a trace it is recommended to create a subject using
+ * [InputMethodManagerServiceTraceSubject.assertThat](myTrace). Alternatively, it is also possible
+ * to use Truth.assertAbout(InputMethodManagerServiceTraceSubject.FACTORY), however it will provide
+ * less debug information because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = InputMethodManagerServiceTraceParser.parseFromTrace(myTraceFile) val subject
+ * = InputMethodManagerServiceTraceSubject.assertThat(trace) Example2: val trace =
+ * InputMethodManagerServiceTraceParser.parseFromTrace(myTraceFile) val subject =
+ * InputMethodManagerServiceTraceSubject.assertThat(trace) { check("Custom check") {
+ * myCustomAssertion(this) } }
+ */
+class InputMethodManagerServiceTraceSubject
+private constructor(
+ fm: FailureMetadata,
+ val trace: InputMethodManagerServiceTrace,
+ override val parent: InputMethodManagerServiceTraceSubject?,
+ val facts: Collection<Fact>
+) :
+ FlickerTraceSubject<InputMethodManagerServiceEntrySubject>(fm, trace),
+ IInputMethodManagerServiceSubject<InputMethodManagerServiceTraceSubject> {
+
+ override val selfFacts by lazy {
+ val allFacts = super.selfFacts.toMutableList()
+ allFacts.addAll(facts)
+ allFacts
+ }
+
+ override val subjects by lazy {
+ trace.entries.map { InputMethodManagerServiceEntrySubject.assertThat(it, trace, this) }
+ }
+
+ /** {@inheritDoc} */
+ override fun then(): InputMethodManagerServiceTraceSubject = apply { super.then() }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): InputMethodManagerServiceTraceSubject = apply {
+ check("InputMethodManagerServiceTrace").that(trace).isEmpty()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): InputMethodManagerServiceTraceSubject = apply {
+ check("InputMethodManagerServiceTrace").that(trace).isNotEmpty()
+ }
+
+ /** Executes a custom [assertion] on the current subject */
+ @JvmOverloads
+ operator fun invoke(
+ name: String,
+ isOptional: Boolean = false,
+ assertion: Assertion<InputMethodManagerServiceEntrySubject>
+ ): InputMethodManagerServiceTraceSubject = apply { addAssertion(name, isOptional, assertion) }
+
+ /** Run the assertions for all trace entries within the specified time range */
+ fun forRange(startTime: Long, endTime: Long) {
+ val subjectsInRange = subjects.filter { it.entry.timestamp in startTime..endTime }
+ assertionsChecker.test(subjectsInRange)
+ }
+
+ /**
+ * User-defined entry point for the trace entry with [timestamp]
+ *
+ * @param timestamp of the entry
+ */
+ fun entry(timestamp: Long): InputMethodManagerServiceEntrySubject =
+ subjects.first { it.entry.timestamp == timestamp }
+
+ /**
+ * @return List of [InputMethodManagerServiceEntrySubject]s matching [predicate] in the order
+ * they appear in the trace
+ */
+ fun imeClientEntriesThat(
+ predicate: (InputMethodManagerServiceEntry) -> Boolean
+ ): List<InputMethodManagerServiceEntrySubject> = subjects.filter { predicate(it.entry) }
+
+ companion object {
+ /** Boilerplate Subject.Factory for InputMethodManagerServiceTraceSubject */
+ private fun getFactory(
+ parent: InputMethodManagerServiceTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, InputMethodManagerServiceTrace> = Factory { fm, subject ->
+ InputMethodManagerServiceTraceSubject(fm, subject, parent, facts)
+ }
+
+ /**
+ * Creates a [InputMethodManagerServiceTraceSubject] to represent a
+ * InputMethodManagerService trace, which can be used to make assertions.
+ *
+ * @param trace InputMethodManagerService trace
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ trace: InputMethodManagerServiceTrace,
+ parent: InputMethodManagerServiceTraceSubject? = null,
+ facts: Collection<Fact> = emptyList()
+ ): InputMethodManagerServiceTraceSubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(parent, facts))
+ .that(trace) as InputMethodManagerServiceTraceSubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ fun entries(
+ parent: InputMethodManagerServiceTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, InputMethodManagerServiceTrace> {
+ return getFactory(parent, facts)
+ }
+ }
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceEntrySubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceEntrySubject.kt
new file mode 100644
index 0000000..acd01c6
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceEntrySubject.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.InputMethodServiceEntry
+import com.android.server.common.inputmethod.InputMethodServiceTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.assertions.FlickerSubject
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [InputMethodServiceEntry] objects, used to make assertions over behaviors that
+ * occur on a single InputMethodServiceEntry state.
+ *
+ * To make assertions over a specific state from a trace it is recommended to create a subject using
+ * [InputMethodServiceTraceSubject.assertThat](myTrace) and select the specific state using:
+ * [InputMethodServiceTraceSubject.first] [InputMethodServiceTraceSubject.last]
+ * [InputMethodServiceTraceSubject.entry]
+ *
+ * Alternatively, it is also possible to use [InputMethodServiceEntrySubject.assertThat](myState) or
+ * Truth.assertAbout([InputMethodServiceEntrySubject.getFactory]), however they will provide less
+ * debug information because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = InputMethodServiceTraceParser.parseFromTrace(myTraceFile) val subject =
+ * InputMethodServiceTraceSubject.assertThat(trace).first() ... .invoke { myCustomAssertion(this) }
+ */
+class InputMethodServiceEntrySubject
+private constructor(
+ fm: FailureMetadata,
+ val entry: InputMethodServiceEntry,
+ val trace: InputMethodServiceTrace?,
+ override val parent: FlickerSubject?
+) : FlickerSubject(fm, entry), IInputMethodServiceSubject<InputMethodServiceEntrySubject> {
+ override val timestamp: Long
+ get() = entry.timestamp
+ override val selfFacts = listOf(Fact.fact("InputMethodServiceEntry", entry))
+
+ /** Executes a custom [assertion] on the current subject */
+ operator fun invoke(
+ assertion: Assertion<InputMethodServiceEntry>
+ ): InputMethodServiceEntrySubject = apply { assertion(this.entry) }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): InputMethodServiceEntrySubject = apply {
+ check("InputMethodServiceEntry").that(entry).isNull()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): InputMethodServiceEntrySubject = apply {
+ check("InputMethodServiceEntry").that(entry).isNotNull()
+ }
+
+ override fun toString(): String {
+ return "InputMethodServiceEntrySubject($entry)"
+ }
+
+ companion object {
+ /** Boilerplate Subject.Factory for InputMethodServiceTraceSubject */
+ private fun getFactory(
+ trace: InputMethodServiceTrace?,
+ parent: FlickerSubject?
+ ): Factory<Subject, InputMethodServiceEntry> = Factory { fm, subject ->
+ InputMethodServiceEntrySubject(fm, subject, trace, parent)
+ }
+
+ /**
+ * Creates a [InputMethodServiceEntrySubject] to represent a InputMethodService
+ * state[entry], which can be used to make assertions.
+ *
+ * @param entry InputMethodService trace entry
+ * @param parent Trace that contains this entry (optional)
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ entry: InputMethodServiceEntry,
+ trace: InputMethodServiceTrace? = null,
+ parent: FlickerSubject? = null
+ ): InputMethodServiceEntrySubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(trace, parent))
+ .that(entry) as InputMethodServiceEntrySubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ @JvmOverloads
+ fun entries(
+ trace: InputMethodServiceTrace? = null,
+ parent: FlickerSubject? = null
+ ): Factory<Subject, InputMethodServiceEntry> = getFactory(trace, parent)
+ }
+}
diff --git a/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceTraceSubject.kt b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceTraceSubject.kt
new file mode 100644
index 0000000..b01e4c9
--- /dev/null
+++ b/libraries/flicker/src/com/android/server/wm/flicker/traces/inputmethod/InputMethodServiceTraceSubject.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.traces.inputmethod
+
+import com.android.server.common.inputmethod.InputMethodServiceEntry
+import com.android.server.common.inputmethod.InputMethodServiceTrace
+import com.android.server.wm.flicker.assertions.Assertion
+import com.android.server.wm.flicker.traces.FlickerFailureStrategy
+import com.android.server.wm.flicker.traces.FlickerTraceSubject
+import com.google.common.truth.Fact
+import com.google.common.truth.FailureMetadata
+import com.google.common.truth.FailureStrategy
+import com.google.common.truth.StandardSubjectBuilder
+import com.google.common.truth.Subject
+import com.google.common.truth.Subject.Factory
+
+/**
+ * Truth subject for [InputMethodServiceTrace] objects, used to make assertions over behaviors that
+ * occur throughout a whole trace
+ *
+ * To make assertions over a trace it is recommended to create a subject using
+ * [InputMethodServiceTraceSubject.assertThat](myTrace). Alternatively, it is also possible to use
+ * Truth.assertAbout(InputMethodServiceTraceSubject.FACTORY), however it will provide less debug
+ * information because it uses Truth's default [FailureStrategy].
+ *
+ * Example: val trace = InputMethodServiceTraceParser.parseFromTrace(myTraceFile) val subject =
+ * InputMethodServiceTraceSubject.assertThat(trace) Example2: val trace =
+ * InputMethodServiceTraceParser.parseFromTrace(myTraceFile) val subject =
+ * InputMethodServiceTraceSubject.assertThat(trace) { check("Custom check") {
+ * myCustomAssertion(this) } }
+ */
+class InputMethodServiceTraceSubject
+private constructor(
+ fm: FailureMetadata,
+ val trace: InputMethodServiceTrace,
+ override val parent: InputMethodServiceTraceSubject?,
+ val facts: Collection<Fact>
+) :
+ FlickerTraceSubject<InputMethodServiceEntrySubject>(fm, trace),
+ IInputMethodServiceSubject<InputMethodServiceTraceSubject> {
+
+ override val selfFacts by lazy {
+ val allFacts = super.selfFacts.toMutableList()
+ allFacts.addAll(facts)
+ allFacts
+ }
+
+ override val subjects by lazy {
+ trace.entries.map { InputMethodServiceEntrySubject.assertThat(it, trace, this) }
+ }
+
+ /** {@inheritDoc} */
+ override fun then(): InputMethodServiceTraceSubject = apply { super.then() }
+
+ /** {@inheritDoc} */
+ override fun isEmpty(): InputMethodServiceTraceSubject = apply {
+ check("InputMethodServiceTrace").that(trace).isEmpty()
+ }
+
+ /** {@inheritDoc} */
+ override fun isNotEmpty(): InputMethodServiceTraceSubject = apply {
+ check("InputMethodServiceTrace").that(trace).isNotEmpty()
+ }
+
+ /** Executes a custom [assertion] on the current subject */
+ @JvmOverloads
+ operator fun invoke(
+ name: String,
+ isOptional: Boolean = false,
+ assertion: Assertion<InputMethodServiceEntrySubject>
+ ): InputMethodServiceTraceSubject = apply { addAssertion(name, isOptional, assertion) }
+
+ /** Run the assertions for all trace entries within the specified time range */
+ fun forRange(startTime: Long, endTime: Long) {
+ val subjectsInRange = subjects.filter { it.entry.timestamp in startTime..endTime }
+ assertionsChecker.test(subjectsInRange)
+ }
+
+ /**
+ * User-defined entry point for the trace entry with [timestamp]
+ *
+ * @param timestamp of the entry
+ */
+ fun entry(timestamp: Long): InputMethodServiceEntrySubject =
+ subjects.first { it.entry.timestamp == timestamp }
+
+ /**
+ * @return List of [InputMethodServiceEntrySubject]s matching [predicate] in the order they
+ * appear in the trace
+ */
+ fun imeClientEntriesThat(
+ predicate: (InputMethodServiceEntry) -> Boolean
+ ): List<InputMethodServiceEntrySubject> = subjects.filter { predicate(it.entry) }
+
+ companion object {
+ /** Boilerplate Subject.Factory for InputMethodServiceTraceSubject */
+ private fun getFactory(
+ parent: InputMethodServiceTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, InputMethodServiceTrace> = Factory { fm, subject ->
+ InputMethodServiceTraceSubject(fm, subject, parent, facts)
+ }
+
+ /**
+ * Creates a [InputMethodServiceTraceSubject] to represent a InputMethodService trace, which
+ * can be used to make assertions.
+ *
+ * @param trace InputMethodService trace
+ */
+ @JvmStatic
+ @JvmOverloads
+ fun assertThat(
+ trace: InputMethodServiceTrace,
+ parent: InputMethodServiceTraceSubject? = null,
+ facts: Collection<Fact> = emptyList()
+ ): InputMethodServiceTraceSubject {
+ val strategy = FlickerFailureStrategy()
+ val subject =
+ StandardSubjectBuilder.forCustomFailureStrategy(strategy)
+ .about(getFactory(parent, facts))
+ .that(trace) as InputMethodServiceTraceSubject
+ strategy.init(subject)
+ return subject
+ }
+
+ /** Static method for getting the subject factory (for use with assertAbout()) */
+ @JvmStatic
+ fun entries(
+ parent: InputMethodServiceTraceSubject?,
+ facts: Collection<Fact> = emptyList()
+ ): Factory<Subject, InputMethodServiceTrace> {
+ return getFactory(parent, facts)
+ }
+ }
+}