{"id":37024208,"url":"https://github.com/spokestack/spokestack-tray-android","last_synced_at":"2026-01-14T02:55:23.669Z","repository":{"id":42187179,"uuid":"300085692","full_name":"spokestack/spokestack-tray-android","owner":"spokestack","description":"A UI component that makes it easy to add voice interaction to your app.","archived":true,"fork":false,"pushed_at":"2022-04-11T14:32:31.000Z","size":4563,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-06T09:47:24.326Z","etag":null,"topics":["android","android-ui","asr","nlu","spokestack","tts","voice","voice-assistant"],"latest_commit_sha":null,"homepage":"https://spokestack.io","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spokestack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-30T23:12:15.000Z","updated_at":"2024-03-06T14:25:16.000Z","dependencies_parsed_at":"2022-08-12T08:50:54.006Z","dependency_job_id":null,"html_url":"https://github.com/spokestack/spokestack-tray-android","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/spokestack/spokestack-tray-android","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spokestack%2Fspokestack-tray-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spokestack%2Fspokestack-tray-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spokestack%2Fspokestack-tray-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spokestack%2Fspokestack-tray-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spokestack","download_url":"https://codeload.github.com/spokestack/spokestack-tray-android/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spokestack%2Fspokestack-tray-android/sbom","scorecard":{"id":841969,"data":{"date":"2025-08-11","repo":{"name":"github.com/spokestack/spokestack-tray-android","commit":"bd785bb590478b8584ddaba2d8105db2799866f5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"project is archived","details":["Warn: Repository is archived."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/8 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci-build.yml:1","Warn: no topLevel permission defined: .github/workflows/publish-docs.yml:1","Warn: no topLevel permission defined: .github/workflows/release-drafter.yml:1","Warn: no topLevel permission defined: .github/workflows/update-deps.yml:1","Warn: no topLevel permission defined: .github/workflows/update-gradle-wrapper.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci-build.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/ci-build.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci-build.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/ci-build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci-build.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/ci-build.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-docs.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/publish-docs.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish-docs.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/publish-docs.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish-docs.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/publish-docs.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-drafter.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/release-drafter.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/update-deps.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/update-deps.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/update-deps.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/update-deps.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/update-deps.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/update-deps.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/update-gradle-wrapper.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/update-gradle-wrapper.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/update-gradle-wrapper.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/spokestack/spokestack-tray-android/update-gradle-wrapper.yml/main?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   6 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: gradle/wrapper/gradle-wrapper.jar:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T20:40:26.747Z","repository_id":42187179,"created_at":"2025-08-23T20:40:26.747Z","updated_at":"2025-08-23T20:40:26.747Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408798,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-ui","asr","nlu","spokestack","tts","voice","voice-assistant"],"created_at":"2026-01-14T02:55:22.992Z","updated_at":"2026-01-14T02:55:23.659Z","avatar_url":"https://github.com/spokestack.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://www.spokestack.io/blog/integrating-spokestack-in-android\" title=\"Integrating Spokestack in Android\"\u003e![Spokestack Tray Android](./example/spokestack-tray-android.png)\u003c/a\u003e\n\n[ ![Maven Central](https://img.shields.io/maven-central/v/io.spokestack/tray)](https://search.maven.org/search?q=tray)\n[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](https://opensource.org/licenses/Apache-2.0)\n\nA `Fragment` for adding voice control via Spokestack to any Android app. You can find a simple demo app that shows the tray in action in the `example` directory.\n\n## Table of Contents\n* [Description](#description)\n* [Usage](#usage)\n* [Configuration](#configuration)\n* [Customization](#customization)\n* [License](#license)\n\n\n## Description\n\nWhen you add the Spokestack Tray Fragment to your layout, you'll get a microphone button shaped like a tab on the side of the screen (_which_ side it's on is up to you; more on that later). Tapping or dragging the tab reveals the rest of the tray, which is arranged like a messaging stream in a chat app. Opening the tray activates the microphone, and anything the user says will be sent through an automatic speech recognition (ASR) service and displayed as text. That text is then sent to a natural language understanding (NLU) model for classification. Results of the classification are sent to the application component you've established to listen to events from the tray, which can produce a response that the tray will both display and read to the user via Spokestack's text-to-speech (TTS) synthesis service. The microphone will be reenabled if the app's response directs it to; otherwise, the tray will close and disable ASR.\n\nAnd just like that, you've added voice to your app!\n\n\u003cimg align=\"center\" src=\"./example/tray_demo.gif\" alt=\"Example app\"\u003e\n\nOh, and after that initial interaction, the tray can be opened with a wakeword instead of a tap. The wakeword is \"Spokestack\" by default, but [that can be customized](https://www.spokestack.io/docs/Concepts/wakeword-models).\n\nIf some of that didn't make sense, fear not! Read on, and we'll cover all the details below.\n\n## Usage\n\n---\n\n**Note**: Spokestack Tray used to be hosted on JCenter, but since the announcement of its [discontinuation](https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter), we've moved distribution to Maven Central. Please ensure that your root-level `build.gradle` file includes `mavenCentral()` in its `repositories` block in order to access versions \u003e= 0.4.1.\n\nEnsure you're using version 0.4.2 or above to properly resolve the dependency on the core Spokestack library after JCenter becomes inaccessible.\n\n---\n\nBy default, Spokestack Tray handles ASR, NLU, and TTS for voice interactions with users—that's converting their voice to text, processing that text to produce an action, and synthesizing the app's response to be read back to the user. For more information on these features, see [the Spokestack docs](https://www.spokestack.io/docs/Concepts).\n\nTo use NLU and TTS, you'll need a [free Spokestack account](https://www.spokestack.io/create). From your account page, you'll be able to create and download NLU models; and the client ID and secret key are needed at runtime for TTS requests.\n\nFirst, though, add the dependency to your app's `build.gradle` (check the JCenter badge above for the latest version):\n\n```groovy\nimplementation 'io.spokestack:tray:0.4.1'\n```\n\nAs mentioned above, Spokestack Tray is implemented as a `Fragment` that renders on top of your existing `Activity` and handles voice interaction, so you'll want to add it to your activity's layout:\n\n```xml\n    \u003c!-- nested in the main layout, after other views/sublayouts --\u003e\n\n    \u003cinclude\n        android:id=\"@+id/tray_fragment\"\n        layout=\"@layout/spokestack_tray_fragment\"\n        /\u003e\n```\n\n**Note**: Depending on your app layout, you may also have to add `android:clipChildren=\"false\"` to the fragment's parent layout(s) to avoid the microphone tab disappearing as the tray opens.\n\nThen make your activity itself extend `TrayActivity` (a subclass of `AppCompatActivity`), implement the methods it requires, and the library will take care of the rest.\n\nIf you'd prefer to do the setup yourself, here's a sample that doesn't use `TrayActivity`:\n\n```kotlin\nimport io.spokestack.tray.*\n\nclass MyActivity : AppCompatActivity(), SpokestackTrayListener {\n\n    lateinit var tray: SpokestackTray\n\n    // ...\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n\n        val config = TrayConfig.Builder()\n            // credentials from your Spokestack account\n            .credentials(\"spokestack-client-id\", \"spokestack-secret-key\")\n            .wakewordModelURL(\"https://path-to-wakeword-models\")\n            .nluURL(\"https://path-to-nlu-files\")\n            // note the implementation of `SpokestackTrayListener` in the class declaration\n            .withListener(this)\n            // optional builder customization; see the documentation for more details...\n            .build()\n        supportFragmentManager.fragmentFactory = SpokestackTrayFactory(config)\n\n        // note that the factory is instantiated and set on the manager BEFORE calling\n        // `super.onCreate()`\n        super.onCreate(savedInstanceState)\n    }\n\n    override fun onStart() {\n        // set the value of the lateinit `tray` var\n        tray = SpokestackTray.getInstance(config)\n        super.onStart()\n    }\n```\n\nWhen you download Spokestack wakeword or NLU models, you'll have several URLs to different files. `wakewordModelURL` and `nluURL` above only require the path to the relevant directory, not full file URLs. So for the demo \"Spokestack\" wakeword, set `wakewordModelURL` to \"https://d3dmqd7cy685il.cloudfront.net/model/wake/spokestack/\".\n\nThe Tray is designed for seamless use across activities — for example, to allow a user to continue giving a voice command while the app switches activities — so its state is stored outside the fragment itself and survives fragment destruction. If your app needs to release resources held by the Tray and its underlying `Spokestack` instance, call the tray's `stop()` method. If you then need to re-enable voice control before the current Tray fragment instance is destroyed, you must call `start()`.\n\nIf you want to keep tray state intact after process death, you can store it in its parent activity's `onSaveInstanceState` and `onRestoreInstanceState` methods using the Tray's `getState()` and `loadState()` methods; see their documentation for more details.\n\n### Responses\n\nChances are that if you're allowing the user to talk to your app, you want the app to talk back. Tray is integrated with Spokestack's TTS service, so synthesizing audio is just as easy as transcribing it.\n\nWhen you extend `TrayActivity`, one of the methods you'll have to implement is `getTrayListener()`, which creates and returns a `SpokestackTrayListener`. This interface assists your app in reacting to events received and produced by the Tray. Because each use case is unique, all its methods are optional; the one we're interested in here is `onClassification`. This method is called after a user's speech has been transcribed by ASR and classified by NLU. It supplies your app with the NLU result and asks you to return a response:\n\n```kotlin\noverride fun onClassification(result: NLUResult): VoicePrompt {\n  return if (result.intent == \"your-special-intent\") {\n    VoicePrompt(\"I hear you loud and clear\")\n  } else {\n  VoicePrompt(\n    \"Sorry; I didn't catch that\",\n    expectFollowup = true)\n  }\n}\n```\n\nThe optional second parameter in the `VoicePrompt` constructor lets the Tray know if you're expecting a response — if you are, it will resume active listening after your prompt is played so the user doesn't have to use the wakeword or a button for each interaction.\n\n## Configuration\n\nThe above sample will get you up and running with minimal fuss, but it's far from all that Spokestack Tray offers. When you're building a `TrayConfig` instance, you can choose to configure and provide the underlying `Spokestack` builder itself. This will let you do things like change ASR providers, set up custom listeners for events from individual systems, and add custom speech processing components if you need to. You can read about the Spokestack builder [here](https://www.spokestack.io/docs/Android/turnkey-configuration).\n\nThere are also a range of options that are applicable to the Tray itself, accessible via helper methods on the `TrayConfig.Builder` instance. Describing each one here would make this readme...ponderous, though, so check out the [documentation](https://spokestack.github.io/spokestack-tray-android/-spokestack-tray/) for more details. Documentation on `TrayConfig.Builder` is [here](https://spokestack.github.io/spokestack-tray-android/-spokestack-tray/io.spokestack.tray/-tray-config/-builder**.\n\n\n## Customization\n\nMost aspects of the tray's UI can be customized. Often this is accomplished in XML by overriding values set in the library.\n\nOne exception to this is the tray's orientation: Its microphone button defaults to appearing as a right-facing tab on the lefthand side of the screen, with the tray consequently sliding in from the left. It also supports a righthand orientation but requires two changes in order to do so:\n\n1. Call `.orientation(TrayConfig.Orientation.RIGHT)` on the `TrayConfig`builder before building the configuration.\n1. Set appropriate layout parameters when including the tray Fragment in your layout. When the fragment is right-aligned to its parent, layout constraints in the tray's layout itself take care of the rest. Here's the example we gave above modified for a righthand orientation:\n```xml\n\u003cinclude\n  layout=\"@layout/spokestack_tray_fragment\"\n  android:layout_width=\"wrap_content\"\n  android:layout_height=\"wrap_content\"\n  app:layout_constraintBottom_toBottomOf=\"parent\"\n  app:layout_constraintEnd_toEndOf=\"parent\" /\u003e\n```\n\nWe only _need_ the last constraint here; the rest of the attributes are identical to the source layout. Since we're using `include`, though, overriding one attribute means overriding all of them; see the note at the end of the paragraph [here](https://developer.android.com/training/improving-layouts/reusing-layouts#Include).\n\nValue-based UI customizations are listed below. The filenames here point to the original definitions in the library's `res/values` folder, but replacements can be defined elsewhere in your project. The example app illustrates this by overriding the text color for system messages in `res/values/custom_colors.xml`.\n\n### `colors.xml`\n\n* `spsk_colorTrayBg`: The background color used for the tray's message stream.\n* `spsk_colorIcon`: The foreground color used for icons that need to contrast with `spsk_colorBrand`. Defaults to white.\n* `spsk_colorDragHandle`: The color used for the tray's resizing drag handle.\n* `spsk_colorBrand`: The primary color of UI elements like the microphone button and icons without a background.\n* `spsk_colorListenText`: The color used for text in the \"listening\" bubble.\n* `spsk_colorSystemText`: The color used for text in system message bubbles.\n* `spsk_colorUserText`: The color used for text in user message bubbles.\n* `spsk_colorSystemBg`: The background color used for system message bubbles.\n* `spsk_colorUserBg`: The background color used for user message bubbles.\n* `spsk_colorGradientOne`: The start color used for the listening gradient animation. Defaults to `spsk_colorBrand`.\n* `spsk_colorGradientEnd`: The end color used for the listening gradient animation.\n* `spsk_colorTransparent`: Transparent color used as the background tint for the \"back\" arrow on the tray.\n\n### `dimens.xml`\n\n* `spsk_micTabWidth`: Width for the microphone tab button. Defaults to `60dp`.\n* `spsk_micTabHeight`: Height for the microphone tab button. Defaults to `80dp` and should be kept in a 4:3 ratio with `spsk_micTabWidth`.\n* `spsk_listenBubbleWidth`: Width for the listening bubble that appears during ASR. Defaults to `120dp`and should be kept in a 2:1 ratio with `spsk_listenBubbleHeight`.\n* `spsk_listenBubbleHeight`: Height for the listening bubble that appears during ASR. Defaults to `60dp`.\n* `spsk_messageStreamHeight`: Starting height for the message stream inside the tray. Defaults to `100dp`.\n* `spsk_messageStreamMinHeight`: Minimum height to which the tray can be resized by drag. Defaults to `80dp`.\n\n### `ints.xml`\n\n* `spsk_trayAnimateMs`: The amount of time, in milliseconds, the tray takes to open or close. Defaults to `500`.\n\n### `strings.xml`\n\n* `spsk_listening`: The text displayed in the tray during active listening (ASR). Defaults to `\"LISTENING\"`.\n\n### `styles.xml`\n\n* `spsk_messageFont`: The font family used to display ASR transcripts and system messages in the tray. Defaults to `sans-serif` (Roboto).\n\n\n## License\n\nCopyright 2020 Spokestack, Inc.\n\n  Licensed under the Apache License, Version 2.0 (the \"License\");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an \"AS IS\" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspokestack%2Fspokestack-tray-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspokestack%2Fspokestack-tray-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspokestack%2Fspokestack-tray-android/lists"}